【问题标题】:OpenGL fragment shader is moving objectsOpenGL片段着色器正在移动对象
【发布时间】:2014-03-20 09:35:32
【问题描述】:

我正在尝试以与此 Vuforia 帖子中建议的方式类似的方式将定向光照写入 OpenGL 着色器:

https://developer.vuforia.com/resources/dev-guide/enabling-lighting-effects

但是,这个着色器的效果相当暗淡,并且被锁定在设备上,就好像光源来自屏幕一样。因此,我创建了一个uniform vec3f,它由模型视图投影矩阵操作,以允许我将一个常量向量锁定到模型框架(顺便说一下,这个位似乎正在工作)。为了消除暗淡,我增加了环境光和漫反射光颜色矢量的值,并且我还为定向光添加了轻微的黄色偏光,为环境光添加了轻微的蓝色偏光。

这导致一些东西消失了;我猜想着色器可能正在创建无效的颜色值。没问题。我在末尾添加了一个钳制系统,它采用 0.9 到 1.1 的值并将它们压缩到 0.9 到 1.0 的范围(一种原始软剪辑),并采用低于 0.0 的任何值并将它们钳制到 0.0。

上限钳位适用于某些对象,但不适用于其他对象。下限钳制导致各种对象看起来以明显随机的角度旋转。

所以我假设正在发生的事情是我的着色器溢出到相邻的内存位置并搞砸了顶点渲染,但我不知道是什么。此外,由于我直到中间颜色向量被钳位后才写入 gl_FragColor,所以我不知道为什么会发生这种情况。谁能给点建议?

附上完整的着色器代码:

static const char* cubeMeshVertexShader = " \
  \
attribute vec4 vertexPosition; \
attribute vec4 vertexNormal; \
attribute vec2 vertexTexCoord; \
 \
varying vec2 texCoord; \
varying vec4 normal; \
 \
uniform mat4 modelViewMatrix; \
uniform mat4 modelViewProjectionMatrix; \
void main() \
{ \
   gl_Position = modelViewProjectionMatrix * vertexPosition; \
   normal = modelViewMatrix * vec4(vertexNormal.xyz, 0.0); \
   normal = normalize(normal); \
   texCoord = vertexTexCoord; \
} \
";


static const char* cubeFragmentShader = " \
 \
precision mediump float; \
 \
varying vec2 texCoord; \
varying vec4 normal; \
 \
uniform sampler2D texSampler2D; \
uniform vec3 lightingVector; \
uniform vec3 diffuseMaterial; \
 \
void main() \
{ \
   vec3 n = normalize(normal.xyz); \
   vec3 lightDir = vec3(0.0, 0.0, -1.0); \
   vec3 ambient = vec3(0.5, 0.57, 0.6); \
   vec3 diffuseLight = vec3(0.9, 0.89, 0.87); \
   float diffuseFactor = max(0.0, dot(n, normalize(lightingVector))); \
   vec3 diffuse = diffuseFactor * diffuseMaterial * diffuseLight; \
   vec3 shadedColor = ambient + diffuse; \
 \
   vec4 intermediate = vec4(shadedColor, 1.0) * texture2D(texSampler2D, texCoord); \
   if(intermediate.x>0.9) { \
      if(intermediate.x<1.1) { \
         intermediate.x = intermediate.x / 2.0 + 0.45; \
      } else { \
         intermediate.x = 1.0; \
      } \
   } else if(intermediate.x<0.0) { \
      intermediate.x = 0.0; \
   } \
   if(intermediate.y>0.9) { \
      if(intermediate.y<1.1) { \
         intermediate.y = intermediate.y / 2.0 + 0.45; \
      } else { \
         intermediate.y = 1.0; \
      } \
   } else if(intermediate.y<0.0) { \
      intermediate.y = 0.0; \
   } \
   if(intermediate.z>0.9) { \
      if(intermediate.z<1.1) { \
         intermediate.z = intermediate.z / 2.0 + 0.45; \
      } else { \
         intermediate.z = 1.0; \
      } \
   } else if(intermediate.y<0.0) { \
      intermediate.y = 0.0; \
   } \
   gl_FragColor = intermediate; \
} \
";

编辑:OpenGL 标准规定 gl_FragColor 自动钳制为 [0,1],因此我的钳制系统是不必要的(尽管我可能会保留软剪辑)。但是,这表明导致问题的实际上是着色器操作的副作用,而不是效果。

【问题讨论】:

  • 您所描述的溢出(您的假设)不会发生在 GPU 和着色器上。你永远不能覆盖你不应该从普通着色器覆盖的内存。从理论上讲,它可能是驱动程序或硬件错误,但我高度对此表示怀疑。
  • 着色器代码中的“钳制”部分会非常慢。请考虑数学函数或查找表。此外,为了调试,请处理您的值超过 1.1 的情况。而且你那里至少有一个错误;最后一个条件(else if (y&lt;0.0))应该检查并设置intermediate.z,我相信。
  • 你用 texel 值调整shadedColor 的那一行有点可疑。我不确定这是否可以正常发生,但是如果您的纹理查找有时返回 0 的 alpha,并且您启用了 alpha 混合或拒绝,您最终会得到一个剪辑片段(即可能是您所看到的现在。)你能把那行改成vec4 intermediate = vec4(shadedColor * texture2D(texSampler2D, texCoord).rgb, 1);并检查一下吗?
  • 我认为这是一个 NDK 构建错误。评论仍然很有帮助,所以谢谢!
  • 问题不在于;都是不连贯的if 语句。例如,您可以用这个替换整个if-else-if-else... 结构(假设vec3 x = intermediate.rgb;vec3 edge = vec3(0.9, 0.9, 0.9);,并对错误的格式表示抱歉):vec3 over_edge = step(edge, x); vec3 delta = over_edge * (x - edge) * 0.5; gl_FragColor = vec4(clamp(x - delta, 0, 1), 1);。我认为这将等同于您的所有条件,并且会更快。

标签: android c++ opengl-es


【解决方案1】:

着色器中的光照目录是恒定的,但 lightdir 应该是指向光源的对象的目录,因此它应该在顶点着色器中按每个顶点计算

vec3 LightDir = normalize(gl_LightSource[0].position.xyz - vec3(gl_ModelViewMatrix * gl_Vertex);

此外,您在中间计算中的一个系数(钳位具有适当的功能:钳位)可以等于 0。

这可能是:

  • 您的纹理未绑定,它将乘以 (0,0,0,0) 您的 shadedColor。
  • 您的漫反射材质未设置
  • 你的光向量垂直于法线(点积 = 0)

【讨论】:

  • 实际上我认为这是一个 NDK 构建问题。不过谢谢!
  • 如果对象在场景中旋转,这仍然是一个问题,即您的光矢量在片段着色器中是恒定的
  • 我希望将向量锁定到对象,所以这实际上很好——我正在使用 C++ 函数在外部设置向量值,这正是我想要做的。我不需要每个顶点的光照变化(点积用于计算每个片段接收的定向光照量)。
  • 没问题,总之有帮助:)
【解决方案2】:

这实际上是由于我愚蠢地没有在另一个编辑中初始化一些参数而导致的;它试图通过NaN 旋转一些对象。我把问题留在这里是因为 cmets 对着色器编程有一些很好的建议。

【讨论】:

  • 你应该接受你自己的答案,所以这不会一直无人回答。
猜你喜欢
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多