在片段着色器中绘制球体法线贴图
Drawing a sphere normal map in the fragment shader
我正在尝试使用 GL_POINTS 在片段着色器中绘制一个带有法线贴图的简单球体。目前,我只是简单地在屏幕上绘制一个点,然后对其应用片段着色器"spherify"。
但是,我无法正确为球体着色(或者至少我认为我是)。看起来我正在正确计算 z 但是当我将 'normal' 颜色应用到 gl_FragColor
时它看起来不太正确(或者这是人们对法线贴图的期望?)。我假设 gl_PointCoord 和片段坐标之间存在一些不一致,但我不太明白。
顶点着色器
precision mediump float;
attribute vec3 position;
void main() {
gl_PointSize = 500.0;
gl_Position = vec4(position.xyz, 1.0);
}
片段着色器
precision mediump float;
void main() {
float x = gl_PointCoord.x * 2.0 - 1.0;
float y = gl_PointCoord.y * 2.0 - 1.0;
float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));
vec3 position = vec3(x, y, z);
float mag = dot(position.xy, position.xy);
if(mag > 1.0) discard;
vec3 normal = normalize(position);
gl_FragColor = vec4(normal, 1.0);
}
实际输出:
预期输出:
首先,面向相机的法线[0,0,-1]
应该是rgb值:[0.5,0.5,1.0]
。您必须重新缩放事物以将这些负值移动到 0
和 1
之间。
其次,球体的法线不会呈线性变化,而是呈正弦波变化。所以你需要一些三角函数。从垂直法线 [0,0,-1]
开始然后将法线旋转一个角度对我来说很有意义,因为 角度 是线性变化的。
作为解决这个问题的结果,我想到了这个:
http://glslsandbox.com/e#50268.3
从这里使用一些旋转函数:https://github.com/yuichiroharai/glsl-y-rotate
颜色通道被限制在 [0, 1] 范围内。 (0, 0, 0) 是黑色,(1, 1, 1) 是全白。
由于法向量被归一化,其分量在[-1, 1]范围内。
要获得预期的结果,您必须将法向量从 [-1, 1] 范围映射到 [0, 1]:
vec3 normal_col = normalize(position) * 0.5 + 0.5;
gl_FragColor = vec4(normal_col, 1.0);
如果使用 abs
值,则具有相同大小的正值和负值具有相同的颜色表示。颜色的强度随着数值的渐变而增加:
vec3 normal_col = abs(normalize(position));
gl_FragColor = vec4(normal_col, 1.0);
我正在尝试使用 GL_POINTS 在片段着色器中绘制一个带有法线贴图的简单球体。目前,我只是简单地在屏幕上绘制一个点,然后对其应用片段着色器"spherify"。
但是,我无法正确为球体着色(或者至少我认为我是)。看起来我正在正确计算 z 但是当我将 'normal' 颜色应用到 gl_FragColor
时它看起来不太正确(或者这是人们对法线贴图的期望?)。我假设 gl_PointCoord 和片段坐标之间存在一些不一致,但我不太明白。
顶点着色器
precision mediump float;
attribute vec3 position;
void main() {
gl_PointSize = 500.0;
gl_Position = vec4(position.xyz, 1.0);
}
片段着色器
precision mediump float;
void main() {
float x = gl_PointCoord.x * 2.0 - 1.0;
float y = gl_PointCoord.y * 2.0 - 1.0;
float z = sqrt(1.0 - (pow(x, 2.0) + pow(y, 2.0)));
vec3 position = vec3(x, y, z);
float mag = dot(position.xy, position.xy);
if(mag > 1.0) discard;
vec3 normal = normalize(position);
gl_FragColor = vec4(normal, 1.0);
}
实际输出:
预期输出:
首先,面向相机的法线[0,0,-1]
应该是rgb值:[0.5,0.5,1.0]
。您必须重新缩放事物以将这些负值移动到 0
和 1
之间。
其次,球体的法线不会呈线性变化,而是呈正弦波变化。所以你需要一些三角函数。从垂直法线 [0,0,-1]
开始然后将法线旋转一个角度对我来说很有意义,因为 角度 是线性变化的。
作为解决这个问题的结果,我想到了这个:
http://glslsandbox.com/e#50268.3
从这里使用一些旋转函数:https://github.com/yuichiroharai/glsl-y-rotate
颜色通道被限制在 [0, 1] 范围内。 (0, 0, 0) 是黑色,(1, 1, 1) 是全白。
由于法向量被归一化,其分量在[-1, 1]范围内。 要获得预期的结果,您必须将法向量从 [-1, 1] 范围映射到 [0, 1]:
vec3 normal_col = normalize(position) * 0.5 + 0.5;
gl_FragColor = vec4(normal_col, 1.0);
如果使用 abs
值,则具有相同大小的正值和负值具有相同的颜色表示。颜色的强度随着数值的渐变而增加:
vec3 normal_col = abs(normalize(position));
gl_FragColor = vec4(normal_col, 1.0);