如何正确计算Gertner波法线?Godot代码异常求助
Gerstner波法线计算错误排查与修正
问题根源分析
你的代码存在以下几个关键错误,导致法线计算异常:
- 波数计算错误:Gerstner波的波数
k应为2π/波长,你写成了2/波长,缺失了π,直接导致波的频率和相位完全偏离预期。 - 相位计算不一致且符号错误:
get_wave与get_normal的相位公式不统一,且波的传播相位应该是k*(方向点积原始坐标 - 速度*时间)(减号表示波沿方向移动),你使用了加号,相位方向完全错误。 - 法线公式推导错误:当前
get_normal的计算式不符合Gerstner波的法线数学推导,且未对法线向量进行归一化。 - 顶点位移处理错误:直接赋值
VERTEX.y = res.y会丢失原始顶点的基础高度,叠加多个波时问题更明显。 - 法线后处理错误:
NORMAL.y = 1.0 - NORMAL.y属于无意义操作,破坏了法线的方向正确性。
修正后的代码
vec3 get_wave(vec4 wave, vec2 direction, vec3 vtx) { // x = SPEED, y = WAVELENGTH, z = AMPLITUDE, w = STEEPNESS float lambda = wave.y; float amplitude = wave.z; float steepness = wave.w; float speed = wave.x; float k = 2.0 * PI / lambda; // 正确的波数计算 float theta = k * (dot(direction, vtx.xz) - speed * TIME); // 正确的传播相位 vec3 displacement = vec3(0.0); displacement.x = steepness * amplitude * direction.x * cos(theta); displacement.z = steepness * amplitude * direction.y * cos(theta); displacement.y = amplitude * sin(theta); return displacement; } vec3 get_normal(vec4 wave, vec2 direction, vec3 vtx) { float lambda = wave.y; float amplitude = wave.z; float steepness = wave.w; float speed = wave.x; float k = 2.0 * PI / lambda; float theta = k * (dot(direction, vtx.xz) - speed * TIME); float kA = k * amplitude; vec3 normal; // 遵循GPU Gems中Gerstner波的法线公式 normal.x = -steepness * kA * direction.x * cos(theta); normal.z = -steepness * kA * direction.y * cos(theta); normal.y = 1.0 - steepness * kA * sin(theta); return normalize(normal); // 必须归一化得到正确的单位法线 } void vertex() { vec3 original_vtx = VERTEX; vec3 wave_displacement = get_wave(wave_1, wave_1_dir, original_vtx); // 正确叠加波位移,保留原始顶点高度 VERTEX.x += wave_displacement.x; VERTEX.y += wave_displacement.y; VERTEX.z += wave_displacement.z; // 使用原始顶点计算法线,避免位移后的坐标干扰 NORMAL = get_normal(wave_1, wave_1_dir, original_vtx); }
额外注意事项
- 确保
wave_1_dir是归一化的单位向量,否则会导致波的传播方向和幅度计算错误。 - 如果需要叠加多个Gerstner波,需将每个波的位移相加,法线分量相加后再统一归一化。
内容的提问来源于stack exchange,提问作者E F
相关产品推荐
相关产品推荐

