片段着色器中的Uniform int始终为零

时间:2014-01-28 17:48:41

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

我正在为我的游戏做自己的引擎,并且我在着色器方面遇到了很多问题。最令人讨厌的一个是我无法计算灯光,因为片段着色器中的条件永远不会满足,所以永远不要求不同材质/灯光的颜色。我发现问题的代码是:

// Compute lights
vec4 totalColorLighting = vec4(0.0);
for (int indexComputeLights = 0; indexComputeLights <  MAX_LIGHTS; indexComputeLights++)
{
    if (indexComputeLights < numLights) {

numLights是传递给片段着色器的制服。如果我在if语句之外写totalColorLight = vec4(1,0);,我的模型将以白色绘制。如果我把它放在里面,就像我想要的那样,屏幕仍然是黑色......

简而言之,显示白色模型的代码是:

for (int indexComputeLights = 0; indexComputeLights <  MAX_LIGHTS; indexComputeLights++)                              
{
    totalColorLight = vec4(1,0); // model is white, so here it´s entering

    if (indexComputeLights < numLights) {
                // code that never get executed
            }
}

代码无效:

for (int indexComputeLights = 0; indexComputeLights <  MAX_LIGHTS; indexComputeLights++)    
{
    if (indexComputeLights < numLights) {
            totalColorLight = vec4(1,0); // model is black, so here it´s NOT entering
            }
}

获得“workarround”的其他方法是将“numLights”更改为,例如2或1这样的常数。我修改了通过eclipse调试器将统一值传递给着色器的变量,并且1,所以应该输入if语句。

我将数据上传到此统一的方式是:

int[] vecNumLights = new int[1];
vecNumLights[0] = numLights;            
GLES20.glUniform1iv(gl_numLights_Uniform_Locator, 1, vecNumLights, 0);

快速浏览一下,有人知道我的错误吗?您需要复制更多代码吗?

顺便说一句,我使用4.4.2 Api 19 SDK

编辑1:

我注意到indexComputeLights从一开始就不为零。如果我写这样的条件:

 if (indexComputeLights > 0) totalColorLight = totalColorLight + vec4(0.05); 

如果条件是

,那么条件越高,模型就越白
 if (indexComputeLights > 6) 

颜色结束时更加透明和黑色,只是按照我认为的相反顺序。使用for-unroll发生了什么?

EDIT2:

我认为我的问题与此非常相似:http://www.opengl.org/discussion_boards/showthread.php/171366-problem-with-uniform-int-and-for-loop

不同之处在于我没有注意到for循环是无穷无尽的

EDIT3:

我发现numLights(这是一个统一的int)总是为零。我不明白什么是失败的,因为所有其他制服看起来都很好。我在顶点和片段着色器之间共享统一名称,但在顶点着色器中看起来工作正常。

EDIT4:

我想与您分享完整的顶点和片段代码。

顶点着色器:

#pragma glsl

attribute vec3 position;
attribute vec3 normal;
attribute vec2 texCoord;

// matrices we'll need
uniform mat4 inversedTrasposedModelViewMatrix; 
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

// other uniforms, constant or data we are going to use
const int MAX_LIGHTS = 8;

struct LightSourceParameters {
mediump vec3 ambient; 
mediump vec3 lightColor;
mediump vec4 position;  
mediump float spotExponent; 
mediump float spotCutoff; // (range: [0.0,90.0], 180.0)
mediump vec3 spotDirection;
mediump float constantAttenuation; 
mediump float linearAttenuation; 
mediump float quadraticAttenuation; 
};
uniform LightSourceParameters LightSource[MAX_LIGHTS];

uniform lowp int numLights;

// out parameters to fragment shader: varyings      
varying vec3 outNormal;
varying vec2 outTextCoord;
varying vec3 outViewVector;
varying vec3 outLightVector[MAX_LIGHTS];



void main(){

// Calculate view-space position coordinate
vec4 P = modelViewMatrix * vec4(position,1.0);

// Calculate the normal in view-space
outNormal = vec3(inversedTrasposedModelViewMatrix * vec4(normal ,0.0));

// Calculate the view vector in view-space space coordinate
outViewVector = -P.xyz;

// Assign the texture coordinate
outTextCoord = texCoord;

// Calculate clip-space position of each vertex
gl_Position = projectionMatrix * P;

// Calculate light vector for all light source
for (int indexLightVector = 0; indexLightVector < MAX_LIGHTS; indexLightVector++){
    if (indexLightVector < numLights) {
        /* Si no es ambiental: la unica luz que no lleva asociada vector */
        if ((length(LightSource[indexLightVector].ambient) == 0.0) /* no ambiental */
                && (LightSource[indexLightVector].position.w != 0.0)){ /* no directional */

            /* La luz es o point o spotLight */                 
            outLightVector[indexLightVector] = vec3(modelViewMatrix*LightSource[indexLightVector].position) - P.xyz;

        }
        else if (length(LightSource[indexLightVector].ambient) == 0.0) { /* no ambiental */
            /* La luz es directional: position es un vector,
             * lo transformamos con inversedTransposedModelViewMatrix
             * y lo negamos para que vaya desde el punto a la luz y no al revés
             */
            outLightVector[indexLightVector] = - vec3(inversedTrasposedModelViewMatrix*LightSource[indexLightVector].position);

        }
    }
}


} 

片段着色器:

#pragma glsl

precision mediump float;

const int MAX_LIGHTS = 8;

struct LightSourceParameters {
vec3 ambient; 
vec3 lightColor;
vec4 position;  
float spotExponent; 
float spotCutoff; // (range: [0.0,90.0], 180.0)
vec3 spotDirection;
float constantAttenuation; 
float linearAttenuation; 
float quadraticAttenuation; 
};
uniform LightSourceParameters LightSource[MAX_LIGHTS];

struct MaterialParameters {
vec4 emission;   
vec4 ambient;    
vec4 diffuse;
sampler2D diffuseTexture;
int hasDiffuseTexture;    
vec4 specular;
sampler2D specularTexture;
int hasSpecularTexture;
float shininess; 
};  
uniform MaterialParameters Material;

uniform lowp int numLights;

varying vec3 outNormal;
varying vec2 outTextCoord;
varying vec3 outViewVector;
varying vec3 outLightVector[MAX_LIGHTS];

/* Declaramos cabecera de funcion, necesaria para que GLSL no diga que la funcion no existe, al definirse despues de main */
vec4 computeLight(in MaterialParameters material, in LightSourceParameters lightSource, in vec3 normal, in vec2 textCoord, in vec3 lightVector, in vec3 halfVector);

void main(){

    // Normalize the incoming vectors
    vec3 normal = normalize(outNormal);
    vec3 viewVector = normalize(outViewVector);
    vec3 lightVector[MAX_LIGHTS];
    vec3 halfVector[MAX_LIGHTS];    
    // normalize lightvector, compute half vectors and lights
    vec4 totalColorLighting = vec4(0.0);
    int indexComputeLights = 0;
    for (indexComputeLights; indexComputeLights <  MAX_LIGHTS; indexComputeLights++){


        if (indexComputeLights < numLights) {

            totalColorLighting = totalColorLighting + vec4(0.05); 

            if (length(LightSource[indexComputeLights].ambient) == 0.0 ){ /* no es ambiental, que no tienen vector */
                lightVector[indexComputeLights] = normalize(outLightVector[indexComputeLights]);
            }

            if (length(LightSource[indexComputeLights].ambient) == 0.0 ){ /* no es ambiental, que no tienen half vector */
                halfVector[indexComputeLights] = normalize(outLightVector[indexComputeLights] + outViewVector);
            }

            LightSourceParameters light = LightSource[indexComputeLights];
            vec3 currentLightVector = lightVector[indexComputeLights];
            vec3 currentHalfVector = halfVector[indexComputeLights];

            /* Si la luz es ambiental, halfVector y lightVector son 
             * indefinidos para esa luz, pero da igual porque no son 
             * utilizados en el algoritmo que calcula las luces
             */
            totalColorLighting = totalColorLighting + computeLight(Material, light, normal, outTextCoord, currentLightVector, currentHalfVector);
            indexComputeLights = indexComputeLights + 1;
        }

    }

    vec4 emission = Material.emission;
    // vec4 emission = vec4(0.5);
    // totalColorLighting = vec4(0.0);
    // Compute emission material
    if (length(emission) != 0.0) { /* El material tiene un termino emisivo, es decir, emite luz. Lo andimos al total de color calculado */
        totalColorLighting = totalColorLighting + emission;
    }

    /* Devolvemos el color de fragmento calculado para almacenarlo en el framebuffer */
    gl_FragColor = totalColorLighting;
    //gl_FragColor = vec4(1.0);
}

vec4 computeLight(in MaterialParameters material, in LightSourceParameters lightSource, 
                in vec3 normal, in vec2 textCoord, in vec3 lightVector, in vec3 halfVector){

    float attenuation = 1.0; // no attenuation
    vec4 totalLightingColor = vec4(0.0); // no color

    if (length(lightSource.ambient) > 0.0){ // es luz ambiente
        totalLightingColor = vec4(lightSource.ambient, 1.0) * material.ambient;
    }
    else { // Is not ambiental light
        if (lightSource.position.w == 0.0) { // es un vector, por lo tanto es una luz direccional
            attenuation = 1.0; // no attenuation
        }
        else { // Is a point light or a spot light
            float distanceToLight = length(lightVector);
            attenuation = 1.0 / (lightSource.constantAttenuation + 
                                                (lightSource.linearAttenuation * distanceToLight) + 
                                                (lightSource.quadraticAttenuation * distanceToLight * distanceToLight));

        if (lightSource.spotCutoff <= 90.0){ /* Is a spot light */
                vec3 spotDirection = normalize(lightSource.spotDirection);
                float clampedCosine = max(0.0, dot(-lightVector, spotDirection));
                if (clampedCosine < cos(radians(lightSource.spotCutoff))){ /* outside the spotlight cone */
                    attenuation = 0.0; /* full attenuation */
                }
                else { /* inside the spotlight cone */
                    attenuation = attenuation * pow(clampedCosine, lightSource.spotExponent);
                }
            }
        }

        // Calculo de los terminos de color: diffuso y especular
        vec4 diffuseMaterialTerm = vec4(0.0, 0.0, 0.0, 1.0); /* El canal difuso será opaco y negro hasta que se sobreescriban sus datos */
        if (material.hasDiffuseTexture == 0) { /* El canal difuso no tiene textura */
            diffuseMaterialTerm =  material.diffuse;
        }
        else if (material.hasDiffuseTexture == 1){
            diffuseMaterialTerm = texture2D(material.diffuseTexture, textCoord);
        }
        vec4 diffuseReflection = attenuation * vec4(lightSource.lightColor, 1.0) * diffuseMaterialTerm * max(0.0, dot(normal, lightVector));

        vec4 specularReflection = vec4(0.0);
        if (dot(normal, lightVector) < 0.0 ) { // light source in the wrong side
            specularReflection = vec4(0.0);
        }
        else { // light source in the right side
            float NdotHV = max(dot(normal, halfVector), 0.0); /* Normal-dot-halfvector */
            vec4 specularMaterialTerm = vec4 (0.0, 0.0, 0.0, 1.0); /* El canal especular será opaco y negro hasta que se sobreescriban sus datos */
            if (material.hasSpecularTexture == 0){
                specularMaterialTerm = material.specular;
            }
            else if (material.hasSpecularTexture == 1){
                specularMaterialTerm = texture2D(material.specularTexture, textCoord);
            }
            specularReflection = attenuation * pow(NdotHV, material.shininess) * vec4(lightSource.lightColor, 1.0) * specularMaterialTerm;
        }

        totalLightingColor = diffuseReflection + specularReflection;

    }
    return totalLightingColor;

}

这是我用来上传这个制服的代码(Java)(numLights):

GLES20.glUseProgram(gl_Program.GetProgramID()); // GetProgramID() returns 3 in my case  

int numLights = iLightList.size(); // the scene I want to render has 1 light, so this value is 1

String numLightsString = "numLights";
int gl_numLights_Uniform_Locator = gl_Program.GetUniformLocation(numLightsString); // is 83 in my program

GLES20.glUniform1i(gl_numLights_Uniform_Locator, numLights);
int error = GLES20.glGetError(); // error is always 0

非常感谢任何帮助

编辑5:

我发现了一些很奇怪的东西。如果我在片段着色器中注释此代码,则使用正确的值加载统一的numLights:

 // vec4 emission = Material.emission;
 // if (length(emission) != 0.0) { /* El material tiene un termino emisivo, es decir, emite luz. Lo añadimos al total de color calculado */
 //     totalColorLighting = totalColorLighting + emission;
 // }

但如果我这样做,我就失去了发光部分的计算......有什么想法吗?

2 个答案:

答案 0 :(得分:1)

应该使用GLES20.glUniform1i,因为GLES20.glUniform1iv案例适用于uniform int numLights[1];。我确信您已经拥有,GLES20.glUniform1i应该在GLES20.glUseProgram之后并且在绘制任何内容之前。

83对于某个位置来说相当高,但并非不合理。我对android规范知之甚少,但它肯定可能耗尽统一的位置和内存。也许尝试简化着色器(使用较少的光线进行测试)或将制服放得更高。

[编辑] 为了继续这个想法,当涉及到循环和函数时,GLSL编译器可能真的不直观。当分支开始变得非常大时。您可能只是遇到一些奇怪的GLSL编译器错误。您可以尝试手动展开循环,在for循环条件中抛出indexComputeLights < MAX_LIGHTS && indexComputeLights < numLights会导致生成的条件嵌套(至少在我的nvidia卡上使用当前驱动程序)。也许用常量替换昂贵的computeLight调用仅用于测试。我遇到了生成的代码似乎太大的情况,我得到的结果无效而不是编译错误。

lowp会影响设置制服的能力吗?

获得所需结果的另一种方法(也可能更快)是为每个灯数编译着色器。这可以通过在源代码顶部注入#define NUM_LIGHTS x来轻松完成。

答案 1 :(得分:-1)

我面临同样的问题 - 即将 int uniform 传递给顶点着色器会导致不可预测的行为在某些硬件上:它在Android模拟器和我的Kindle Fire第二代平板电脑上工作得很好,但它在Galaxy S III上失败了(撞毁手机!)。 我发现手机崩溃了,因为在顶点着色器中,循环

for(int i=0; i<u_Sinks; i++)

u_Sinks int uniform ,似乎是无限的。但我将1传递给u_Sinks:

GLES20.glUniform1i( mSinksH  , 1);

当然我确实确保为mSinksH分配了有效值&gt; = 0:

mSinksH          = GLES20.glGetUniformLocation(mProgramH, "u_Sinks");    
Log.d("distorted", "mSinksH="+mSinksH);

并且日志打印出mSinksH = 4,这对我来说是正确的。

相关问题