【问题标题】:OpenGL ES 2.0 GLSL shader doesn't compileOpenGL ES 2.0 GLSL 着色器无法编译
【发布时间】:2021-06-29 07:40:45
【问题描述】:

我有一个带有简单着色器的 OpenGL 应用,它可以在具有 API 30 的 Android Studio 中的模拟器设备上运行良好,但在我自己的硬件设备 (API 30) 上却不能。

问题出在片段着色器中。这是代码:

#version 100

precision highp float;


struct DirLight {
    int on;
    vec3 direction;
    vec3 ambientColor;
    vec3 diffuseColor;
    vec3 specularColor;
    float specularExponent;
    sampler2D shadowMap;
    mat4 shadowVPMatrix;
    int shadowEnabled;
};

struct PointLight {
    int on;
    vec3 position;
    float constant;
    float linear;
    float quadratic;
    vec3 ambientColor;
    vec3 diffuseColor;
    vec3 specularColor;
    float specularExponent;
    sampler2D shadowMap;
    mat4 shadowVPMatrix;
    int shadowEnabled;
};

#define MAX_NUM_POINT_LIGHTS 8

uniform DirLight uDirLight;
uniform PointLight uPointLights[MAX_NUM_POINT_LIGHTS];
uniform int uNumPointLights;
uniform vec3 uViewPos;
uniform sampler2D uTexture;
uniform int uIsTextured;
varying vec4 vColor;
varying vec4 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoords;
const vec4 bitShifts = vec4(1.0 / (256.0*256.0*256.0), 1.0 / (256.0*256.0), 1.0 / 256.0, 1.0);



vec4 getColor(){
    if (uIsTextured != 0){
        return texture2D(uTexture,vTexCoords);
    }
    return vColor;
}

float unpack(vec4 color){
    return dot(color, bitShifts);
}

// return 0.0 if in shadow.
// return 1.0 if not in shadow.
float calcShadow(sampler2D shadowMap, vec4 positionFromLight, int shadowEnabled){
    if (shadowEnabled == 0){
        return 1.0;
    }
    vec3 positionFromLight3 = positionFromLight.xyz / positionFromLight.w;
    positionFromLight3 = (positionFromLight3 + 1.0) / 2.0;
    float closestFragmentZ = unpack(texture2D(shadowMap, positionFromLight3.xy));
    float currentFragmentZ = positionFromLight3.z;
    return float(closestFragmentZ > currentFragmentZ);
}

float diffuseLighting(vec3 normal, vec3 lightDir){
    return max(dot(normal, lightDir), 0.0);
}

float specularLighting(vec3 normal, vec3 lightDir, vec3 viewDir, float specularExponent){
    vec3 reflectDir = reflect(-lightDir, normal);
    return pow(max(dot(viewDir, reflectDir), 0.0), specularExponent);
}

vec4 calcDirLight(vec3 normal, vec3 viewDir){
    vec3 lightDir = normalize(-uDirLight.direction);
    float diff = diffuseLighting(normal, lightDir);
    float spec = specularLighting(normal, lightDir, viewDir, uDirLight.specularExponent);
    vec4 color = getColor();
    vec4 ambient = vec4(uDirLight.ambientColor, 1.0) * color;
    vec4 diffuse = vec4(uDirLight.diffuseColor * diff, 1.0) * color;
    vec4 specular = vec4(uDirLight.specularColor * spec, 1.0) * vec4(0.5,0.5,0.5,1.0);
    return ambient + (diffuse + specular) * calcShadow(uDirLight.shadowMap, uDirLight.shadowVPMatrix * vPosition, uDirLight.shadowEnabled);
}

float calcAttenuation(PointLight pointLight, float distance){
    return 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance));
}

vec4 calcPointLight(PointLight pointLight, vec3 normal, vec3 viewDir){
    vec3 d = pointLight.position - vec3(vPosition);
    vec3 lightDir = normalize(d);
    float diff = diffuseLighting(normal, lightDir);
    float spec = specularLighting(normal, lightDir, viewDir, pointLight.specularExponent);
    float distance = length(d);
    float attenuation = calcAttenuation(pointLight,distance);
    vec4 color = getColor();
    vec4 ambient = vec4(pointLight.ambientColor, 1.0) * color;
    vec4 diffuse = vec4(pointLight.diffuseColor * diff, 1.0) * color;
    vec4 specular = vec4(pointLight.specularColor * spec, 1.0) * vec4(0.5,0.5,0.5,1.0);
    ambient *= attenuation;
    diffuse *= attenuation;
    specular *= attenuation;
    return ambient + (diffuse + specular) * calcShadow(pointLight.shadowMap, pointLight.shadowVPMatrix * vPosition, pointLight.shadowEnabled);
}



void main() {
    vec3 normal = normalize(vNormal);
    vec3 viewDir = normalize(uViewPos - vec3(vPosition));
    vec4 result = vec4(0.0);
    if (uDirLight.on == 1){
        result = calcDirLight(normal, viewDir);
    }
    for (int i = 0; i < uNumPointLights; i++){
        if (uPointLights[i].on == 1){
            result += calcPointLight(uPointLights[i], normal, viewDir);
        }
    }
    gl_FragColor = result;
}

当我在我的设备上运行应用程序时,logcat 显示以下几行

2021-06-24 17:49:14.032 2061-2096/com.outofbound.rhinoengine I/AdrenoGLES-0: Build Config                     : S P 10.0.7 AArch64
2021-06-24 17:49:14.032 2061-2096/com.outofbound.rhinoengine I/AdrenoGLES-0: Driver Path                      : /vendor/lib64/egl/libGLESv2_adreno.so
2021-06-24 17:49:14.036 2061-2096/com.outofbound.rhinoengine I/AdrenoGLES-0: PFP: 0x016ee190, ME: 0x00000000
2021-06-24 17:49:14.040 2061-2061/com.outofbound.rhinoengine D/SurfaceView: UPDATE null, mIsCastMode = false
2021-06-24 17:49:14.074 2061-2102/com.outofbound.rhinoengine I/AdrenoGLES-0: ERROR: 0:101: 'viewDir' : undeclared identifier 
    ERROR: 0:101: 'specularLighting' : no matching overloaded function found 
    ERROR: 2 compilation errors.  No code generated.
2021-06-24 17:49:14.075 2061-2102/com.outofbound.rhinoengine I/AdrenoGLES-0: ERROR: 0:101: 'viewDir' : undeclared identifier 
    ERROR: 0:101: 'specularLighting' : no matching overloaded function found 
    ERROR: 2 compilation errors.  No code generated.
2021-06-24 17:49:15.316 2061-2085/com.outofbound.rhinoengine W/System: A resource failed to call close.

但是如果我只是在 main() 函数中将 viewDir 重命名为 v

void main() {
        vec3 normal = normalize(vNormal);
        vec3 v = normalize(uViewPos - vec3(vPosition));
        vec4 result = vec4(0.0);
        if (uDirLight.on == 1){
            result = calcDirLight(normal, v);
        }
        for (int i = 0; i < uNumPointLights; i++){
            if (uPointLights[i].on == 1){
                result += calcPointLight(uPointLights[i], normal, v);
            }
        }
        gl_FragColor = result;
    }

上面的错误消失了,但应用程序仍然无法显示黑屏。 有什么建议吗?

【问题讨论】:

  • 尝试将精度设置为中等

标签: android opengl-es opengl-es-2.0


【解决方案1】:

在我看来,viewDir 问题是一个驱动程序错误,它在尝试内联代码时搞砸了。

但是,您应该知道这不是 OpenGLES 2 标准的简单着色器。正如 Dpk 所暗示的,您不能假设 OpenGLES2 中提供了高精度。

此外,您不能假设在任何地方都有足够的统一空间供着色器使用。尝试使用glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &amp;maxFragmentUniforms); 查看支持的制服数量。允许设备低至 16 个 vec4,但您的着色器使用 100 个。

如果您不想担心 GLES2 的某些严格限制,我建议您考虑切换到 OpenGLES 3 或 3.1。如果您坚持使用 OpenGLES2,那么可能会将着色器直接切回任何内容(只返回一种颜色)并逐渐建立功能。

此外,请确保检查着色器编译和链接以及所有 OpenGLES 调用的错误,这样可以节省大量时间。

【讨论】:

  • ES 3.0 没有变化。调用 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniforms);返回 256。所以我认为这与供应商 glsl 编译器有关。如果我将主函数中的 calcPointLight(uPointLights[i], normal) 更改为 calcPointLight(uPointLights[0], normal) 它可以正常工作。
【解决方案2】:

试试

//#version 100    
//precision highp float;

precision mediump float;

试试这个 opengles20 可能不支持参数中的 INT 参见文档

float on;
//if (uDirLight.on == 1){
if (uDirLight.on == 1.0){

【讨论】:

    【解决方案3】:

    我认为该错误与统一uniform PointLight uPointLights[MAX_NUM_POINT_LIGHTS]; 的数组有关。所以我用点光源解决了

    uniform PointLight uPointLight;.

    无论如何,如果使用 0 uniform PointLight uPointLightN;,我会尝试它仍然有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多