问题描述
我有一个带有简单着色器的 OpenGL 应用,该应用在 Android Studio 中的模拟器设备上运行良好,带有 API 30,但在我自己的硬件设备 (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,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,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);
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],v);
}
}
gl_FragColor = result;
}
上面的错误消失了,但应用程序仍然无法运行,显示黑屏。 有什么提示吗?
解决方法
在我看来,viewDir
问题是一个驱动程序错误,试图内联您的代码时出错。
但是,您应该知道这不是 OpenGLES 2 标准的简单着色器。正如 Dpk 暗示的那样,您不能假设 OpenGLES2 具有高精度。
此外,您不能假设任何地方都有足够均匀的空间供您的着色器使用。尝试使用 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,&maxFragmentUniforms);
来查看支持的制服数量。允许设备低至 16 vec4s,但您的着色器使用 100s。
如果您不想担心 GLES2 的某些严格限制,我建议您考虑切换到 OpenGLES 3 或 3.1。如果您坚持使用 OpenGLES2,那么也许可以将着色器从字面上切回零(只返回一种颜色)并逐渐构建功能。
此外,请确保您正在检查着色器编译和链接以及所有 OpenGLES 调用的错误,这样可以节省大量时间。
,试试
//#version 100
//precision highp float;
precision mediump float;
试试这个 opengles20 可能不支持参数中的 INT 参见文档
float on;
//if (uDirLight.on == 1){
if (uDirLight.on == 1.0){
,
我认为该错误与uniform uniform PointLight uPointLights[MAX_NUM_POINT_LIGHTS];
的数组有关。所以我解决了使用一个点光源
uniform PointLight uPointLight;
。
无论如何我会尝试定义多个 uniform PointLight uPointLightN;
与 0