我有一个简单的顶点着色器,用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;
}
Run Code Online (Sandbox Code Playgroud)
有没有人有任何想法?
好吧,让我们从微分几何角度来看这个.你有一个带参数s和t的参数曲面:
X(s,t) = ( s, t, A*sin((s+P)*F) )
Run Code Online (Sandbox Code Playgroud)
所以我们首先计算这个曲面的切线,在我们的两个参数之后是偏导数:
Xs(s,t) = ( 1, 0, A*F*cos((s+P)*F) )
Xt(s,t) = ( 0, 1, 0 )
Run Code Online (Sandbox Code Playgroud)
然后我们只需要计算这些的叉积来得到正常值:
N = Xs x Xt = ( -A*F*cos((s+P)*F), 0, 1 )
Run Code Online (Sandbox Code Playgroud)
所以你的法线可以完全分析计算,你实际上并不需要这个gl_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 );
Run Code Online (Sandbox Code Playgroud)
归一化normal可能不是必要的(因为我们无论如何我们将变换后的法线标准化),但此刻我不确定非标准化法线在存在非均匀缩放时是否会表现正常.当然,如果你希望法线指向负z方向,你需要否定它.
那么,在太空中的表面上的路是不必要的.我们也可以用xz平面内的正弦曲线来思考,因为法线的y部分无论如何都是零,因为只有z取决于x.所以我们只取曲线的切线z=A*sin((x+P)*F),其斜率是z的导数,即xz向量(1, A*F*cos((x+P)*F)),那么它的法线就是(-A*F*cos((x+P)*F), 1)(切换坐标和否定一个),是(非标准化)法线的x和z.好吧,没有3D矢量和偏导数,但结果是一样的.