【问题标题】:How to achieve flat shading with light calculated at centroids?如何使用在质心处计算的光来实现平面着色?
【发布时间】:2013-11-28 00:54:44
【问题描述】:

我想编写一个 GLSL 着色器程序来进行逐面着色。我的第一次尝试使用带有激发顶点flat 插值限定符。我对法线和位置顶点属性都使用平面插值,这给了我想要的纯色表面的老式效果。

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

  1. 仍然基于每个片段(在片段着色器中)执行光照计算,
  2. 位置向量取自激发顶点,而不是三角形的质心(对吗?)。

是否可以将照明方程一次应用于三角形的质心,然后将计算出的颜色值用于整个图元?该怎么做?

【问题讨论】:

    标签: opengl 3d glsl shader


    【解决方案1】:

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

    【讨论】:

    • 这是个好主意!但是引入额外的着色阶段对性能有何影响?从理论上讲,您的方法应该快得多,因为它会为每个图元计算一次照明方程。另一方面,在浏览相关问题和答案时,我发现人们认为几何着色是一种非常缓慢的技术。也许这些只是偏见,但总是值得一问。
    • 扩展几何着色器(即输出的顶点数多于输入的顶点数)总体上非常慢。非扩展几何着色器(例如您为此使用的着色器)通常至少在性能上是可以接受的,而且我认为在较新的硬件上它们总体上相当不错。请注意,除非您的照明计算非常复杂,或者您使用的硬件功能极低,否则在管道中向上移动照明计算可能不会为您节省太多:成本就像像素着色器线程的实际启动一样。
    【解决方案2】:

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

    我已经写了一个例子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);
    }
    

    【讨论】:

    • 请注意,在这种情况下,位置是按片段计算的,而不是在质心处计算一次。这意味着对于非定向灯或阴影投射灯,整个三角形的照明不会相同。
    • 感谢您的示例!但是dFdxdFdy 函数的含义是什么?我应该如何解释它们的输出值?根据我最初的研究,它们“在”四个(对吗?)片段着色器线程之间运行,并对属于两个不同坐标系(3D view space 和 2D viewport space)的向量进行操作>,对吧?)。但它们是什么意思?如何“可视化”它们背后的概念?
    • 在这种用法中,您可以将 dFdx 和 dFdy 视为当前三角形的斜率或切线。用更抽象的术语来说,dFdx 和 dYdy 告诉你当你水平或垂直移动一个像素时给定变量会发生什么。或者用更数学的术语来说,是变量在 x 或 y 方向上的导数。
    • 据我了解:dFdx 返回顶点属性插值函数的差商,沿 2D 视口空间的 X 轴,但关于存在于3D 眼睛空间(例如,位置向量)。或者简单地说:告诉“我”和“我的”下一个水平邻居(在屏幕上)之间属性的变化方向。对吗?
    • @KrzysztofAbramowicz:没有视口空间这样的东西。视口用于限制图像在图像平面上的投影位置,但坐标空间实际上是窗口空间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 2018-12-26
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多