예제들에 나오는 환경맵에 대한 굴절은 실제 상황에서 적용하기 많이 힘들다.
다른 지오매트리들도 많은데 환경맵에 대해서만 굴절이 되니 적용할 만한 상황이 그렇게 많지가 않다.
굴절 유리가 필요해서 다른 많은 예제들(특히 pondwater)을 참고하여 만들었다.
'굴절' 이 주가 아니라 굴절을 하기 전 유리에 비친 상을 표현하는게 목적.
1. SetClipPlane 으로 클리핑 평면을 유리의 평면으로 변경시킴
2. RenderToSurface로 미리 만들어둔 텍스쳐의 Surface로 렌더 (텍스쳐는 D3DUSAGE_RENDERTARGET로)
3. 클리핑 평면을 되돌림
4. 생성된 텍스쳐를 셰이더에서 사용. 셰이더에서도 동차좌표계임을 고려해서 조작해야함
//=============== .fx =========================
uniform extern float4x4 matWVP;
uniform extern texture baseTex;
uniform extern texture glassTex;
sampler2D baseTexSmpler = sampler_state
{
Texture = <baseTex>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 8;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
sampler2D glassTexSmpler = sampler_state
{
Texture = <glassTex>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 8;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
//--------------[ vertex shader ]----------------
struct VS_INPUT {
float3 Pos : POSITION0;
float2 texcoord : TEXCOORD0;
};
struct VS_OUTPUT {
float4 Pos: POSITION0;
float4 ProjTexCoord : TEXCOORD0;
float2 texcoord: TEXCOORD1;
};
VS_OUTPUT glassEff_VtxShder_main(VS_INPUT In){
VS_OUTPUT Out;
Out.Pos = mul(float4(In.Pos, 1.0f), matWVP);
Out.ProjTexCoord = Out.Pos;
Out.texcoord = In.texcoord;
return Out;
}
//--------------[ pixel shader ]----------------
struct PS_INPUT{
float4 ProjTexCoord : TEXCOORD0;
float2 texcoord: TEXCOORD1;
};
float4 glassEff_PixShder_main(PS_INPUT In) : COLOR {
// cliping plane가 동차좌표계이므로 바꿔줘야함
In.ProjTexCoord.xy /= In.ProjTexCoord.w;
In.ProjTexCoord.x = 0.5f*In.ProjTexCoord.x + 0.5f;
In.ProjTexCoord.y = -0.5f*In.ProjTexCoord.y + 0.5f;
// 현실적인 굴절이 아님. 머리가 나빠 그럴싸 하게 정도로 만족ㅜ
// 이것마저도 텍스쳐 바깥을 가져오는 등 몇가지 문제가 있음
float vPerturbMod = -pow(In.ProjTexCoord.x, 10.0f) + 1.0f;
float2 distoVec = float2(-0.1f * sin(3.141592*2*In.ProjTexCoord.x), 0.0f);
distoVec.x *= vPerturbMod;
float4 color= tex2D(baseTexSmpler, In.ProjTexCoord.xy + distoVec);
// 유리에 비치는 빛에 의해 생기는 빗금 (▨) 을 텍스쳐로 넣고 블랜딩.
// 현실적으로 하려면 빛의 방향과 유리의 재질정보를 바탕으로 해야함.
float4 glassColor = tex2D(glassTexSmpler, In.texcoord.xy);
refraction = lerp(color, glassColor, 0.1f);
return color;
}
technique GlassEff
{
pass Object
{
ZENABLE = TRUE;
CULLMODE = CCW;
VertexShader = compile vs_2_0 glassEff_VtxShder_main();
PixelShader = compile ps_2_0 glassEff_PixShder_main();
}
}
IDirect3DTexture9* m_pTex;
ID3DXRenderToSurface* m_pRTS;
IDirect3DSurface9* m_pSuf;
D3DVIEWPORT9 m_vp;
// 표면은 2의 승수 크기로 만들어주는게 좋다.(무조건인진 잘 모르겠음..)
unsigned int rectSz = 512;
// 텍스쳐와 렌더투서피스 포멧, 사이즈 같아야함
D3DXCreateRenderToSurface(pDevice, rectSz, rectSz, D3DFMT_X8R8G8B8, true, D3DFMT_D24X8, &m_pRTS);
D3DXCreateTexture(pDevice, rectSz, rectSz, 0, D3DUSAGE_RENDERTARGET|D3DUSAGE_AUTOGENMIPMAP,
D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pTex);
m_pTex->GetSurfaceLevel(0, &m_pSuf);
m_vp.X = m_vp.Y = 0;
m_vp.Width = m_vp.Height = rectSz;
m_vp.MinZ = 0;
m_vp.MaxZ = 1;
pDevice->SetClipPlane(0, m_wallClipPlane);
pDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 1);
m_pRTS->BeginScene(m_pSuf, &m_vp);
// 여기서 오브젝트 드로우
m_pRTS->EndScene(D3DX_FILTER_NONE);
pDevice->SetClipPlane(0, m_wallClipPlane); //왜인지 모르겠지만 클리핑평면을 다시 셋 해줘야함(이유 아시는분..)
pDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
// 그 후 이펙트를 이용해서 m_pTex를 그리면 끝
볼록유리를 표현하려고 했었는데 그냥 휘어진 유리쯤으로 보인다.
스낼의 법칙을 아는것과 이걸 이용해서 굴절을 구현하는거랑은 차원이 다르다는걸 느꼈다.
처음 생각할때만 해도 텍스쳐 디스토네이션만 주면 되는거 아냐? 했었는데 ㅎㅎ,, 사흘은 고생한듯