访问量: 635

function getCloudColor(
viewVector, // 视线方向
skyColor, // 背景天空色
basePos, // 射线起点
samples, // 采样次数
umbral, // 阈值,用于剔除低噪声
brightFactor, // 高光强度
dither, // 抖动参数
CLOUD_PARAMS // 各种云层平面、中心、厚度等常量
):
// 1. 如果视线朝下,直接返回天空色
if viewVector.y ≤ 0:
return skyColor
// 2. 计算射线与上下云层平面的交点 t0、t1
t0 = (CLOUD_BOTTOM - basePos.y) / viewVector.y
t1 = (CLOUD_TOP - basePos.y) / viewVector.y
// 3. 生成采样起点 p 和步长 stepV
p = basePos + viewVector * t0
pEnd = basePos + viewVector * t1
stepV = (pEnd - p) / samples
p += stepV * dither // 加入少量抖动,减少条带
// 4. 沿射线采样,累积“云厚度” cv 和“首次击中深度” den
cv = 0 // 累计的云体积分量
den = 0 // 首次进入云层的相对位置(0~1)
firstHit = true
totalRange = (CLOUD_CENTER - CLOUD_BOTTOM) + (CLOUD_TOP - CLOUD_CENTER)
for i in 0 .. samples-1:
// 4.1 采样噪声(height field)
noiseHi = sampleNoiseHeight(p.xz, timeOffsetHigh)
noiseLo = sampleNoiseHeight(p.zx, timeOffsetLow) // 可选多层混合
noise = mixAndSmooth(noiseHi, noiseLo)
// 4.2 根据阈值计算云层上下边界
v = (noise - umbral) / (1 - umbral)
inf = CLOUD_CENTER - v * (CLOUD_CENTER - CLOUD_BOTTOM)
sup = CLOUD_CENTER + v * (CLOUD_TOP - CLOUD_CENTER)
// 4.3 判断当前采样点 p.y 是否在云层内部
if inf < p.y < sup:
cv += min(stepLength, sup - inf)
if firstHit:
den = (sup - p.y) / totalRange
firstHit = false
else if withinSoftEdge(p.y, inf, sup, CLOUD_EDGE_WIDTH):
// 边缘过渡:软添加一点积累
cv += softBlendAmount(p.y, inf, sup)
if firstHit:
den = (sup - p.y) / totalRange
firstHit = false
p += stepV
// 5. 归一化累积值和深度
opacity = clamp(cv / (2 * CLOUD_EDGE_WIDTH / viewVector.y), 0, 1)
density = clamp(den, 0.0001, 1)
// 6. 按 density 分层选色:低—中—高
if density < 0.33:
baseColor = COL_SH // 云底色
else if density < 0.66:
baseColor = COL_MD // 中层色
else:
baseColor = COL_HI // 云顶色
// 7. 视向高光:只有高密度部分才额外提亮
if density > 0.66:
highlight = dot(computeNormal(density), -viewVector)
baseColor = mix(baseColor, COL_HI, highlight * brightFactor)
// 8. 自阴影:越厚越暗
baseColor *= mix(1.0, 0.85, density^2 * 0.5)
// 9. 边缘描边:根据深度场梯度增强轮廓
edgeFactor = computeEdgeFactor(opacity)
baseColor = mix(baseColor, OUTLINE_COLOR, edgeFactor * 0.3)
// 10. 根据天空亮度在夜间适当暗化
nightFactor = computeNightFactor(skyColor)
baseColor *= nightFactor
// 11. 最终混合:云层覆盖背景
alpha = opacity * clamp((viewVector.y - 0.05) * 5.0, 0, 1)
return mix(skyColor, baseColor, alpha)
JavaScript
发表回复