webGL 中的平面着色
flat shading in webGL
我正在尝试在 webgl 中实现平面着色,
我知道顶点着色器中的 varying
关键字将插值该值并将其传递给片段着色器。
我正在尝试禁用插值,我发现 flat
关键字可以做到这一点,但它似乎不能在 webgl 中使用?
flat varying vec4 fragColor;
总是出现错误:Illegal use of reserved word 'flat'
我认为 WebGL 中使用的 GLSL 版本不支持 'flat'。如果你想要平面着色,有几个选项:
1) 在每个顶点复制多边形的法线。最简单的解决方法,但是我觉得重复数据有点不尽如人意。
2) 在顶点着色器中,在视图坐标中变换顶点,在片段着色器中,使用计算导数的 dFdx() 和 dFdy() 函数计算法线。这些功能都是由扩展GL_OES_standard_derivatives支持的(使用前需要检查GPU是否支持),大多数GPU,包括智能手机中的GPU,都支持该扩展。
我的顶点着色器如下:
struct VSUniformState {
mat4 modelviewprojection_matrix;
mat4 modelview_matrix;
};
uniform VSUniformState GLUP_VS;
attribute vec4 vertex_in;
varying vec3 vertex_view_space;
void main() {
vertex_view_space = (GLUP_VS.modelview_matrix * vertex_in).xyz;
gl_Position = GLUP_VS.modelviewprojection_matrix * vertex_in;
}
并在关联的片段着色器中:
#extension GL_OES_standard_derivatives : enable
varying vec3 vertex_view_space;
...
vec3 U = dFdx(vertex_view_space);
vec3 V = dFdy(vertex_view_space);
N = normalize(cross(U,V));
... do the lighting with N
我喜欢这个解决方案,因为它使设置代码更简单。一个缺点可能是它为片段着色器提供了更多的工作(但对于今天的 GPU,这应该不是问题)。如果性能是个问题,衡量它可能是个好主意。
3) 另一种可能性是使用几何着色器(如果支持)来计算法线。一般来说它比较慢(但同样,衡量性能可能是个好主意,它可能取决于特定的 GPU)。
另请参阅此问题的答案:
How to get flat normals on a cube
我的实现可以在这里找到:
http://alice.loria.fr/software/geogram/doc/html/index.html
这里有一些在线 web-GL 演示(使用 emscripten 从 C++ 转换为 JavaScript):
http://homepages.loria.fr/BLevy/GEOGRAM/
查看 webGL2。支持平面着色。
对于顶点着色器:
#version 300 es
in vec4 vPos; //vertex position from application
flat out vec4 vClr;//color sent to fragment shader
void main(){
gl_Position = vPos;
vClr = gl_Position;//for now just using the position as color
}//end main
对于片段着色器
#version 300 es
precision mediump float;
flat in vec4 vClr;
out vec4 fragColor;
void main(){
fragColor = vClr;
}//end main
我正在尝试在 webgl 中实现平面着色,
我知道顶点着色器中的 varying
关键字将插值该值并将其传递给片段着色器。
我正在尝试禁用插值,我发现 flat
关键字可以做到这一点,但它似乎不能在 webgl 中使用?
flat varying vec4 fragColor;
总是出现错误:Illegal use of reserved word 'flat'
我认为 WebGL 中使用的 GLSL 版本不支持 'flat'。如果你想要平面着色,有几个选项:
1) 在每个顶点复制多边形的法线。最简单的解决方法,但是我觉得重复数据有点不尽如人意。
2) 在顶点着色器中,在视图坐标中变换顶点,在片段着色器中,使用计算导数的 dFdx() 和 dFdy() 函数计算法线。这些功能都是由扩展GL_OES_standard_derivatives支持的(使用前需要检查GPU是否支持),大多数GPU,包括智能手机中的GPU,都支持该扩展。
我的顶点着色器如下:
struct VSUniformState {
mat4 modelviewprojection_matrix;
mat4 modelview_matrix;
};
uniform VSUniformState GLUP_VS;
attribute vec4 vertex_in;
varying vec3 vertex_view_space;
void main() {
vertex_view_space = (GLUP_VS.modelview_matrix * vertex_in).xyz;
gl_Position = GLUP_VS.modelviewprojection_matrix * vertex_in;
}
并在关联的片段着色器中:
#extension GL_OES_standard_derivatives : enable
varying vec3 vertex_view_space;
...
vec3 U = dFdx(vertex_view_space);
vec3 V = dFdy(vertex_view_space);
N = normalize(cross(U,V));
... do the lighting with N
我喜欢这个解决方案,因为它使设置代码更简单。一个缺点可能是它为片段着色器提供了更多的工作(但对于今天的 GPU,这应该不是问题)。如果性能是个问题,衡量它可能是个好主意。
3) 另一种可能性是使用几何着色器(如果支持)来计算法线。一般来说它比较慢(但同样,衡量性能可能是个好主意,它可能取决于特定的 GPU)。
另请参阅此问题的答案: How to get flat normals on a cube
我的实现可以在这里找到: http://alice.loria.fr/software/geogram/doc/html/index.html
这里有一些在线 web-GL 演示(使用 emscripten 从 C++ 转换为 JavaScript): http://homepages.loria.fr/BLevy/GEOGRAM/
查看 webGL2。支持平面着色。 对于顶点着色器:
#version 300 es
in vec4 vPos; //vertex position from application
flat out vec4 vClr;//color sent to fragment shader
void main(){
gl_Position = vPos;
vClr = gl_Position;//for now just using the position as color
}//end main
对于片段着色器
#version 300 es
precision mediump float;
flat in vec4 vClr;
out vec4 fragColor;
void main(){
fragColor = vClr;
}//end main