1. 쉐이더 코드 작성(GrayScale.cg)
sampler RT : register(s0);
void calculateMaterialColorInDirectionalLight( float4 position : POSITION,
float4 normal : NORMAL,
float2 uv : TEXCOORD0,
out float4 oPosition : POSITION,
out float3 oNormal : COLOR,
out float2 oUv : TEXCOORD0,
uniform float4x4 worldViewProj,
uniform float4x4 world,
uniform float3 ambient,
uniform float diffusePower,
uniform float3 diffuse,
uniform float3 lightDirection,
uniform float3 lightColor
)
{
oPosition = mul(worldViewProj, position);
oUv = uv;
oNormal = (normalize(mul(world, normal))).xyz;
oNormal = diffuse * diffusePower * saturate(dot(oNormal, normalize(lightDirection)));
oNormal = lightColor * (ambient + oNormal);
}
void calculateGrayScaleInMaterialColor( float3 normal : COLOR,
float2 uv : TEXCOORD0,
out float4 oColor : COLOR,
uniform sampler2D RT : register(s0),
uniform float grayRatio
)
{
float3 tex_col = tex2D(RT, uv).rgb * normal;
float3 greyscale = tex_col * (1 - grayRatio) + dot(tex_col, float3(0.3, 0.59, 0.11)) * grayRatio;
oColor = float4(greyscale, 1.0);
}
- 출력 변수에는 out으로 선언한다.
- C 코드에서 입력할 데이터들은 uniform으로 선언한다.
2. 메터리얼 작성(GrayScale.material)
vertex_program ColorConvertor/GrayScale_vp cg
{
source GrayScale.cg
entry_point calculateMaterialColorInDirectionalLight
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
param_named_auto world world_matrix
param_named ambient float3 0.2 0.2 0.2
param_named diffusePower float 1.5
param_named diffuse float3 0.8 0.8 0.8
param_named lightDirection float3 0.0 2.0 2.0
param_named lightColor float3 1.0 1.0 1.0
}
}
fragment_program ColorConvertor/GrayScale_fp cg
{
source GrayScale.cg
entry_point calculateGrayScaleInMaterialColor
profiles ps_2_0 fp30
default_params
{
param_named grayRatio float 0.0
}
}
material ColorConvertor/GrayScale
{
technique
{
pass
{
vertex_program_ref ColorConvertor/GrayScale_vp
{
}
// alternate shadow caster program
fragment_program_ref ColorConvertor/GrayScale_fp
{
}
texture_unit RT
{
texture nskingr.jpg 2d
}
}
}
}
- vertex_program은 버텍스 쉐이더
- fragment_program은 픽셀 쉐이더
- source는 쉐이더 코드 파일명
- entry_point는 쉐이더 코드 함수명
- profiles는 컴파일할 쉐이더 버전
- param_named_auto는 3번째 값(위에서 worldviewproj_matrix, world_matrix)에 따라 ogre에서 매 프레임마다 알아서 갱신시켜주는 데이터
- param_named는 C 코드에서 설정을 해주어야 하는 데이터
- texture_unit은 텍스쳐 설정(위에서는 RT라는 이름으로 텍스쳐 설정, 쉐이더 코드의 RT에 매칭)
- 이름에 '/'가 들어간 것은 계층구조의 의미가 아님. 그냥 통채로 이름이다.
- 픽셀 쉐이더는 오히려 1.1 지원이 안되는 카드가 있음(
여기 참고).
3. 엔터티에 메터리얼 설정
Entity* head2 = mSceneMgr->createEntity("Head2", "ninja.mesh");
MaterialPtr material = (Ogre::MaterialPtr)Ogre::MaterialManager::getSingleton().getByName ("ColorConvertor/GrayScale");
head2->setMaterial(material);
Ogre::GpuProgramParametersSharedPtr filterParams = material->getTechnique(0)->getPass(0)->getVertexProgramParameters();
filterParams->setNamedConstant("ambient", Vector3(0.2f, 0.2f, 0.2f));
filterParams->setNamedConstant("diffusePower", 1.5f);
filterParams->setNamedConstant("diffuse", Vector3(0.8f, 0.8f, 0.8f));
filterParams->setNamedConstant("lightDirection", Vector3(0.0f, 2.0f, 2.0f));
filterParams->setNamedConstant("lightColor", Vector3(1.0f, 1.0f, 1.0f));
Ogre::GpuProgramParametersSharedPtr filterParams2 = material->getTechnique(0)->getPass(0)->getFragmentProgramParameters();
filterParams2->setNamedConstant("grayRatio", 0.0f);
- 쉐이더와 메터리얼 파일 경로를 resources_d.cfg에 포함시켜야 한다.
- 메터리얼에서 기본값을 설정해 놓았으면 코드에서 설정할 필요는 없다.
- 메터리얼의 상수값을 각 엔터티에 다르게 설정하고 싶으면 Ogre::Material::clone("새로운 메터리얼 이름") 함수를 사용해서 메터리얼을 복사해서 사용하면 된다. 복사된 메터리얼은 원본 메터리얼의 상수 설정값을 그대로 가지고 있다.