【问题标题】:How to implement flat shading in OpenGL without duplicate vertices?如何在没有重复顶点的情况下在 OpenGL 中实现平面着色?
【发布时间】:2020-02-02 01:42:00
【问题描述】:

我正在尝试使用平面着色在 LWJGL OpenGL 中渲染 3D 棱镜。例如,我有一个索引如下的多维数据集:

我在顶点缓冲区中只有 8 个顶点,我已经按照上面的方法对其进行了索引。有没有办法在立方体上实现平面法线着色,如下所示?如果可能的话,我不想重写我的顶点和索引缓冲区以包含重复的顶点。

【问题讨论】:

  • 当您说“平面阴影”时,究竟是什么意思?你的意思是你想计算一个在三角形表面上恒定的面法线,还是你真的想在 VS 中计算光照?或者是其他东西。 “如果可能的话,我不想重写我的顶点和索引缓冲区以包含重复的顶点。” 为什么不呢?它会让事情变得容易得多。
  • 我已经为广义的第 n 维 3D 棱镜实现了顶点和索引,所以我不想回去重写所有这些。当我说平面着色时,我只是指创建类似上图所示的立方体。我已经可以计算出每个三角形的面法线,但我不知道如何在法线数组中格式化它们。
  • 所以您知道如何编写漫反射着色器,您的问题是,当您没有 IBO 时,如何将数据发送到 GPU 以使法线对应于直角三角形?
  • @Rabbid76 我担心你在这种情况下有点错误,因为对于 n 维对象,数学并没有在着色器中原生实现,如果发生任何类型的 3D 投影,你就不能再计算法线来自投影面而不会丢失信息......如果整个 ND 网格传递给着色器,它可能是可能的,但它很可能不会以 GLSL 原生方式传递,因此几何着色器也将无用。跨度>
  • @Sibh 看看这些:4D rendering techniquessimple ND rendering engine 以获得一些想法。然而,正如我在前面的评论中提到的,如果你想要正确的平面着色,你需要计算和传递 ND 法线而不是 3D 法线,并将照明点积调整为 ND !!!这些示例仅使用简单的 3D 法线,因此它们缺少 3D 以上的尺寸...这与您将 3D 对象投影到平面上并用单一颜色对其进行整体着色一样,因此您不会看到边缘...

标签: opengl glsl shader lwjgl n-dimensional


【解决方案1】:

如果您不需要任何其他属性(例如纹理坐标),则可以选择使用面法线向量创建立方体网格,仅 8 个顶点。使用flat Interpolation qualifier 作为法线向量。

顶点着色器:

flat out vec3 surfaceNormal;

片段切割器:

flat out vec3 surfaceNormal;

当使用flat 限定符时,顶点着色器的输出将不会被插值。赋予片段着色器的值是与图元的一个顶点相关联的属性之一,Provoking vertex
对于GL_TRINANGLE primitive,这是最后一个或第一个顶点。可以由glProvokingVertex选择。

选择第一个顶点:

glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);

关于立方体网格点的顺序(问题中的图像)

  front      back

  1     3    7     5
   +---+      +---+
   |   |      |   |
   +---+      +---+
  0     2    6     4

您必须设置以下顶点坐标和法向量:

//  x   y   z   nx, ny, nz
    -1, -1, -1,   0, -1,  0,  // 0, nv front
    -1, -1,  1,   0,  0,  1,  // 1, nv top
     1, -1, -1,   0,  0,  0,  // 2
     1, -1,  1,   1,  0,  0,  // 3, nv right
     1,  1, -1,   0,  1,  0,  // 4, nv back
     1,  1,  1,   0,  0,  0,  // 5
    -1,  1, -1,   0,  0, -1,  // 6, nv bottom
    -1,  1,  1,  -1,  0,  0,  // 7, nv left 

以这种方式定义索引,即顶点 7、3、0、4、6、1 是立方体的左、右、前、后、底部和顶部的两个三角形的第一个顶点:

0, 2, 3,   0, 3, 1, // front
4, 6, 7,   4, 7, 5, // back
3, 2, 4,   3, 4, 5, // right
7, 6, 0,   7, 0, 1, // left
6, 4, 2,   6, 2, 0, // bottom 
1, 3, 5,   1, 5, 7  // top

绘制 12 个三角形图元。例如:

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

【讨论】:

  • 诚实的问题,但是,您不是每个顶点还需要 3 个不同的法线吗?每张脸一个?这里的问题不在于插值,而是单个顶点需要不同的法线,具体取决于当前渲染的面
  • @Makogan 不,如果法线向量垂直于面(立方体的侧面),那么每个三角形只需要 1 个。如果边的 2 个三角形共享第一个顶点,则 2 个三角形的一个法向量就足够了。每个激发顶点需要 1 个法线向量。激发顶点由索引定义:0、4、3、7、6、1
  • 你如何告诉 GPU 读取哪个正常?我已经习惯了每个顶点有一个法线和一个 uv 的模式,所以我想当它们不匹配时如何渲染我有点困惑。
  • @Makogan "你如何告诉 GPU [...]" - 关键字 flatglProvokingVertex(GL_FIRST_VERTEX_CONVENTION)。这意味着与三角形的第一个顶点相关联的法向量被使用,第二个和第三个被忽略。注意,有 8 个顶点和 8 个法向量。它与索引和绘制三角形的顺序有关。没有 uv coordiadntes。您不能将此解决方案与纹理坐标一起使用,因为 falt 对纹理进行着色是没有意义的。
  • 啊,我明白了,您置换了面部的索引,这样对于 3 个潜在三角形中的每一个,都有不同的法线。因此,如果我正确理解这件事,如果您有一个三角形风扇,其中有 3 个以上的三角形共享同一个顶点,那么您将需要更花哨的东西。还是我完全错了?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-20
  • 2014-08-07
  • 2020-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多