5

非推奨の機能なしでOpenGLを使用しており、ライトの計算はフラグメントシェーダーで行われます。だから、スムーズなシェーディングをしています。

私の問題は、立方体を描くとき、​​フラットな法線が必要なことです。フラット法線とは、面で生成されたすべてのフラグメントが同じ法線を持っていることを意味します。

これまでの私の解決策は、面ごとに異なる頂点を生成することです。したがって、8つの頂点を使用する代わりに、24(6 * 4)の頂点を使用するようになりました。

しかし、これは私には間違っているようで、頂点を複製します。フラット法線を取得するためのより良い方法はありますか?

更新:OpenGLバージョン3.3.0を使用していますが、OpenGL4はまだサポートされていません。

4

3 に答える 3

10

カメラ空間でライティングを行う場合、dFdx/dFdy を使用して、頂点のカメラ空間位置から顔の法線を計算できます。

したがって、フラグメント シェーダーは次のようになります。

varying vec3 v_PositionCS; // Position of the vertex in camera/eye-space (passed in from the vertex shader)

    void main()
    { 
      // Calculate the face normal in camera space
      vec3 normalCs = normalize(cross(dFdx(v_PositionCS), dFdy(v_PositionCS)));

      // Perform lighting 
      ...
      ...
    }
于 2013-02-20T13:48:05.743 に答える
6

ジオメトリ シェーダは三角形の 3 つの頂点すべてを一度に「見る」ことができるため、ジオメトリ シェーダを使用して法線を計算し、フラグメント シェーダに送ることができます。この方法では、頂点を複製する必要はありません。

// Geometry Shader

#version 330 

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

out vec3 gNormal;

// You will need to pass your untransformed positions in from the vertex shader
in vec3 vPosition[];

uniform mat3 normalMatrix;

void main()
{
    vec3 side2 = vPosition[2] - vPosition[0];
    vec3 side0 = vPosition[1] - vPosition[0];
    vec3 facetNormal = normalize(normalMatrix * cross(side0, side2));

    gNormal = facetNormal;
    gl_Position = gl_in[0].gl_Position;
    EmitVertex();

    gNormal = facetNormal;
    gl_Position = gl_in[1].gl_Position;
    EmitVertex();

    gNormal = facetNormal;
    gl_Position = gl_in[2].gl_Position;
    EmitVertex();

    EndPrimitive();
}
于 2013-02-20T13:44:08.083 に答える
3

別のオプションは、MV-matrix と回転していない AxisAligned 座標をフラグメント シェーダーに渡すことです。

 attribute aCoord;
 varying vCoord;
 void main() {
    vCoord = aCoord;
    glPosition = aCoord * MVP;
 }

フラグメント シェーダーでは、vCoord の主軸を計算し、それを 1.0 (または -1.0) に設定し、他の座標をゼロに設定することで法線を特定できます。これが法線であり、MV マトリックスによって回転する必要があります。

于 2013-02-20T14:00:56.047 に答える