shadertoy代码

const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;
const vec3 COLOR_BACKGROUND = vec3(0.835, 1, 1);
const float PI = 3.14159265359;

// PBR材质结构
struct Material {
    vec3 albedo;
    float metallic;
    float roughness;
};

float sdSphere(vec3 p, float r)
{
  float d = length(p) - r;
  return d;
}

float sdFloor(vec3 p) {
  float d = p.y + 1.;
  return d;
}

vec2 opU( vec2 d1, vec2 d2 )
{
  return (d1.x < d2.x) ? d1 : d2;
}

vec2 map(vec3 p) {
  vec2 res = vec2(1e10, 0.);
  vec2 flooring = vec2(sdFloor(p), 0.5);
  vec2 sphereLeft = vec2(sdSphere(p - vec3(-2.5, 0, -2), 1.), 1.5);
  vec2 sphereRight = vec2(sdSphere(p - vec3(2.5, 0, -2), 1.), 2.5);

  res = opU(res, flooring);
  res = opU(res, sphereLeft);
  res = opU(res, sphereRight);
  return res;
}

vec2 rayMarch(vec3 ro, vec3 rd) {
  float depth = MIN_DIST;
  vec2 res = vec2(0.0);
  float id = 0.;

  for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
    vec3 p = ro + depth * rd;
    res = map(p);
    depth += res.x;
    id = res.y;
    if (res.x < PRECISION || depth > MAX_DIST) break;
  }

  return vec2(depth, id);
}

vec3 calcNormal(in vec3 p) {
    vec2 e = vec2(1.0, -1.0) * 0.0005;
    return normalize(
      e.xyy * map(p + e.xyy).x +
      e.yyx * map(p + e.yyx).x +
      e.yxy * map(p + e.yxy).x +
      e.xxx * map(p + e.xxx).x);
}

// 3D噪声函数
float hash(vec3 p) {
    p = fract(p * 0.3183099 + 0.1);
    p *= 17.0;
    return fract(p.x * p.y * p.z * (p.x + p.y + p.z));
}

float noise(vec3 x) {
    vec3 p = floor(x);
    vec3 f = fract(x);
    f = f * f * (3.0 - 2.0 * f);
    
    return mix(
        mix(mix(hash(p + vec3(0,0,0)), hash(p + vec3(1,0,0)), f.x),
            mix(hash(p + vec3(0,1,0)), hash(p + vec3(1,1,0)), f.x), f.y),
        mix(mix(hash(p + vec3(0,0,1)), hash(p + vec3(1,0,1)), f.x),
            mix(hash(p + vec3(0,1,1)), hash(p + vec3(1,1,1)), f.x), f.y), f.z);
}

// 分形布朗运动(FBM)用于云
float fbm(vec3 p) {
    float value = 0.0;
    float amplitude = 0.5;
    float frequency = 1.0;
    
    for(int i = 0; i < 5; i++) {
        value += amplitude * noise(p * frequency);
        frequency *= 2.0;
        amplitude *= 0.5;
    }
    return value;
}

// 云密度函数
float cloudDensity(vec3 p) {
    // 云层高度范围
    float heightFactor = smoothstep(8.0, 12.0, p.y) * smoothstep(20.0, 16.0, p.y);
    if(heightFactor < 0.01) return 0.0;
    
    // 使用时间让云移动
    vec3 offset = vec3(iTime * 0.3, 0.0, iTime * 0.2);
    float density = fbm(p * 0.2 + offset);
    
    // 添加更多细节
    density += fbm(p * 0.5 + offset * 1.5) * 0.5;
    
    // 调整阈值创建云的形状
    density = smoothstep(0.4, 0.8, density);
    
    return density * heightFactor;
}

// 体素云光线步进
vec4 renderClouds(vec3 ro, vec3 rd, float maxDist) {
    vec3 cloudColor = vec3(0.0);
    float cloudAlpha = 0.0;
    
    float t = 5.0; // 起始距离
    float stepSize = 0.3;
    
    // 天光方向(来自上方)
    vec3 skyLightDir = normalize(vec3(0.3, 1.0, 0.2));
    vec3 skyLightColor = vec3(0.5, 0.7, 1.0) * 2.0; // 蔚蓝色天光
    
    for(int i = 0; i < 60; i++) {
        if(t > maxDist || cloudAlpha > 0.95) break;
        
        vec3 p = ro + rd * t;
        float density = cloudDensity(p);
        
        if(density > 0.01) {
            // 计算云的光照
            // 向光源方向采样以获得透射光
            float lightDensity = 0.0;
            vec3 lightSamplePos = p + skyLightDir * 0.5;
            for(int j = 0; j < 4; j++) {
                lightDensity += cloudDensity(lightSamplePos);
                lightSamplePos += skyLightDir * 0.5;
            }
            
            // 光的衰减
            float lightTransmittance = exp(-lightDensity * 0.5);
            
            // 云的颜色受天光影响
            vec3 ambient = vec3(0.6, 0.7, 0.8) * 0.5;
            vec3 lit = skyLightColor * lightTransmittance + ambient;
            
            // 累积颜色和透明度
            float alpha = density * stepSize * 0.4;
            cloudColor += lit * alpha * (1.0 - cloudAlpha);
            cloudAlpha += alpha * (1.0 - cloudAlpha);
        }
        
        t += stepSize;
    }
    
    return vec4(cloudColor, cloudAlpha);
}

// 根据ID获取材质
Material getMaterial(float id, vec3 p) {
    Material mat;
    
    if (id < 1.0) { // 地板
        mat.albedo = vec3(1. + 0.7*mod(floor(p.x) + floor(p.z), 2.0));
        mat.metallic = 0.0;
        mat.roughness = 0.9;
    } else if (id < 2.0) { // 左球 - 高金属度低粗糙度
        mat.albedo = vec3(0.95, 0.93, 0.88);
        mat.metallic = 0.95;
        mat.roughness = 0.1;
    } else { // 右球 - 高金属度高粗糙度
        mat.albedo = vec3(0.92, 0.70, 0.55);
        mat.metallic = 0.95;
        mat.roughness = 0.8;
    }
    
    return mat;
}

// Fresnel-Schlick近似
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

// GGX/Trowbridge-Reitz法线分布函数
float DistributionGGX(vec3 N, vec3 H, float roughness) {
    float a = roughness * roughness;
    float a2 = a * a;
    float NdotH = max(dot(N, H), 0.0);
    float NdotH2 = NdotH * NdotH;

    float nom = a2;
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;

    return nom / denom;
}

// Smith's Schlick-GGX几何遮蔽函数
float GeometrySchlickGGX(float NdotV, float roughness) {
    float r = (roughness + 1.0);
    float k = (r * r) / 8.0;

    float nom = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}

float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx2 = GeometrySchlickGGX(NdotV, roughness);
    float ggx1 = GeometrySchlickGGX(NdotL, roughness);

    return ggx1 * ggx2;
}

vec3 calculatePBR(vec3 p, vec3 N, vec3 V, Material mat, vec3 lightPos, vec3 lightColor) {
    vec3 L = normalize(lightPos - p);
    vec3 H = normalize(V + L);
    
    float distance = length(lightPos - p);
    float attenuation = 1.0 / (distance * distance);
    vec3 radiance = lightColor * attenuation;
    
    vec3 F0 = vec3(0.04);
    F0 = mix(F0, mat.albedo, mat.metallic);
    
    float NDF = DistributionGGX(N, H, mat.roughness);
    float G = GeometrySmith(N, V, L, mat.roughness);
    vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
    
    vec3 numerator = NDF * G * F;
    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
    vec3 specular = numerator / denominator;
    
    vec3 kS = F;
    vec3 kD = vec3(1.0) - kS;
    kD *= 1.0 - mat.metallic;
    
    float NdotL = max(dot(N, L), 0.0);
    
    return (kD * mat.albedo / PI + specular) * radiance * NdotL;
}

// 计算天光贡献
vec3 calculateSkyLight(vec3 p, vec3 N, vec3 V, Material mat) {
    // 半球采样天光
    vec3 skyLightDir = vec3(0.0, 1.0, 0.0); // 从上方来的主要天光
    vec3 skyLightColor = vec3(0.5, 0.7, 1.0) * 1.5; // 蔚蓝色
    
    // 计算遮蔽(简化版AO)
    float ao = 1.0;
    vec3 aoDir = N;
    for(int i = 0; i < 5; i++) {
        float dist = 0.1 + float(i) * 0.2;
        vec3 testPos = p + aoDir * dist;
        float scene = map(testPos).x;
        ao *= 1.0 - max(0.0, (dist - scene) / dist);
    }
    ao = clamp(ao, 0.0, 1.0);
    
    vec3 H = normalize(V + N);
    
    vec3 F0 = vec3(0.04);
    F0 = mix(F0, mat.albedo, mat.metallic);
    
    float NDF = DistributionGGX(N, H, mat.roughness);
    float G = GeometrySmith(N, V, N, mat.roughness);
    vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
    
    vec3 numerator = NDF * G * F;
    float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, N), 0.0) + 0.0001;
    vec3 specular = numerator / denominator;
    
    vec3 kS = F;
    vec3 kD = vec3(1.0) - kS;
    kD *= 1.0 - mat.metallic;
    
    float NdotL = max(dot(N, skyLightDir), 0.0);
    
    return (kD * mat.albedo / PI + specular * 0.5) * skyLightColor * NdotL * ao;
}

vec3 render(vec3 ro, vec3 rd) {
    vec3 col = COLOR_BACKGROUND;

    vec2 res = rayMarch(ro, rd);
    float d = res.x;
    
    // 渲染云
    vec4 clouds = renderClouds(ro, rd, min(d, MAX_DIST));
    
    if (d > MAX_DIST) {
        // 只有天空和云
        col = mix(col, clouds.rgb, clouds.a);
        return col;
    }

    float id = res.y;

    vec3 p = ro + rd * d;
    vec3 normal = calcNormal(p);
    vec3 viewDir = normalize(ro - p);
    
    Material mat = getMaterial(id, p);
    
    // 主光源
    vec3 lightPosition1 = vec3(2, 2, 7);
    vec3 lightColor1 = vec3(300.0, 300.0, 300.0);
    
    // 补光
    vec3 lightPosition2 = vec3(-3, 1, 5);
    vec3 lightColor2 = vec3(100.0, 100.0, 100.0);
    
    // 计算PBR光照
    vec3 Lo = vec3(0.0);
    Lo += calculatePBR(p, normal, viewDir, mat, lightPosition1, lightColor1);
    Lo += calculatePBR(p, normal, viewDir, mat, lightPosition2, lightColor2);
    
    // 添加天光照明
    Lo += calculateSkyLight(p, normal, viewDir, mat);
    
    // 环境光(蔚蓝色调)
    vec3 ambient = vec3(0.5, 0.6, 0.7) * 0.05 * mat.albedo;
    col = ambient + Lo;
    
    // 混合云层
    col = mix(col, clouds.rgb, clouds.a);
    
    // 色调映射(Reinhard)
    col = col / (col + vec3(1.0));
    
    // Gamma校正
    col = pow(col, vec3(1.0/2.2));
    
    return col;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;

  vec3 ro = vec3(0, 0, 3);
  vec3 rd = normalize(vec3(uv, -1));

  vec3 col = render(ro, rd);

  fragColor = vec4(col, 1.0);
}