【问题标题】:Shader looks terrible on iOS but fine on Windows着色器在 iOS 上看起来很糟糕,但在 Windows 上很好
【发布时间】:2015-06-24 19:27:16
【问题描述】:

我正在开发适用于 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。当我让一切都变得高高在上时,它有时看起来几乎是正确的,但现在即使是那个技巧似乎也不再有用了......

【问题讨论】:

    标签: ios opengl glsl opengl-es-2.0 glsles


    【解决方案1】:
    1. 您不得使用未初始化的变量。查看 diffuse 变量,您为未初始化的变量添加了一个值。只需替换:

      highp vec3 diffuse;
      

      与:

      highp vec3 diffuse = vec3(0,0,0);
      

      如果您使用未初始化的变量,则行为可能因驱动程序而异。

    2. 尽可能避免使用 if 语句。对于您的情况,最好为一盏灯、两盏灯和三盏灯创建三个单独的着色器。您可以使用预处理器来保留单个源文件。

    【讨论】:

    • 非常感谢,您为我节省了尝试东西的时间 :-) 我从没想过这会是个问题(我对 GLSL 还很陌生)。为什么我应该避免使用“if”语句?我想灵活地使用灯光,也许在不创建新着色器的情况下从一帧到另一帧关闭一个……这会导致错误吗?再次感谢:-)
    • @Ben 在着色器中分支的问题是它们非常慢。您可以编写自己的预处理器,使用与#ifdef/#endif 类似的构造从相同的源代码编译多个着色器。在同一着色器的多个版本之间切换比在着色器本身中动态分支要快得多。
    • 非常感谢,我会尽量避免使用“if”和“else”。不幸的是,我只有在绘图时才知道确切的灯光数量,并且我将灯光数量作为统一传递。我将不得不更改它,以便您只能通过创建着色器时指定的灯光数量。这当然不太灵活并且会导致错误。目前我可以通过我想要的任意数量的灯光,而且这一切都在内部处理,所以永远不会太少或太多。我会考虑的……
    猜你喜欢
    • 2020-03-03
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多