基于 "normals" 剔除线和点
Culling lines and points based on "normals"
我正在尝试在 WebGL 中模拟 glPolygonMode( GL_BACK, GL_LINE)
之类的东西。我可以使用模式 LINES
而不是 TRIANGLES
进行绘制,但我看不到 WebGL 如何自动确定特定段是否面向背面,因为段不会面向任何地方。
为了解决这个问题,我将原始三角形的法线传递给着色器。在通常的模型视图转换(旋转、缩放、平移)下很容易计算这个转换;然后我只是将法线乘以逆的转置。根据法线是进还是出我可以决定是否剔除线段。
然而,这并不完全正确。我还需要投影矩阵的逆矩阵来考虑透视变形。
我正在使用 CanvasMatrix4.frustum()
或 CanvasMatrix4.ortho()
函数来获取投影矩阵。是否有可用于其反函数的公式或函数?
或者,是否有更好的方法来模拟 glPolygonMode( GL_BACK, GL_LINE)
?
求三角形的面积。如果是正数,就画出来,如果是负数,就剔除它。
如果可以选择使用 WebGl 扩展,您可能需要查看 OES_standard_derivatives. This extension was introduced for the specific purpose of solving your perspective correction issue. According to WebGL Stats 支持非常普遍。
在您的主代码库中,启用此扩展:
gl.getExtension("OES_standard_derivatives");
该扩展引入了 dFdx 和 dFdy 函数,允许您像这样进行 front/back 测试:
vec3 dx = dFdx(position);
vec3 dy = dFdy(position);
vec3 faceNormal = normalize(cross(dx, dy));
if (dot(normal, faceNormal) > 0.0) {
// Front facing
}
将三角形的其他顶点作为额外属性发送的想法似乎可行。
这是顶点着色器的关键部分。属性aPos
是线段中使用的顶点的位置; v1
是围绕三角形的下一个顶点,v2
是下一个顶点。
我编辑了代码以省略与照明相关的内容。这可能不是最有效的实施方式,但它确实有效。
attribute vec3 aPos;
uniform mat4 mvMatrix;
uniform mat4 prMatrix;
attribute vec3 v1;
attribute vec3 v2;
varying float normz;
void main(void) {
gl_Position = prMatrix * (mvMatrix * vec4(aPos, 1.));
vec4 v1p = (prMatrix*(mvMatrix*vec4(v1, 1.)));
v1p = v1p/v1p.w - gl_Position/gl_Position.w;
vec4 v2p = (prMatrix*(mvMatrix*vec4(v2, 1.)));
v2p = v2p/v2p.w - gl_Position/gl_Position.w;
normz = v1p.x*v2p.y - v1p.y*v2p.x; // z component of cross product
}
在片段着色器中,根据normz
的符号丢弃片段。我用
if ((normz <= 0.) != front) discard;
其中 front
是一个 bool
表示我是否要显示正面。
我正在尝试在 WebGL 中模拟 glPolygonMode( GL_BACK, GL_LINE)
之类的东西。我可以使用模式 LINES
而不是 TRIANGLES
进行绘制,但我看不到 WebGL 如何自动确定特定段是否面向背面,因为段不会面向任何地方。
为了解决这个问题,我将原始三角形的法线传递给着色器。在通常的模型视图转换(旋转、缩放、平移)下很容易计算这个转换;然后我只是将法线乘以逆的转置。根据法线是进还是出我可以决定是否剔除线段。
然而,这并不完全正确。我还需要投影矩阵的逆矩阵来考虑透视变形。
我正在使用 CanvasMatrix4.frustum()
或 CanvasMatrix4.ortho()
函数来获取投影矩阵。是否有可用于其反函数的公式或函数?
或者,是否有更好的方法来模拟 glPolygonMode( GL_BACK, GL_LINE)
?
求三角形的面积。如果是正数,就画出来,如果是负数,就剔除它。
如果可以选择使用 WebGl 扩展,您可能需要查看 OES_standard_derivatives. This extension was introduced for the specific purpose of solving your perspective correction issue. According to WebGL Stats 支持非常普遍。
在您的主代码库中,启用此扩展:
gl.getExtension("OES_standard_derivatives");
该扩展引入了 dFdx 和 dFdy 函数,允许您像这样进行 front/back 测试:
vec3 dx = dFdx(position);
vec3 dy = dFdy(position);
vec3 faceNormal = normalize(cross(dx, dy));
if (dot(normal, faceNormal) > 0.0) {
// Front facing
}
将三角形的其他顶点作为额外属性发送的想法似乎可行。
这是顶点着色器的关键部分。属性aPos
是线段中使用的顶点的位置; v1
是围绕三角形的下一个顶点,v2
是下一个顶点。
我编辑了代码以省略与照明相关的内容。这可能不是最有效的实施方式,但它确实有效。
attribute vec3 aPos;
uniform mat4 mvMatrix;
uniform mat4 prMatrix;
attribute vec3 v1;
attribute vec3 v2;
varying float normz;
void main(void) {
gl_Position = prMatrix * (mvMatrix * vec4(aPos, 1.));
vec4 v1p = (prMatrix*(mvMatrix*vec4(v1, 1.)));
v1p = v1p/v1p.w - gl_Position/gl_Position.w;
vec4 v2p = (prMatrix*(mvMatrix*vec4(v2, 1.)));
v2p = v2p/v2p.w - gl_Position/gl_Position.w;
normz = v1p.x*v2p.y - v1p.y*v2p.x; // z component of cross product
}
在片段着色器中,根据normz
的符号丢弃片段。我用
if ((normz <= 0.) != front) discard;
其中 front
是一个 bool
表示我是否要显示正面。