Побочные шейдеры Earth Day/Night в OpneGL ES 2.0

У меня есть приложение для iPhone, которое моделирует планету Земля! Я хотел бы сделать его реалистичным: есть сферический объект, текстура и шейдер ночной и дневной сторон, но это не работает!

Метод рисования объекта My Sphere:

    -(bool)execute:(GLuint)texture;
 {    
    glBindTexture(GL_TEXTURE_2D, texture);
    glBindVertexArrayOES(m_VertexArrayName);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, m_NumVertices);
    glBindTexture(GL_TEXTURE_2D, 0);
    return true;
 }

Мой метод вызова ViewController:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

    glUseProgram(m_NightsideProgram);
    [m_Sphere setBlendMode:0];
    [m_Sphere execute:m_EarthNightTexture.name];

    glUseProgram(m_DaysideProgram);
    [m_Sphere setBlendMode:1];
    [m_Sphere execute:m_EarthDayTexture.name];

    glCullFace(GL_FRONT);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CW);

}

Режимы наложения: 0: glBlendFunc(GL_SRC_COLOR, GL_DST_COLOR); 1: glBlendFunc(GL_ONE, GL_CONSTANT_COLOR); // Константа имеет средне-синий цвет, чтобы сделать его немного светлее

Фрагментшейдер ночной стороны:

precision mediump float;

varying lowp vec4 colorVarying;
varying vec2 v_texCoord;

uniform sampler2D s_texture;


void main() {
    vec4 newColor;

    newColor=1.0-colorVarying;

    gl_FragColor = texture2D(s_texture, v_texCoord)*newColor;                    
}

Фрагментшейдер DaySide:

precision mediump float;

varying lowp vec4 colorVarying;
varying lowp vec4 specularColorVarying;
varying vec2 v_texCoord;

uniform sampler2D s_texture;


void main() {
    vec4 finalSpecular=vec4(0,0,0,1);
    vec4 surfaceColor;
    float halfBlue;

    surfaceColor=texture2D(s_texture,v_texCoord);

    halfBlue=0.5*surfaceColor[2];

    if(halfBlue>1.0)
        halfBlue=1.0;

    if((surfaceColor[0]<halfBlue) && (surfaceColor[1]<halfBlue))
        finalSpecular=specularColorVarying;

    gl_FragColor = surfaceColor*colorVarying+colorVarying*finalSpecular;                    
}

Если я использую только один из шейдеров, он выглядит хорошо, но вместе он работать не будет!


person Lajos Viktor    schedule 29.05.2012    source источник


Ответы (1)


Чтобы вызов glUniform... вступил в силу, должна быть действительная привязанная/используемая программа, и даже в этом случае он изменяет только значение юниформа для этой конкретной программы (обозначаемое расположением юниформа). Таким образом, вы должны вызывать свои функции glUniform... для каждой программы после соответствующей функции glUseProgram.

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

С другой стороны, юниформ-переменная сохраняет свое значение, даже когда соответствующая программа становится несвязанной (glUseProgram(0_or_any_other_program)).

person Christian Rau    schedule 29.05.2012