GLSL-计算曲面法线

GLSL-计算曲面法线,glsl,Glsl,我有一个简单的顶点着色器,用GLSL编写,我想知道是否有人可以帮助我计算曲面的法线。我正在“升级”平面,因此当前的灯光模型看起来。。。奇怪的这是我目前的代码: varying vec4 oColor; varying vec3 oEyeNormal; varying vec4 oEyePosition; uniform float Amplitude; // Amplitude of sine wave uniform float Phase; // Phase of

我有一个简单的顶点着色器,用GLSL编写,我想知道是否有人可以帮助我计算曲面的法线。我正在“升级”平面,因此当前的灯光模型看起来。。。奇怪的这是我目前的代码:

varying vec4 oColor;
varying vec3 oEyeNormal;
varying vec4 oEyePosition;

uniform float Amplitude;     // Amplitude of sine wave
uniform float Phase;         // Phase of sine wave
uniform float Frequency;     // Frequency of sine wave

varying float sinValue;

void main()
{
    vec4 thisPos = gl_Vertex;

    thisPos.z = sin( ( thisPos.x + Phase ) * Frequency) * Amplitude;

    // Transform normal and position to eye space (for fragment shader)
    oEyeNormal    = normalize( vec3( gl_NormalMatrix * gl_Normal ) );
    oEyePosition  = gl_ModelViewMatrix * thisPos;       

    // Transform vertex to clip space for fragment shader
    gl_Position   = gl_ModelViewProjectionMatrix * thisPos;

    sinValue = thisPos.z;
}

有人有什么想法吗?

好的,让我们从微分几何的角度来看这个问题。得到了一个参数为s和t的参数化曲面:

X(s,t) = ( s, t, A*sin((s+P)*F) )
我们首先计算这个曲面的切线,这是两个参数后的偏导数:

Xs(s,t) = ( 1, 0, A*F*cos((s+P)*F) )
Xt(s,t) = ( 0, 1, 0 )
然后我们只需要计算这些的叉积就可以得到法线:

N = Xs x Xt = ( -A*F*cos((s+P)*F), 0, 1 )
因此,法线可以完全通过分析计算,实际上不需要
gl\u normal
属性:

float angle = (thisPos.x + Phase) * Frequency;
thisPos.z = sin(angle) * Amplitude;
vec3 normal = normalize(vec3(-Amplitude*Frequency*cos(angle), 0.0, 1.0));

// Transform normal and position to eye space (for fragment shader)
oEyeNormal    = normalize( gl_NormalMatrix * normal );
normal
的规范化可能不是必需的(因为我们无论如何都要规范化转换后的法线),但就目前而言,我不确定在存在非均匀缩放的情况下,未规范化的法线是否会正常工作。当然,如果你想让法线指向负的z方向,你需要对它求反



嗯,穿越太空表面的方法是不必要的。我们也可以只考虑x-z平面内的正弦曲线,因为法线的y部分无论如何都是零,因为只有z依赖于x。所以我们只取曲线的切线,它的斜率是z的导数,是x-z向量
(1,A*F*cos((x+P)*F))
,这条曲线的法线就是
(-A*F*cos((x+P)*F),1)
(切换坐标并取反一),即(非标准化)法线的x和z。没有3D向量和偏导数,但结果是一样的。

此外,你应该调整你的性能:

oEyeNormal = normalize(vec3(gl_NormalMatrix * gl_Normal));
  • 因为gl_NormalMatrix是3x3矩阵,所以不需要将其转换为vec3
  • 无需在顶点着色器中规格化传入法线,因为在该着色器中不进行任何基于长度的计算。一些来源说,传入法线应该始终由应用程序进行规范化,以便在顶点着色器中根本不需要它。但由于这不是着色器开发人员的事,所以在计算基于顶点的照明(gouraud)时,我仍然会对它们进行规格化

  • 非常感谢你!一旦我启动到我的Win7分区,我将很快尝试这个方法。我在灯光和GLSL上玩得很开心!1. - 嗯,强制转换是不必要的,但这两种转换都不会带来任何性能损失,因为vec3到vec3的强制转换应该是不可操作的(GLSL编译器在这里复制不会那么愚蠢)。但你是对的,这完全没有必要。2这显然是错误的。他不规范化传入的法线(这确实不是一个好主意,因为应用程序当然应该提供规范化的法线)。但是他规范化了变换后的法线(与
    gl_NormalMatrix
    相乘后),这是解释任何缩放和剪切变换所必需的。当然,您知道,在曲面上插值非标准化法线会导致错误的每片段法线。所以最后这里没有太多的性能需要调整。最后它甚至没有回答实际问题,可能更适合作为评论。@ChristianRau我的回答更适合作为评论,因为它离题了,我同意。但你应该再仔细阅读我的回答。我说过,在顶点着色器中不需要
    对其进行规格化,除非在特殊计算中使用它,例如顶点着色器中的lightning!是的,不需要在顶点着色器中规格化输入法线。但是OP无论如何都不会这么做。他所做的是对变换后的法线进行归一化(在乘以
    gl_NormalMatrix
    之后),这对于考虑缩放等是必要的,因为需要将适当的归一化法线放入变量中,以便为片段获得适当的插值法线。请仔细阅读我的评论。