【发布时间】: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<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);。我认为这将等同于您的所有条件,并且会更快。