2013-08-15 3 views
7

정상적인 매핑 문제가 있습니다. ASSIMP 라이브러리를 통해로드 된 각 모델에 텍스처와 일반 텍스처가 있습니다. 나는 ASSIMP 라이브러리의 도움으로 각 객체의 접선 벡터를 계산할 것이므로 이것들이 잘되어야한다. 객체는 일반 매핑을 사용하여 완벽하게 작동하지만 객체 중 하나를 번역하기 시작하면 (즉, 변형 된 모델 행렬에 영향을 미침) 조명이 실패합니다. 이미지에서 볼 수 있듯이 바닥 (y 축 아래로 이동)은 확산 조명의 대부분을 잃어버린 듯하며 반사 조명이 잘못된 방향입니다 (전구와 플레이어 위치 사이에 있어야합니다).정상적인 매핑과 변환으로 인해 조명이 깨집니다.

Normal mapping gone wrong

정상적인 매트릭스와 관련이있을 수 있지만 (번역은 손실되어야 함) 셰이더에 잘못된 매트릭스가 사용 된 것일 수 있습니다. 나는 아이디어가 부족하여 문제에 대한 통찰력을 얻을 수 있기를 바랍니다.

버텍스 쉐이더 :

#version 330 

layout(location = 0) in vec3 position; 
layout(location = 1) in vec3 normal; 
layout(location = 2) in vec3 tangent; 
layout(location = 3) in vec3 color; 
layout(location = 4) in vec2 texCoord; 

// fragment pass through 
out vec3 Position; 
out vec3 Normal; 
out vec3 Tangent; 
out vec3 Color; 
out vec2 TexCoord; 

out vec3 TangentSurface2Light; 
out vec3 TangentSurface2View; 

uniform vec3 lightPos; 
uniform vec3 playerPos; 

// vertex transformation 
uniform mat4 model; 
uniform mat4 view; 
uniform mat4 projection; 

void main() 
{ 
    mat3 normalMatrix = mat3(transpose(inverse(model))); 
    Position = vec3(model * vec4(position, 1.0)); 
    Normal = normalMatrix * normal; 
    Tangent = tangent; 
    Color = color; 
    TexCoord = texCoord; 

    gl_Position = projection * view * model * vec4(position, 1.0); 

    // Calculate tangent matrix and calculate fragment bump mapping coord space. 
    vec3 light = lightPos; 
    vec3 n = normalize(normalMatrix * normal); 
    vec3 t = normalize(normalMatrix * tangent); 
    vec3 b = cross(n, t); 
    // create matrix for tangent (from vertex to tangent-space) 
    mat3 mat = mat3(t.x, b.x ,n.x, t.y, b.y ,n.y, t.z, b.z ,n.z); 
    vec3 vector = normalize(light - Position); 
    TangentSurface2Light = mat * vector; 
    vector = normalize(playerPos - Position); 
    TangentSurface2View = mat * vector; 
} 

조각 쉐이더

#version 330 

in vec3 Position; 
in vec3 Normal; 
in vec3 Tangent; 
in vec3 Color; 
in vec2 TexCoord; 

in vec3 TangentSurface2Light; 
in vec3 TangentSurface2View; 

out vec4 outColor; 

uniform vec3 lightPos; 
uniform vec3 playerPos; 
uniform mat4 view; 
uniform sampler2D texture0; 
uniform sampler2D texture_normal; // normal 

uniform float repeatFactor = 1; 

void main() 
{ 
    vec4 texColor = texture(texture0, TexCoord * repeatFactor); 
    vec4 matColor = vec4(Color, 1.0); 
    vec3 light = vec3(vec4(lightPos, 1.0)); 
    float dist = length(light - Position); 
    // float att = 1.0/(1.0 + 0.01 * dist + 0.001 * dist * dist); 
    float att = 1.0; 
    // Ambient 
    vec4 ambient = vec4(0.2); 
    // Diffuse 
    // vec3 surface2light = normalize(light - Position); 
    vec3 surface2light = normalize(TangentSurface2Light); 
    // vec3 norm = normalize(Normal); 
    vec3 norm = normalize(texture(texture_normal, TexCoord * repeatFactor).xyz * 2.0 - 1.0); 
    float contribution = max(dot(norm, surface2light), 0.0); 
    vec4 diffuse = contribution * vec4(0.6); 
    // Specular 
    // vec3 surf2view = normalize(-Position); // Player is always at position 0 
    vec3 surf2view = normalize(TangentSurface2View); 
    vec3 reflection = reflect(-surface2light, norm); // reflection vector 
    float specContribution = pow(max(dot(surf2view, reflection), 0.0), 32); 
    vec4 specular = vec4(1.0) * specContribution; 

    outColor = (ambient + (diffuse * att)+ (specular * pow(att, 3))) * texColor; 
    // outColor = vec4(Color, 1.0) * texture(texture0, TexCoord); 
} 

편집

대신 세계와 카메라 공간 사이 pingponging의 세계 공간에서 모든 것을 (쉽게 계산하는 쉐이더 코드를 편집 이해하기 쉽고 오류가 발생하기 쉽지 않음).

+0

** 물어볼 곳이 잘못되었습니다. ** 극도로 행운이 없다면 아마 답을 얻지 못할 것입니다. http://gamedev.stackexchange.com 또는 http://www.gamedev.net에 문의하십시오. –

+0

@ TheOtherGuy : 제안에 감사드립니다.나는 거기에 게시하려고 시도 할 것입니다. 왜냐하면이 게임은 밀접하게 관련되어 있기 때문에 아마도 더 많은 행운을 가질 것입니다. –

+1

좋아, 행운을 빈다! –

답변

4

이상한 조작을 행렬로 만듭니다. VS에서는 inverse view-world로 normal (즉, model-space)을 변형합니다. 그건 말이 안되요. 세계 공간에서 계산하는 것이 더 쉬울 수도 있습니다. 작동하는 샘플 코드가 있지만 약간 다른 이름을 사용합니다.

정점 셰이더 : 다음은 투영 (화면)에 위치 - 공간 변환

void main_vs(in A2V input, out V2P output) 
{ 
    output.position = mul(input.position, _worldViewProjection); 
    output.normal = input.normal; 
    output.binormal = input.binormal; 
    output.tangent = input.tangent; 
    output.positionWorld = mul(input.position, _world); 
    output.tex = input.tex; 
} 

, TBN 모델이 공간에 남아, 그들은 나중에 사용될 것이다. 또한 조명 평가를위한 세계 공간의 위치를 ​​얻습니다.

픽셀 쉐이더 : 여기

void main_ps(in V2P input, out float4 output : SV_Target) 
{ 
    float3x3 tbn = float3x3(input.tangent, -input.binormal, input.normal); 

    //extract & decode normal: 
    float3 texNormal = _normalTexture.Sample(_normalSampler, input.tex).xyz * 2 - 1; 

    //now transform TBN-space texNormal to world space: 
    float3 normal = mul(texNormal, tbn); 
    normal = normalize(mul(normal, _world)); 

    float3 lightDirection = -_lightPosition.xyz;//directional 
    float3 viewDirection = normalize(input.positionWorld - _camera); 
    float3 reflectedLight = reflect(lightDirection, normal); 

    float diffuseIntensity = dot(normal, lightDirection); 
    float specularIntensity = max(0, dot(reflectedLight, viewDirection)*1.3); 

    output = ((_ambient + diffuseIntensity * _diffuse) * _texture.Sample(_sampler, input.tex) 
     + pow(specularIntensity, 7) * float4(1,1,1,1)) * _lightColor; 
} 

내가 직접 조명을 사용하여, 당신은 우리가 처음 질감에서 정상이 여기에

float3 lightDirection = normalize(input.positionWorld - _lightPosition.xyz);//omni 

같은 것을해야한다, 그 TBN 공간입니다. 그런 다음 TBN 행렬을 적용하여 모델 공간으로 변환합니다. 그리고 월드 공간으로 변환하는 월드 행렬을 적용, 우리는 이미 위의 ommitted 등

빛의 위치, 눈, 일부 다른 쉐이더 코드를 가지고 있었다 (DX11을하지만, 번역 쉽게) :

cbuffer ViewTranforms 
{ 
    row_major matrix _worldViewProjection; 
    row_major matrix _world; 
    float3 _camera; 
}; 

cbuffer BumpData 
{ 
    float4 _ambient; 
    float4 _diffuse; 
}; 

cbuffer Textures 
{ 
    texture2D _texture; 
    SamplerState _sampler; 

    texture2D _normalTexture; 
    SamplerState _normalSampler; 
}; 

cbuffer Light 
{ 
    float4 _lightPosition; 
    float4 _lightColor; 
}; 

//------------------------------------ 

struct A2V 
{ 
    float4 position : POSITION; 
    float3 normal : NORMAL; 
    float3 binormal : BINORMAL; 
    float3 tangent : TANGENT; 
    float2 tex : TEXCOORD; 
}; 

struct V2P 
{ 
    float4 position : SV_POSITION; 
    float3 normal : NORMAL; 
    float3 binormal : BINORMAL; 
    float3 tangent : TANGENT; 
    float3 positionWorld : NORMAL1; 
    float2 tex : TEXCOORD; 
}; 

또한, 여기 나는 precomputed binormal을 사용합니다 : 코드를 남겨두고 그것을 계산합니다 (교차점 (법선, 접선)을 통해). 희망이 도움이됩니다.

+0

일부 셰이더 코드를 게시 해 주셔서 감사합니다. 정상적인 매핑 계산의 차이점을 찾는 데 도움이 될 수 있습니다. 그러나 버텍스 쉐이더의 법선 벡터에 normalMatrix 계산을 볼 수 없습니다. AFAIK 당신은 정상적인 행렬 (번역 구성 요소없이 모델 (보기) 행렬의 tranpose - 역행렬)을 사용해야합니까, 아니면 제가 빠진 것이 있습니까? 현재 정상적인 행렬에 대해 Model AND view 구성 요소를 사용하고 있지만 모델 또는 모델 뷰 매트릭스가 아닌 경우 (modelviewmatrix는 변환하지 않을 때 좋은 결과를 제공하지만 모델은 그렇지 않음) 여전히 확실하지 않습니다. –

+0

내 의견이 너무 길어서 나눌거야. 당신은 왜 역 M (V) 행렬을 필요로하는지 이해합니까? 설명하려고했던 것은 다른 공간 (세계, 모델, TBN, 뷰 또는 심지어 화면)에서 계산을 수행 할 수 있다는 것입니다. 이렇게하려면 데이터를 변환해야하므로 모든 구성 요소 (눈, 빛의 방향, 정점 pos 등)가 동일한 공간에 있거나 쓰레기가 반환됩니다. – Celestis

+0

예 : 월드 공간에 빛이 있고 모델 공간에 정점과 법선이 있습니다. 확산 조명을 계산하려면 어떻게해야합니까? 모델 행렬에 따라 법선과 정점을 모두 곱합니다. 이렇게하면 법선과 정점이 모델에서 월드 공간으로 변환됩니다. 그래야만 점 (빛, 정상)을 그릴 수 있습니다. 역변환은 그것을 역으로 수행합니다. 역 모델 행렬에 의해 빛의 위치를 ​​곱함으로써, 세계에서 모델 공간으로 빛을 변환 할 수도 있습니다. 모든 값을 계산하기위한 공간이 다릅니다. – Celestis

관련 문제