Skinning

첨 해보는 하드웨어 스키닝이라.. 개념정리가 좀 필요하네..

  • Requirements  에서 BonesPerPartition   = 20  으로 최대 Bone 개수를 제한한다. 현재 기본은 20개의 bone 처리

  • Stream은 역시 Vertex shader와 순서를 맞춰주자.
     PDP_BlendWeights 1 PDT_Float4 // 본의 웨이트값 
     PDP_BlendIndices 2 PDT_UByteColorw //256. 본의 인덱싱 넘버.
    를 추가해 주자.

-vertex shader에서 skinning을 사용하기 위해 nsf에다가,
Define 되어 있는 Bone의 Matrix를 정의해주자
CM_Defined      SkinBoneMatrix3     g_Bones     0    20

이렇게 설정이 끝났다면, 이번엔 hlsl로 넘어오자.

hlsl 에서 선언해줄 부분은 SKINBONEMATRIX3 이다.
float4x3 g_Bones[MAX_BONES]  : SKINBONEMATRIX3; 
으로 선언해준다. MAX_BONES은 상수로, 일단 20일 집어 넣는다.

vertex shader의 입력에서
 float4 vBlendWeights : BLENDWEIGHT;
 float4 vBlendIndices : BLENDINDICES;
두 개를 집어 넣는 것을 잊지 말자. 이전에 stream과 순서가 맞아야 한다는 것도 중요하다.
출력은… 별거 없다.
계산은 전부 vertex shader에서만 이루어지니까.

우선
int4 indices = D3DCOLORtoUBYTE4(In.vBlendIndices);// same as In.BlendIndices.bgra * 255.5;
로 indices를 만든다. 이것은 아까 받아온 bone의 index이다.

그다음 4개의 본을 각각 계산하기 시작하자.
첫 번째로는 weight값을 계산한다.
weight값은 다 합쳐서 1이 되어야 하기 때문에, 만약의 실수에 대비하는 것이 좋다.

  float weight4 = 1.0f - In.vBlendWeights[0] - In.vBlendWeights[1] - In.vBlendWeights[2];
들어온 3개의 weight값을 모두 1에서 빼주면, 남는 값이 weight4 라는 것이다. 굳이 4를 계산할 것 없이, 남은 것을 자동으로 입력해주어서 오차가 있더라도 대응할 수 있도록 해 준다.

그다음 float4로 재정렬 시킨다. 방금 구한 공식을 이용하여 4개로 연결하면 float4에 들어갈 것이기 때문이다.
 float4 weights = float4( In.vBlendWeights[0], In.vBlendWeights[1], In.vBlendWeights[2], weight4);

이렇게 weight 값을 구했으면, 이번엔 계산을 하자.
float4x3 mBoneTransform; 라는 행렬을 하나 가상으로 만들어 놓고,

각 본의 indices와 weight값을 곱한 것을 차례로 더하여 행렬을 만든다. 이 부분에 대해서는 설명을 좀 들어야 할듯.
mBoneTransform  = weights[0] * g_Bones[indices[0]];
    mBoneTransform += weights[1] * g_Bones[indices[1]];
    mBoneTransform += weights[2] * g_Bones[indices[2]];
    mBoneTransform += weights[3] * g_Bones[indices[3]];

이렇게 제작된 mBoneTransform 좌표계를
position 과 곱해주면 bone position이 나온다는 원리.
float3 vBoneSpacePos = mul(float4(In.vPosition, 1.0f), mBoneTransform);

normal도 당연히 이 좌표계에 곱해주면 끝난다.
꽤나 간단하지만 잘 안된다.

… 궁리중…

Hugo로 만듦
JimmyStack 테마 사용 중