简体   繁体   中英

OpenGL ES 2.0 GLSL shader doesn't compile

I have an OpenGL app with a simple shader that run well on an emulator device in Android Studio with API 30 but on my own hardware device (API 30) it doesn't.

The problem is in the fragment shader. This is the code:

#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;
}

When I run the app on my device logcat shows the following lines

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.

BUT if I simply rename viewDir to v in main() function

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;
    }

the error above disappears but the app still doesn't work showing a black screen. Any tips?

It looks to me that the viewDir issue is a driver bug where it's messed up trying to inline your code.

However, you should be aware that is not a simple shader by OpenGLES 2 standards. As Dpk implied, you cannot assume high precision is available in OpenGLES2.

Additionally, you cannot assume that there's anywhere near enough uniform space for your shader. Try using glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxFragmentUniforms); to see how many uniforms are supported. Devices are allowed to go as low as 16 vec4s, but your shader uses 100s.

I'd suggest you consider switching to OpenGLES 3 or 3.1 if you don't want to worry about some of the tight limits of GLES2. If you persist with OpenGLES2 then maybe cut the shader right back to literally nothing (just return a colour) and gradually build up the functionality.

Also, make sure you are checking for errors on shader compilation and linking and all OpenGLES calls, it can save a lot of time.

try

//#version 100    
//precision highp float;

precision mediump float;

and try this opengles20 may not support INT in param see doc

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

I think the error is related to the array of uniform uniform PointLight uPointLights[MAX_NUM_POINT_LIGHTS]; . So I solved using one point light

uniform PointLight uPointLight; .

Anyway I'll try if defining multiple uniform PointLight uPointLightN; with 0 <= N < MAX_NUM_POINT_LIGHTS it still works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM