폴리곤 수를 늘리지 않고도
디테일을 추가할 수 있는 법선 맵핑
-이론-
각 픽셀의 법선 정보를 담고있는 텍스쳐를 법선맵(normal map)이라고 한다.
법선
법선백터의 경우 -1~0~1 의 값을 가진다 하지만 텍스쳐는 0~1의 값을 갖는다 그때문에 법선벡터의 값을 수식으로 0~1을 가진것 처럼 만들어 준다. 그렇게 해주면 법선 벡터의 0이 텍스쳐에서는 0.5가 되게 만들어 준다.
법선맵 RGB = XYZ x 0.5 + 0.5 |
법선맵을 법선백터로 바꾸는 공식
법선벡터 XYZ = 법선맵 RGB x 2 - 1 |
법선공간
법선벡터는 각 표면을 기준으로 벡터의 방향이 결정된다
법선백터를 접선공간, 혹은 표면공간이라고 한다.
시멘틱
uv의 u나 v의 축을 접선이라고 부른다.
외적 계산으로 또 하나의 축을 구한다.이것을 종 법선이라고 한다.
법선맵,접선,종법선의 정보를 이미 모델이나 텍스쳐가 자지고있기 때문에 시멘틱을 사용하는 것만으로 이점보들을 구할 수 있다.
-HLSL함수-
TANGENT : 정점에서 접선정보를 불어올때 사용하는 시멘틱.
BINORMAL : 정점에서 종법선정보를 불러올때 사용하는 시멘틱.
transpos() : 전치 행렬을 구하는 HLSL함수.
-실습-
정점 셰이더
struct VS_INPUT{
float4 mPosition : POSITION;
float3 mNormal : NORMAL;
float2 mUV : TEXCOORD0;
float3 mTangent: TANGENT;
float3 mBinormal:BINORMAL;
};
//탄젠트와 바이노멀 시멘틱 구조체 선언
struct VS_OUTPUT{
float4 mPosition : POSITION;
float2 mUV: TEXCOORD0;
float3 mLightDir : TEXCOORD1;
float3 mViewDir: TEXCOORD2;
float3 T : TEXCOORD3;
float3 B : TEXCOORD4;
float3 N : TEXCOORD5;
};
float4x4 gWorldMatrix;
float4x4 gWorldViewProjectionMatrix;
float4 gWorldLightPosition;
float4 gWorldCameraPosition;
VS_OUTPUT vs_main (VS_INPUT Input){
VS_OUTPUT Output;
Output.mPosition = mul(Input.mPosition, gWorldMatrix);
Output.mUV = Input.mUV;
float4 worldPosition = mul(Input.mPosition, gWorldViewProjectionMatrix);
float3 lightDir = worldPosition.xyz - gWorldLightPosition.xyz;
Output.mLightDir = normalize(lightDir);
float3 viewDir = normalize(Output.mPosition.xyz - gWorldCameraPosition.xyz);
Output.mViewDir = viewDir;
float3 worldNormal = mul(Input.mNormal,(float3x3)gWorldMatrix);
Output.N = normalize(worldNormal);
//노멀 눨드 구하기
float3 worldTangent = mul(Input.mNormal, (float3x3)gWorldMatrix);
Output.T = normalize(worldTangent);
//탄젠트 월드 구하기
float3 worldBinormal = mul(Input.mBinormal, (float3x3)gWorldMatrix);
Output.B = normalize(worldBinormal);
//바이노멀 월드 구하기
return Output;
}
픽셀 셰이더
sampler2D DiffuseSampler;
sampler2D SpecularSampler;
sampler2D NormalSampler;
//노멀텍스쳐 샘플러
float3 gLightColor;
엠비언트 컬러
struct PS_INPUT{
float2 mUV : TEXCOORD0;
float3 mLightDIr : TEXCOORD1;
float3 mViewDir : TEXCOORD2;
float3 T : TEXCOORD3;
float3 B : TEXCOORD4;
float3 N : TEXCOORD5;
};
float4 ps_main(PS_INPUT Input):COLOR{
float3 tangentNormal = tex2D( NormalSampler, Input.mUV).xyz;
tangentNormal = normalize(tangentNormal * 2 - 1);
//탄젠트노멀을 0~1까지로 바꿔주는 수식
float3x3 TBN = float3x3(normalize(Input.T), normalize(Input.B),normalize(Input.N));
TBN = transpose(TBN);
//전치 행열
float3 worldNormal = mul(TBN, tangentNormal);
float3 lightDir = normalize(Input.mLightDIr);
float3 diffuse = saturate(dot(worldNormal, -lightDir));
float4 albedo = tex2D(DiffuseSampler, Input.mUV);
diffuse = gLightColor * albedo.rgb * diffuse;
float3 specular = 0;
if(diffuse.x>0){
float3 reflection = reflect(lightDir, worldNormal);
float3 viewDir = normalize(Input.mViewDir);
specular = saturate(dot(reflection, -viewDir));
specular = pow(specular, 20.0f);
float4 specularIntendity = tex2D(SpecularSampler, Input.mUV);
specular *= specularIntendity.rgb * gLightColor;
}
float3 ambient = float3(0.1f,0.1f,0.1f) * albedo;
return float4(ambient + diffuse * specular,1);
}
'Unity공부 > HLSL Shader 공부' 카테고리의 다른 글
셰이더 프로그래밍 입문-8 (0) | 2012.12.03 |
---|---|
셰이더 프로그래밍 입문-7 (0) | 2012.11.27 |
셰이더 프로그래밍 입문-5 (0) | 2012.11.19 |
셰이더 프로그래밍 입문-4 (0) | 2012.11.16 |
셰이더 프로그래밍 입문-3 (2) | 2012.11.14 |