LibGDX-шейдер, работающий на рабочем столе, но не на Android


Я написал простую программу, которая визуализирует сферу в трехмерной среде и окрашивает ее в соответствии с четырьмя источниками света вокруг сферы. Когда я запускаю программу на рабочем столе, она работает просто отлично, но на устройстве Android сфера просто окрашена.

Вот изображения, иллюстрирующие то, о чем я говорю:

Введите описание изображения здесь -> рабочий стол

Введите описание изображения здесь -> Android

А вот и шейдер код:

Сфера.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;
}

Сфера.фраг

#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;
}
Я очень надеюсь, что кто-нибудь из Вас сможет объяснить мне, что я делаю не так.

Номера Версий:

LibGDX: 0.9.8

ADT: Build v22. 0. 1-685705

Android-Устройство: Sony Xperia S, Android 4.1.2

Цель сборки проекта: Android 4.3, API 18

Mainfest содержит

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

Шейдер создан автор:

shaderProgram = new ShaderProgram( Gdx.files.internal( "shaders/sphere.vert" ), Gdx.files.internal( "shaders/sphere.frag" ) );
if ( !shaderProgram.isCompiled() )
{
    Gdx.app.error( TAG, shaderProgram.getLog() );
}

Сфера-это неподвижная модель:

Создание:

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" ) );

Рендеринг:

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();
Надеюсь, что это вся необходимая информация.

Заранее спасибо!

1 4

1 ответ:

Преобразование моего комментария как догадки в ответ:

Спецификация GLSL требует только, чтобы поддерживались очень простые циклы (очень "постоянные" границы циклов и т. д.). Смотрите мой ответ for-loop в шейдерном коде, работающем с жестко закодированным числом, но не с однородной переменной

В вашем случае вы, вероятно, можете исправить это, всегда зацикливаясь на MAX_LIGHTS и просто умножая воздействие неактивного света на 0 (или убедившись, что настройки неактивного света все равны нулю или все 1.0 или все, что делает их неэффективными).

Обратите внимание, что добавление ветви внутри цикла для "пропуска" ненужной работы может быть медленнее из-за того, как работают шейдеры пикселей (при параллельном выполнении SIMD). Попробуйте сделать так, чтобы все пиксели всегда выполняли одну и ту же последовательность инструкций.