A iluminação especular aparece nos lados voltados para os olhos e na parte traseira do objeto

StackOverflow https://stackoverflow.com//questions/20008089

Pergunta

Estou escrevendo um pequeno teste de sombreamento Phong e batendo a cabeça contra uma parede de tijolos tentando fazer o componente especular funcionar.Parece funcionar corretamente, exceto que a luz especular é aplicada tanto na parte frontal quanto na traseira do objeto.(O objeto em si é transparente, com faces classificadas manualmente no lado da CPU.)

Observe que o componente difuso funciona perfeitamente (aparece apenas no lado voltado para a fonte de luz) – o que parece descartar um problema com os normais que chegam ao sombreador de fragmento, eu acho.

Pelo que entendi, a componente especular é proporcional ao cos do ângulo entre o vetor olho e o vetor de luz refletida.

Para manter as coisas extremamente simples, meu código de teste tenta fazer isso no espaço mundial.A posição da câmera e o vetor de luz são codificados (desculpe) como (0,0,4) e (-0.707, 0, -0.707) respectivamente.O vetor olho é portanto (0,0,4) - fragPosition.

Como a matriz do modelo executa apenas rotação, o sombreador de vértice simplesmente transforma o vértice normal pela matriz do modelo.(Observação: esta não é uma boa prática, pois muitos tipos de transformação não preservam a ortogonalidade normal.Geralmente para a matriz normal, você deveria usar a transposição inversa do 3x3 superior esquerdo da matriz do modelo.) Para manter as coisas simples, o fragment shader opera em um único canal de cor flutuante e ignora o expoente especular (/usa um expoente de 1).

Sombreador de vértice:

#version 140

uniform mat4 mvpMtx;
uniform mat4 modelMtx;

in vec3 inVPos;
in vec3 inVNormal;

out vec3 normal_world;
out vec3 fragpos_world;

void main(void) {
  gl_Position = mvpMtx * vec4(inVPos, 1.0);
  normal_world = vec3(modelMtx * vec4(inVNormal, 0.0));
  fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0)); 
}

Sombreador de fragmento:

#version 140

uniform float
    uLightS,
    uLightD,
    uLightA;

uniform float uObjOpacity;

in vec3 normal_world, fragpos_world;
out vec4 fragOutColour;

void main(void) {

    vec3 vN = normalize(normal_world);
    vec3 vL = vec3(-0.707, 0, -0.707);

    // Diffuse:
    // refl in all directions is proportional to cos(angle between -light vector & normal)
    // i.e. proportional to -l.n
    float df = max(dot(-vL, vN), 0.0);

    // Specular:
    // refl toward eye is proportional to cos(angle between eye & reflected light vectors)
    // i.e. proportional to r.e
    vec3 vE = normalize(vec3(0, 0, 4) - fragpos_world);
    vec3 vR = reflect(vL, vN);
    float sf = max(dot(vR, vE), 0.0);

    float col = uLightA + df*uLightD + sf*uLightS;

    fragOutColour = vec4(col, col, col, uObjOpacity);

}

Não consigo encontrar um erro aqui;alguém pode explicar por que o componente especular aparece na parte traseira e também no lado voltado para a luz do objeto?

Muito obrigado.

Foi útil?

Solução

Sua contribuição especular será na verdade a mesma para as faces frontal e posterior porque o GLSL reflect é insensível ao sinal do normal.De esta referência:

reflect(I, N) = I - 2.0 * dot(N, I) * N

portanto, inverter o sinal de N introduz dois sinais de menos que se cancelam.Em palavras, o que reflect faz é inverter o sinal da componente de I que está no mesmo eixo que N.Isso não depende de qual caminho N está enfrentando.

Se você quiser remover o componente especular de suas faces traseiras, acho que você precisará verificar explicitamente sua dot(vE,vN).

Outras dicas

Tente mudar

fragpos_world = vec3(modelMtx * vec4(inVPos, 0.0)); 

para

fragpos_world = vec3(modelMtx * vec4(inVPos, 1.0)); 

porque http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/#Homogeneous_coordenadas

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top