如何在质心计算的光线下实现平面着色?

时间:2013-11-28 00:54:44

标签: opengl 3d glsl shader

我想为每个面部着色编写一个GLSL着色器程序。我的第一次尝试使用flat插值限定符和激发顶点。我对正常和位置顶点属性使用平面插值,这为我提供了实心绘制表面所需的老式效果。

虽然渲染看起来正确,但着色器程序实际上并没有做正确的工作:

  1. 光照计算仍然基于每个片段(在片段着色器中)执行,
  2. 位置向量取自激发的顶点,而不是三角形的质心(右?)。
  3. 是否可以将照明方程一次应用于三角形的质心,然后将计算出的颜色值用于整个基元?怎么做?

2 个答案:

答案 0 :(得分:2)

使用几何着色器,其输入为三角形,其输出为三角形。从顶点着色器传递法线和位置,自己计算质心(通过平均位置),并执行照明,将输出颜色作为输出变量传递给片段着色器,片段着色器只读取并写出来。

答案 1 :(得分:1)

另一种简单的方法是使用屏幕空间位置的导数计算片段着色器中的(屏幕空间)面法线。它实现起来非常简单,甚至表现良好。

我写了一个例子here(需要支持WebGL的浏览器):

顶点:

attribute vec3 vertex;

uniform mat4 _mvProj;
uniform mat4 _mv;

varying vec3 fragVertexEc;

void main(void) {
    gl_Position = _mvProj * vec4(vertex, 1.0);
    fragVertexEc = (_mv * vec4(vertex, 1.0)).xyz;
}

片段:

#ifdef GL_ES
precision highp float;
#endif

#extension GL_OES_standard_derivatives : enable

varying vec3 fragVertexEc;

const vec3 lightPosEc = vec3(0,0,10);
const vec3 lightColor = vec3(1.0,1.0,1.0);

void main()
{
    vec3 X = dFdx(fragVertexEc);
    vec3 Y = dFdy(fragVertexEc);
    vec3 normal=normalize(cross(X,Y));

    vec3 lightDirection = normalize(lightPosEc - fragVertexEc);

    float light = max(0.0, dot(lightDirection, normal));

    gl_FragColor = vec4(normal, 1.0);
    gl_FragColor = vec4(lightColor * light, 1.0);
}