着色器在 iOS 上看起来很糟糕,但在 Windows 上看起来不错
Shader looks terrible on iOS but fine on Windows
我正在为 Windows 和 iOS 开发跨平台渲染器。对于示例应用程序,我编写了一个在两个平台上都能正常工作的着色器(Windows 上的着色器版本“#version 120”和 iOS 上的“#version 100”)。
接下来我又添加了两个光源,iOS 奇怪的事情开始发生了。我多次更改我的代码,但它从未向我显示预期的结果(手电筒是使用只有一盏灯的着色器渲染的,这就是它在 iOS 上看起来不错的原因)。
(1) 有时一切都是一种颜色:
(2) 有时它看起来很糟糕:
在 Windows 上看起来像我预期的样子:
有谁知道为什么我的着色器在 iOS 上这样做?
这是我用于 (2) 的片段着色器:
//Light
uniform mediump float numLights;
//L0
uniform mediump vec4 lightPosition_0;
uniform mediump vec3 lightColor_0;
uniform mediump float lightIntensity_0;
uniform mediump float lightAttenuation_0;
//L1
/*same as for light 0 */
//L2
/*same as for light 0 */
uniform mediump vec3 ambientColor;
uniform mediump vec3 Ka;
uniform mediump vec3 Kd;
uniform mediump vec3 Ks;
uniform sampler2D NormalMap;
uniform sampler2D DiffuseMap;
uniform sampler2D SpecularMap;
varying highp vec4 texCoordVarying;
varying highp vec4 posWorldSpace; // pos in View Space
varying highp vec3 tangentSurface2light_0;
varying highp vec3 tangentSurface2light_1;
varying highp vec3 tangentSurface2light_2;
void main()
{
//normal based on normal map
highp vec3 normalNormalMap = normalize(texture2D(NormalMap, texCoordVarying.st).xyz *2.0 - 1.0);
//ambient light
highp vec3 ambient = clamp(ambientColor + Ka, 0.0, 1.0);
//diffuse light
highp vec3 diffuse;
// light 0
if(numLights >= 1.0)
{
//light intensity based on distance from light to object
highp float distance = distance(posWorldSpace, lightPosition_0);
highp float intensityBasedOnDist = lightIntensity_0/(lightAttenuation_0*distance*distance);
intensityBasedOnDist = clamp(intensityBasedOnDist, 0.0, 1.0);
//light intensity based on angle between normal and light vector
highp float intensity = max(dot(normalNormalMap,tangentSurface2light_0), 0.0) ;
intensity = clamp(intensity, 0.0, 1.0);
//diffuse light
diffuse += lightColor_0 * intensity * intensityBasedOnDist;
}
// light 1
if(numLights >= 2.0)
{
/*same as for light 0 */
}
// light 2
if(numLights >= 3.0)
{
/*same as for light 0 */
}
diffuse = diffuse * Kd * texture2D(DiffuseMap, texCoordVarying.st).xyz;
gl_FragColor = vec4(clamp(ambient + diffuse, 0.0, 1.0), 1.0);
}
我做了很多 highp 或 mediump 的东西。当我制作 everything high 时,它有时看起来几乎是正确的,但现在即使那个技巧似乎也不再有用了......
您不得使用未初始化的变量。查看 diffuse 变量,您向未初始化的变量添加了一个值。只需替换:
highp vec3 diffuse;
与:
highp vec3 diffuse = vec3(0,0,0);
如果您使用未初始化的变量,行为可能因驱动程序而异。
- 尽可能避免 if 语句。对于您的情况,最好为一盏灯、两盏灯和三盏灯创建三个独立的着色器。您可以使用预处理器来保留单个源文件。
我正在为 Windows 和 iOS 开发跨平台渲染器。对于示例应用程序,我编写了一个在两个平台上都能正常工作的着色器(Windows 上的着色器版本“#version 120”和 iOS 上的“#version 100”)。
接下来我又添加了两个光源,iOS 奇怪的事情开始发生了。我多次更改我的代码,但它从未向我显示预期的结果(手电筒是使用只有一盏灯的着色器渲染的,这就是它在 iOS 上看起来不错的原因)。
(1) 有时一切都是一种颜色:
(2) 有时它看起来很糟糕:
在 Windows 上看起来像我预期的样子:
有谁知道为什么我的着色器在 iOS 上这样做?
这是我用于 (2) 的片段着色器:
//Light
uniform mediump float numLights;
//L0
uniform mediump vec4 lightPosition_0;
uniform mediump vec3 lightColor_0;
uniform mediump float lightIntensity_0;
uniform mediump float lightAttenuation_0;
//L1
/*same as for light 0 */
//L2
/*same as for light 0 */
uniform mediump vec3 ambientColor;
uniform mediump vec3 Ka;
uniform mediump vec3 Kd;
uniform mediump vec3 Ks;
uniform sampler2D NormalMap;
uniform sampler2D DiffuseMap;
uniform sampler2D SpecularMap;
varying highp vec4 texCoordVarying;
varying highp vec4 posWorldSpace; // pos in View Space
varying highp vec3 tangentSurface2light_0;
varying highp vec3 tangentSurface2light_1;
varying highp vec3 tangentSurface2light_2;
void main()
{
//normal based on normal map
highp vec3 normalNormalMap = normalize(texture2D(NormalMap, texCoordVarying.st).xyz *2.0 - 1.0);
//ambient light
highp vec3 ambient = clamp(ambientColor + Ka, 0.0, 1.0);
//diffuse light
highp vec3 diffuse;
// light 0
if(numLights >= 1.0)
{
//light intensity based on distance from light to object
highp float distance = distance(posWorldSpace, lightPosition_0);
highp float intensityBasedOnDist = lightIntensity_0/(lightAttenuation_0*distance*distance);
intensityBasedOnDist = clamp(intensityBasedOnDist, 0.0, 1.0);
//light intensity based on angle between normal and light vector
highp float intensity = max(dot(normalNormalMap,tangentSurface2light_0), 0.0) ;
intensity = clamp(intensity, 0.0, 1.0);
//diffuse light
diffuse += lightColor_0 * intensity * intensityBasedOnDist;
}
// light 1
if(numLights >= 2.0)
{
/*same as for light 0 */
}
// light 2
if(numLights >= 3.0)
{
/*same as for light 0 */
}
diffuse = diffuse * Kd * texture2D(DiffuseMap, texCoordVarying.st).xyz;
gl_FragColor = vec4(clamp(ambient + diffuse, 0.0, 1.0), 1.0);
}
我做了很多 highp 或 mediump 的东西。当我制作 everything high 时,它有时看起来几乎是正确的,但现在即使那个技巧似乎也不再有用了......
您不得使用未初始化的变量。查看 diffuse 变量,您向未初始化的变量添加了一个值。只需替换:
highp vec3 diffuse;
与:
highp vec3 diffuse = vec3(0,0,0);
如果您使用未初始化的变量,行为可能因驱动程序而异。
- 尽可能避免 if 语句。对于您的情况,最好为一盏灯、两盏灯和三盏灯创建三个独立的着色器。您可以使用预处理器来保留单个源文件。