스키닝 셰이더

jjuiddong
이동: 둘러보기, 찾기



  • 셰이더 스키닝 하면서 삽질 한 부분.
    • D3DFVF_TEX3 는 텍스쳐 좌표를 3개 쓰겠다는 뜻이다.
    • D3DFVF_TEX0 은 텍스쳐를 쓰지 않겠다는 뜻이다.
    • D3DFVF_TEXCOORDSIZE2(index) 는 멀티 텍스쳐를 쓸 때, 각 텍스쳐의 좌표 차원을 설정할 때 쓰이는 매크로다.
    • 버텍스 구조체는 해골책을 참조해서 만들었다.
	struct sVertexNormTexSkin
	{
		Vector3 p;
		Vector3 n;
		float u,v;
		float weights[4];
		float matrixIndices[4];

		enum {FVF = (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX3 |
			D3DFVF_TEXCOORDSIZE2(0)|		// texture
			D3DFVF_TEXCOORDSIZE4(1)|		// blend weight
			D3DFVF_TEXCOORDSIZE4(2)) };	// blend indices
	};
  • 계속
    • VertexDeclaration 은 설정할 필요가 없었다. SetFVF() 만으로 충분하다.
    • 매트릭스 팔레트는 flot4x3 으로 선언해서 POSITION 값과 곱할 때 여분의 w 값을 무시하도록 해야 한다.
    • application 에서 4x4 형태의 행렬을 저장해도 문제 없다.
    • 셰이더 코드는 아래와 같다.
// 팔레트
float4x3 mPalette[ 64];

// -------------------------------------------------------------
// 1패스:정점셰이더
// -------------------------------------------------------------
VS_OUTPUT VS_pass0(
	float4 Pos : POSITION,          // 모델정점
	float3 Normal : NORMAL,		// 법선벡터
	float2 Tex : TEXCOORD0,		// 텍스쳐 좌표
	float4 Weights : TEXCOORD1,	// 버텍스 가중치
	float4 BoneIndices : TEXCOORD2 // 본 인덱스 (4개 저장)
)
{
	VS_OUTPUT Out = (VS_OUTPUT)0; // 출력데이터
     
	// 좌표변환
	float4x4 mWVP = mul(mWorld, mVP);

	float3 p = {0,0,0};
	float3 n = {0,0,0};

	p += mul(Pos, mPalette[ BoneIndices.x]) * Weights.x;
	p += mul(Pos, mPalette[ BoneIndices.y]) * Weights.y;
	p += mul(Pos, mPalette[ BoneIndices.z]) * Weights.z;
	p += mul(Pos, mPalette[ BoneIndices.w]) * Weights.w;

	n += mul(Normal, mPalette[ BoneIndices.x]) * Weights.x;
	n += mul(Normal, mPalette[ BoneIndices.y]) * Weights.y;
	n += mul(Normal, mPalette[ BoneIndices.z]) * Weights.z;
	n += mul(Normal, mPalette[ BoneIndices.w]) * Weights.w;

	Out.Pos = mul( float4(p,1), mWVP );
	n = normalize(n);

	// 법선 벡터 계산.
	float3 N = normalize( mul(n, (float3x3)mWIT) ); // 월드 좌표계에서의 법선.
	
	Out.N = N;
	Out.Eye = vEyePos - Pos.xyz;
	Out.Tex = Tex;
    
     return Out;
}


//////////////////////////////////////////////////////////////////////////////////////

  • D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR 타입으로 fvf 를 설정하고 스키닝을 구현 할 수 있다.
  • 핵심은 매트릭스 팔레트를 float4x3 으로 하는게 핵심 이었다. 나머지는 그 동안 삽질한 코드와 동일 하다.
	struct sVertexNormTexSkin2
	{
		Vector3 p;
		float weights[4];
		DWORD matrixIndices;
		Vector3 n;
		float u,v;	

		enum {FVF = (D3DFVF_XYZB5 | D3DFVF_LASTBETA_D3DCOLOR | 
			D3DFVF_NORMAL | D3DFVF_TEX1)};
	};


  • 셰이더 코드는 아래와 같다.
// 팔레트
float4x3 mPalette[ 64];

// -------------------------------------------------------------
// 1패스:정점셰이더
// -------------------------------------------------------------
VS_OUTPUT VS_pass0(
	float4 Pos : POSITION,          // 모델정점
	float3 Normal : NORMAL,		// 법선벡터
	float2 Tex : TEXCOORD0,		// 텍스쳐 좌표
	float4 Weights : BLENDWEIGHT,	// 버텍스 가중치
	float4 BoneIndices : BLENDINDICES// 본 인덱스 (4개 저장)
)
{
	VS_OUTPUT Out = (VS_OUTPUT)0; // 출력데이터
    
	// 좌표변환
	float4x4 mWVP = mul(mWorld, mVP);

	// BoneIndices 는 0~1 사이 값으로 스케일링된 상태이기 때문에 
	// rgba *  255 를 해줘야 어플리케이션에서 저장한 BoneIndex를 
	// 얻어올 수 있다. D3DCOLORtoUBYTE4() 함수가 그 역할을 하게 된다.
	//
	// ARGB 형태로 어플리케이션 단에서 저장 한 값이 
	// D3DCOLORtoUBYTE4() 함수를 거치면서 BGRA 형태로 바뀐다.
	// 저장한 순서대로 Bone Index 를 접근하려면 wzyx 순으로 접근해야 한다.
	int4 IndexVector = D3DCOLORtoUBYTE4(BoneIndices);

	float3 p = {0,0,0};
	float3 n = {0,0,0};

	p += mul(Pos, mPalette[ IndexVector.w]) * Weights.x;
	p += mul(Pos, mPalette[ IndexVector.z]) * Weights.y;
	p += mul(Pos, mPalette[ IndexVector.y]) * Weights.z;
	p += mul(Pos, mPalette[ IndexVector.x]) * Weights.w;

	n += mul(Normal, mPalette[ IndexVector.w]) * Weights.x;
	n += mul(Normal, mPalette[ IndexVector.z]) * Weights.y;
	n += mul(Normal, mPalette[ IndexVector.y]) * Weights.z;
	n += mul(Normal, mPalette[ IndexVector.x]) * Weights.w;

	Out.Pos = mul( float4(p,1), mWVP );
	n = normalize(n);

	// 법선 벡터 계산.
	float3 N = normalize( mul(n, (float3x3)mWIT) ); // 월드 좌표계에서의 법선.
	
	Out.N = N;
	Out.Eye = vEyePos - Pos.xyz;
	Out.Tex = Tex;
    
    return Out;
}


  • D3DCOLORtoUBYTE4() 함수 때문에 코드가 좀더 복잡해졌다. 때문에 속도도 텍스쳐좌표로 스키닝할 때보다 느리다.
개인 도구
이름공간

변수
행위
둘러보기
도구모음