问题
I have written a simple program that renders a sphere in a 3d environment and colores it according to four light sources around the sphere. When I run the program on the desktop it works just fine but on an Android device the sphere is just plain colored.
Here are images to illustrate what I am talking about:


And here is the shader code:
sphere.vert
#ifdef GL_ES
precision mediump float;
#endif
uniform mat4 u_projectionMatrix;
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
const int MAX_LIGHTS = 8;
uniform int u_lights_active;
uniform vec3 u_ambient;
uniform vec3 u_position[ MAX_LIGHTS ];
uniform vec3 u_diffuse[ MAX_LIGHTS ];
uniform vec3 u_att_coeffs[ MAX_LIGHTS ];
// since builtins aren't used, we use attributes as substitute
attribute vec2 a_texCoord0;
attribute vec4 a_position;
attribute vec3 a_normal;
// outputs to fragment shader
varying vec2 v_tex_coord;
varying vec4 v_color;
void main()
{
vec3 tempColor = u_ambient;
vec3 ecPosition = vec3( u_modelViewMatrix * a_position );
vec3 viewVec = normalize( -ecPosition );
vec3 tnorm = normalize( u_normalMatrix * a_normal );
for ( int i = 0; i < u_lights_active; ++i )
{
float dist = length( ecPosition - u_position[i] ); // distance from light to fragment
float att = 1.0 / ( u_att_coeffs[i].x + u_att_coeffs[i].y*dist + u_att_coeffs[i].z*dist*dist );
vec3 lightVec = normalize( u_position[i] - ecPosition );
float diffuse = max( dot( lightVec, tnorm ), 0.0 );
tempColor += att * u_diffuse[i] * diffuse;
}
tempColor = clamp( tempColor, 0.0, 1.0 );
v_color = vec4( tempColor, 0.0 );
gl_Position = u_projectionMatrix * vec4( ecPosition, 1.0 );
v_tex_coord = a_texCoord0.xy;
}
sphere.frag
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_texture;
varying vec2 v_tex_coord;
varying vec4 v_color;
void main()
{
vec4 texColor = texture2D( u_texture, v_tex_coord );
gl_FragColor = texColor * v_color;
}
I really hope that one of you guys can explain to me, what I'm doing wrong.
Version Numbers:
LibGDX: 0.9.8
ADT: Build v22.0.1-685705
Android Device: Sony Xperia S, Android 4.1.2
Project Build Target: Android 4.3, API 18
Mainfest contains
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
The shader is created by:
shaderProgram = new ShaderProgram( Gdx.files.internal( "shaders/sphere.vert" ), Gdx.files.internal( "shaders/sphere.frag" ) );
if ( !shaderProgram.isCompiled() )
{
Gdx.app.error( TAG, shaderProgram.getLog() );
}
The sphere is a StillModel:
creation:
final ModelLoaderHints hint = new ModelLoaderHints( true );
model = ModelLoaderRegistry.loadStillModel( Gdx.files.internal( "data/sphere.obj" ), hint );
texture = new Texture( Gdx.files.internal( "data/sphere_tex.png" ), Format.RGB888, false );
material = new Material( "mat", new TextureAttribute( texture, 0, "u_texture" ) );
rendering:
shaderProgram.begin();
texture.bind( 0 );
shaderProgram.setUniformMatrix( C.U_PROJECTION_MATRIX, cam.projection );
// light values
shaderProgram.setUniformi( C.U_LIGHTS_ACTIVE, lightsActive );
shaderProgram.setUniform3fv( C.U_LIGHT_AMBIENT, lightAmbient, 0, 3 );
shaderProgram.setUniform3fv( C.U_LIGHT_POSITION, lightPosition, 0, 3 * lightsActive );
shaderProgram.setUniform3fv( C.U_LIGHT_DIFFUSE, lightDiffuse, 0, 3 * lightsActive );
shaderProgram.setUniform3fv( C.U_LIGHT_ATT_COEFFS, lightAttCoeffs, 0, 3 * lightsActive );
modelMatrix.setToTranslation( positionWrap );
modelMatrix.rotate( rotationAxis, rotation );
modelMatrix.scale( scaleX, scaleY, scaleZ );
modelViewMatrix.set( cam.view ).mul( modelMatrix );
normalMatrix.set( modelViewMatrix ).inv().tra();
shaderProgram.setUniformMatrix( C.U_NORMAL_MATRIX, normalMatrix3x3.set( normalMatrix ) );
shaderProgram.setUniformMatrix( C.U_MODEL_VIEW_MATRIX, modelViewMatrix );
stillModel.render( shaderProgram );
shaderProgram.end();
Hope this is all the information needed.
Thanks in advance!
回答1:
Converting my comment-as-guess into an answer:
The GLSL spec only requires that very simple loops are supported (very "constant" loop bounds, etc). See my answer for-loop in shader code working with hardcoded number but not with uniform variable
In your case, you can probably fix this by always looping over the MAX_LIGHTS, and just multiplying the non-active light's impact by 0 (or making sure the non-active lights settings are all zero or all 1.0 or whatever makes them ineffectual).
Note that adding a branch inside the loop to "skip" unnecessary work may be slower because of how pixel shaders run (in SIMD parallel execution). Try and make all pixels always run the same sequence of instructions.
来源:https://stackoverflow.com/questions/18735667/libgdx-shader-working-on-desktop-but-not-on-android