12
20

<이 포스팅은 강좌가 아닙니다. 셰이더 프로그램 입문 책 구매해서 읽으세요>

UV 애니메이션

 

정점셰이더에서 시간에 따라 UV 좌표를 이용해 애니메이션을 줄 수 있다.

 

위 그림처럼 UV를 밀어서 강물이 흘러가는 듯한 효과를 줄 수 있는 것이다.

 

시간의 흐름에 따라 UV 값을 천천히 변경해야하는데, GPU를 사용하는 쉐이더에서는

 

시간을 구하는 함수가 없다 그래서 전역변수로 넘겨 받아야한다.

 

VS 구조체, 변수
mUV를 시간을 더해 Output로 보낸다.

mUV의 UV값이 1을 더하면 다시 자리로 돌아온다. 0.25f를 곱한건

 

너무 속도가 빨라서 속도를 조정한 것이다.

 

결과

 

UV를 이용해서 애니메이션을 주었다.

이를 이용해 마그마나 물의 텍스쳐가 움직이게 할 수 있다.

더보기
//vs
float4x4 gWorldMatrix;
float4x4 gWorldViewProjMatrix;

float4 gWorldLightPos;
float4 gWorldCamPos;
//time value
float gTime;

struct VS_INPUT 
{
   float4 mPosition : POSITION;
   float3 mNormal   : NORMAL;
   float3 mTangent  : TANGENT;
   float3 mBinormal : BINORMAL;
   float2 mUV       : TEXCOORD0;
};

struct VS_OUTPUT 
{
   float4 mPosition : POSITION;
   float2 mUV       : TEXCOORD0;
   float3 mLightDir : TEXCOORD1;
   float3 mViewDir  : TEXCOORD2;
   float3 mT        : TEXCOORD3;
   float3 mB        : TEXCOORD4;
   float3 mN        : TEXCOORD5;
};

VS_OUTPUT vs_main( VS_INPUT Input )
{
   VS_OUTPUT Output;
 
   Output.mPosition = mul( Input.mPosition, gWorldViewProjMatrix );
   //uv
   //Output.mUV = Input.mUV;
   Output.mUV = Input.mUV + float2(gTime*0.25f,gTime*0.25f);
   
   float4 worldPos = mul(Input.mPosition, gWorldMatrix);

   float3 lightDir = worldPos.xyz - gWorldLightPos.xyz;
   Output.mLightDir = normalize(lightDir);
   
   float3 viewDir = normalize(worldPos.xyz-gWorldCamPos.xyz);
   Output.mViewDir = viewDir;
   
   float3 worldNormal = mul(Input.mNormal, (float3x3)gWorldMatrix);
   Output.mN=normalize(worldNormal);
   
   float3 worldTangent = mul(Input.mTangent, (float3x3)gWorldMatrix);
   Output.mT=normalize(worldTangent);
   
   float3 worldBinormal = mul(Input.mBinormal, (float3x3)gWorldMatrix);
   Output.mB=normalize(worldBinormal);
  
   return  Output;
}

//ps
struct PS_INPUT
{
   float2 mUV : TEXCOORD0;
   float3 mLightDir : TEXCOORD1;
   float3 mViewDir : TEXCOORD2;
   float3 mT : TEXCOORD3;
   float3 mB : TEXCOORD4;
   float3 mN : TEXCOORD5;
};

sampler2D     DiffuseSampler;
sampler2D     SpecularSampler;
sampler2D     NormalSampler;
samplerCUBE   EnvironmentSampler;
float3        gLightColor;

float4 ps_main( PS_INPUT Input) : COLOR
{  
   float3 tangentNormal = tex2D(NormalSampler, Input.mUV).xyz;
   tangentNormal = normalize(tangentNormal*2-1);
   //tangentNormal = float3(0,0,1);
   float3x3 TBN = float3x3(normalize(Input.mT), normalize(Input.mB),normalize(Input.mN));
   TBN = transpose(TBN);
   float3 worldNormal = mul(TBN, tangentNormal); 

   float4 albedo = tex2D(DiffuseSampler, Input.mUV);
   float3 lightDir = normalize(Input.mLightDir);
   float3 diffuse = saturate(dot(worldNormal, -lightDir));
   diffuse = gLightColor * albedo.rgb*diffuse;
   
   float3 viewDir = normalize(Input.mViewDir);
   float3 specular = 0;
   
   if(diffuse.x > 0.0f)
   {
      float3 reflection = reflect(lightDir, worldNormal);
 
      specular = saturate(dot(reflection, -viewDir));
      specular = pow(specular,20.0f);
      
      float4 specularInten=tex2D(SpecularSampler, Input.mUV);
      specular*=specularInten.rgb*gLightColor;
   }
   float3 viewReflect = reflect(viewDir, worldNormal);
   float3 environment = texCUBE(EnvironmentSampler, viewReflect).rgb;
   float3 ambient = float3(0.1f, 0.1f, 0.1f)*albedo;
   
   return float4(ambient+diffuse+specular+(environment*0.5f),1);
}

 

울렁효과

 

코사인 그래프를 보면 연속적으로 +1~-1로  연속 곡선을 이룬다.

더해서 울렁효과는 Cos 함수를 이용해 출렁이게 하는 것이다.

 

 

위 프로젝트에서 이어서 변수를 더해준다. 

 

공간 변환하기전에 지역공간에서 mPosition 정점의 위치를 바꿔준다.

 

cos이 -1 ~ +1 으로 연속적인 곡선이기 때문에

 

위 아래로만 움직이는 것을 볼 수 있다. 

 

모든 정점을 한꺼번에 높여줬다 내려줬다만 반복하는거다.

 

정점 마다 높낮이를 달리 할라면 UV 좌표를 사용해야한다.

 

UV값은 표면에 따라 지속적으로 변하므로 UV좌표의 U좌표를 시간에 더한 것으로

 

코사인 값을 구하면 정점마다 코사인 함수에 들어가는 인자가 부드럽게 변한다.

 

결과

더보기
//vs
float4x4 gWorldMatrix;
float4x4 gWorldViewProjMatrix;

float4 gWorldLightPos;
float4 gWorldCamPos;
//time value
float gTime;
float gWaveHeight;
float gSpeed;
float gWaveFrequency;
float gUVSpeed;

struct VS_INPUT 
{
   float4 mPosition : POSITION;
   float3 mNormal   : NORMAL;
   float3 mTangent  : TANGENT;
   float3 mBinormal : BINORMAL;
   float2 mUV       : TEXCOORD0;
};

struct VS_OUTPUT 
{
   float4 mPosition : POSITION;
   float2 mUV       : TEXCOORD0;
   float3 mLightDir : TEXCOORD1;
   float3 mViewDir  : TEXCOORD2;
   float3 mT        : TEXCOORD3;
   float3 mB        : TEXCOORD4;
   float3 mN        : TEXCOORD5;
};

VS_OUTPUT vs_main( VS_INPUT Input )
{
   VS_OUTPUT Output;
   //지역공간에서 적용
   float cosTime = gWaveHeight * cos((gTime*gSpeed)+(Input.mUV.x*gWaveFrequency));
   Input.mPosition.y+=cosTime;
     
   Output.mPosition = mul( Input.mPosition, gWorldViewProjMatrix );
   float4 worldPos = mul(Input.mPosition, gWorldMatrix);
   float3 lightDir = worldPos.xyz - gWorldLightPos.xyz;
   Output.mLightDir = normalize(lightDir);
   
   float3 viewDir = normalize(worldPos.xyz-gWorldCamPos.xyz);
   Output.mViewDir = viewDir;
   
   float3 worldNormal = mul(Input.mNormal, (float3x3)gWorldMatrix);
   Output.mN=normalize(worldNormal);
   
   float3 worldTangent = mul(Input.mTangent, (float3x3)gWorldMatrix);
   Output.mT=normalize(worldTangent);
   
   float3 worldBinormal = mul(Input.mBinormal, (float3x3)gWorldMatrix);
   Output.mB=normalize(worldBinormal);
   
   Output.mUV = Input.mUV + float2(gTime*gUVSpeed,0);
   
   return  Output;
}

//ps
struct PS_INPUT
{
   float2 mUV : TEXCOORD0;
   float3 mLightDir : TEXCOORD1;
   float3 mViewDir : TEXCOORD2;
   float3 mT : TEXCOORD3;
   float3 mB : TEXCOORD4;
   float3 mN : TEXCOORD5;
};

sampler2D     DiffuseSampler;
sampler2D     SpecularSampler;
sampler2D     NormalSampler;
samplerCUBE   EnvironmentSampler;
float3        gLightColor;

float4 ps_main( PS_INPUT Input) : COLOR
{  
   float3 tangentNormal = tex2D(NormalSampler, Input.mUV).xyz;
   tangentNormal = normalize(tangentNormal*2-1);
   //tangentNormal = float3(0,0,1);
   float3x3 TBN = float3x3(normalize(Input.mT), normalize(Input.mB),normalize(Input.mN));
   TBN = transpose(TBN);
   float3 worldNormal = mul(TBN, tangentNormal); 

   float4 albedo = tex2D(DiffuseSampler, Input.mUV);
   float3 lightDir = normalize(Input.mLightDir);
   float3 diffuse = saturate(dot(worldNormal, -lightDir));
   diffuse = gLightColor * albedo.rgb*diffuse;
   
   float3 viewDir = normalize(Input.mViewDir);
   float3 specular = 0;
   
   if(diffuse.x > 0.0f)
   {
      float3 reflection = reflect(lightDir, worldNormal);
 
      specular = saturate(dot(reflection, -viewDir));
      specular = pow(specular,20.0f);
      
      float4 specularInten=tex2D(SpecularSampler, Input.mUV);
      specular*=specularInten.rgb*gLightColor;
   }
   float3 viewReflect = reflect(viewDir, worldNormal);
   float3 environment = texCUBE(EnvironmentSampler, viewReflect).rgb;
   float3 ambient = float3(0.1f, 0.1f, 0.1f)*albedo;
   
   return float4(ambient+diffuse+specular+(environment*0.5f),1);
}
COMMENT