쉐이더 관련 데이터를 어떻게 관리해야 편할까 많이 고민 중입니다. 이것저것 많이 시도하고 있는 중인데, 현재 적용시킨 부분을 간단히 적어볼까 합니다. 대부분의 내용은 이전 포스트에 적었던 우버 쉐이더 관련 PT에서 많은 힌트를 얻어 구현 하였습니다.

데이터 포맷은 작업시 가독성과 편집이 용이한 XML을 이용하였습니다. 우버 쉐이더 작성을 위한 Define 리스트를 적습니다.
<Defines>
	<Define>_SHADER_USE_DIFFUSE_MAP_</Define>
	<Define>_SHADER_USE_NORMAL_MAP_</Define>
	<Define>_SHADER_USE_SKINNING_</Define>
</Defines>
위의 경우 DiffuseMap과 NormalMap, Skinning을 사용하는 쉐이더라는 것을 알 수 있습니다. DiffuseMap과 NormalMap을 사용하니 해당 텍스쳐 경로도 같이 넣어줍니다.
<Texture>
	<DiffuseMap0 FileName=".\Resource\Texture\cobblestonesDiffuse.tga"></DiffuseMap0>
	<NormalMap FileName=".\Resource\Texture\cobblestonesNormal.tga"></NormalMap>
</Texture>
그 다음 파라미터 값입니다. 쉐이더에는 많은 양의 파라미터 값을 지정해줘야합니다. 간단히 메시를 화면에 출력해주기 위해서는 월드행렬, 뷰행렬, 투영행렬이 필요하고, 텍스쳐를 입히기 위해서는 텍스쳐가 필요하고, 각종 효과를 주기위해서는 그 에따른 추가 파라미터 값들이 필요합니다. 그리고 이 파라미터 값을 지정해주기 위해서는 해당 파라미터의 핸들이 필요합니다.

한가지 염두하고 있는 것이 코드 수정의 최소화입니다. 쉐이더의 파라미터가 추가되거나 삭제가 되더라도 그 에 따른 코드 수정이 적어야 한다는거죠. 데이터 중심의 개발( Data-Driven Development )이 되어야 합니다. 쉐이더 변수명이나 Semantics를 이용하면 쉐이더 변수의 핸들을 얻어올수 있는데,  이것을 이용하여 쉐이더 파라미터를 맵핑합니다.
<Semantics>
	<Semantic Name="WORLD"/>
	<Semantic Name="WORLDVIEW"/>
	<Semantic Name="VIEWPROJECTION"/>
	<Semantic Name="AMBIENTCOLOR" ValueCount="4" Value1="255" Value2="255" Value3="255" Value4="255" />
	<Semantic Name="DIFFUSEMAP0"/>
	<Semantic Name="NORMALMAP"/>
</Semantics>
위의 경우 월드행렬, 월드뷰행렬, 뷰프로젝션행렬, 환경광등을 정의하는 부분입니다. 이것을 파싱하여, 해당 쉐이더 효과를 사용시 자동으로 파라미터 값을 설정하도록 합니다.
typedef void (ev_CEffectApply::*fpParameterFunction)( const stSemanticData& );
typedef stdext::hash_map< wstring, fpParameterFunction > EffectParameterFunc;
m_EffectParameterFunc_HashMap.insert( make_pair( L"WORLD", &ev_CEffectApply::ApplyWorldMatrix ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"WORLDVIEW", &ev_CEffectApply::ApplyWorldViewMatrix ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"VIEWPROJECTION", &ev_CEffectApply::ApplyViewProjMatrix ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"WORLDVIEWPROJECTION", &ev_CEffectApply::ApplyWorldViewProjMatrix ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"DIFFUSEMAP0", &ev_CEffectApply::ApplyDiffuseMap0 ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"DIFFUSEMAP1", &ev_CEffectApply::ApplyDiffuseMap1 ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"NORMALMAP", &ev_CEffectApply::ApplyNormalMap ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"SPECULARMAP", &ev_CEffectApply::ApplySpecularMap ) );
m_EffectParameterFunc_HashMap.insert( make_pair( L"AMBIENTCOLOR", &ev_CEffectApply::ApplyAmbientColor ) );

파라미터 설정하는 부분은 콜백 함수를 사용해보기로 했습니다. 쉐이더 파라미터를 할당 해주는 클래스를 하나 만들어 각 파라미터를 설정해주는 함수를 만듭니다. 그리고 각 함수를 Semantic을 키 값으로 하여, 콜백 함수로 정의합니다. 이렇게 해서 파싱된 Semantic 리스트를 통해 자동으로 파라미터 할당 함수가 호출 되도록 구현하였습니다.
// 파싱된 semantics 을 순차 실행
for each( stSemanticData semantic in semantics_vector )
{
	EffectParameterFuncIT it = m_EffectParameterFunc_HashMap.find( semantic.strSemantic );
	if( m_EffectParameterFunc_HashMap.end() != it )
	{
		// 콜백 함수 호출
		(this->*it->second)( semantic );
	}
}

아 이 캐 치



  1. BlogIcon ozlael 2011.05.24 12:50

    부왘~! 짤방 흥한당 ㅎ

  2. BlogIcon 구차니 2011.05.29 21:15 신고

    음....



    응?





    응!




    짤방과 대문사진만 기억에 남았어요!




    그런데 Xml은 어떤식으로 사용하세요?
    어떤식으로 파싱을 구성하고 어떤식의 트리로 구성을 하는지 궁금해요

    • BlogIcon 친절한티스 2011.05.31 14:56 신고

      생성/파싱은 직접 구현안하고 TinyXML 사용하고 있어욤. 트리는 딱히 정하지 않고, 그냥 필요한 값들만 키값하고 저장하는 식이예요.

+ Recent posts