GPU Gems 1

Chapter 4. Animation in the "Dawn" Demo

공대나온남자 2009. 2. 5. 02:20

원문: http://http.developer.nvidia.com/GPUGems/gpugems_ch04.html

Chapter 4. Animation in the "Dawn" Demo

Curtis Beeson
NVIDIA

4.1 Introduction

"Dawn" is a demonstration that was created by NVIDIA Corporation to introduce the GeForce FX product line and illustrate how a high-level language (such as HLSL or Cg) could be used to create a realistic human character. The vertex shaders deform a high-resolution mesh through indexed skinning and morph targets, and they provide setup for the lighting model used in the fragment shaders. The skin and wing fragment shaders offer both range and detail that could not have been achieved before the introduction of advanced programmable graphics hardware. See Figure 4-1.

 

“Dawn”은 GeForce FX 제품군을 소개하고 고차원 언어(HLSL이나 Cg같은)가 실제 같은 인간 캐릭터를 만드는데 어떻게 사용될 수 있는지 설명하기 위해 NVIDIA사에서 제작한 데모이다. 정점 쉐이더는 색인된 스키닝과 모프 타겟을 통해 고해상도 메쉬를 변형하고 단편 쉐이더에서 사용된 조명 모델을 위한 설정을 제공한다. 피부와 날개 단편 쉐이더는 진보된 프로그래밍 가능한 그래픽 하드웨어가 소개되기 전에는 이루어질 수 없었던 범위와 세밀함을 둘 다 제공한다. 그림 4-1을 보라.

 

fig04-01.jpg

Figure 4-1 A Screen Capture of the Real-Time Dawn

 

This chapter discusses how programmable graphics hardware was used to accelerate the animation of the Dawn character in the demo.

 

이 챕터에서는 데모에 있는 Dawn 캐릭터의 애니메이션을 가속화하기 위해서 프로그래밍 가능한 그래픽 하드웨어가 어떻게 사용되는지를 논의한다.

 

4.2 Mesh Animation

Traditionally, mesh animation has been prohibitively expensive for complex meshes because it was performed on the CPU, which was already burdened with physical simulation, artificial intelligence, and other computations required by today's applications. Newer graphics hardware has replaced the traditional fixed-function pipeline with programmable vertex and fragment shaders, and it can now alleviate some of that burden from the CPU.

 

이전부터, 메쉬 애니메이션은 복잡한 메쉬일 경우 매우 값비싼 작업이었다. 이미 물리 시뮬레이션, 인공지능, 오늘날의 어플리케이션에서 필요한 다른 계산의 부담을 안고 있는 CPU에서 수행되었기 때문이다. 최신 그래픽 하드웨어는 전통적인 고정-함수 파이프라인을 프로그래밍 가능한 정점, 단편 쉐이더로 대체하고 있고, CPU의 부담을 일부 덜 수 있다.

 

Sometimes it is still necessary to perform such operations on the CPU. Many stencil-based shadow volume techniques must traverse the transformed mesh in order to find the silhouette edges, and the generation of the dynamic shadow frustum is often best done on the CPU (see Chapter 9, "Efficient Shadow Volume Rendering"). In scenes where the character is drawn multiple times per frame into shadow buffers, glow buffers, and other such temporary surfaces, it may be better to perform the deformations on the CPU if the application becomes vertex-limited. Deciding whether to perform mesh deformations on the CPU or on the GPU should be done on a per-application or even on a per-object basis.

 

때때로 CPU에서의 연산이 여전히 필요하다. 많은 스텐실 기반 그림자 볼륨 기법은 실루엣 모서리를 찾기 위해 변형된 메쉬를 다루어야하고, 동적 그림자 절두체의 생성은 종종 CPU에서 가장 잘 수행된다(챕터9, "Efficient Shadow Volume Rendering" 을 보라). 캐릭터가 그림자 버퍼, 백열 버퍼, 다른 임시 표면에 매 프레임마다 여러 번 그려지는 장면에서는, 어플리케이션이 정점에 제한적이면 CPU에서 변형을 수행하는게 더 나을 수도 있다. 메쉬 변형을 CPU에서 수행할지 GPU에서 수행할지는 어플리케이션에 따라 혹은 개별 물체에 따라 결정되어야 한다.

 

The modeling, texturing, and animation of the Dawn character were done primarily in Alias Systems' Maya package. We therefore based our mesh animation methods on the tool set the software provides. We have since created a similar demo ("Dusk," used to launch the GeForce FX 5900) in discreet's 3ds max package, using the same techniques; these methods are common to a variety of modeling packages and not tied to any single workflow. The methods used in these two demos are (indexed) skinning, where vertices are influenced by a weighted array of matrices, and weighted morph targets, used to drive the emotions on Dawn's face.

 

Dawn 캐릭터의 모델링, 텍스쳐링, 애니메이션은 Alias Systems의 Maya 패키지로 주로 작업했다. 그러므로 우리는 메쉬 애니메이션 방식을 소프트웨어가 제공하는 도구를 기반으로 하였다. 우리는 이전에 같은 기법을 사용하여 discreet사의 3ds max 패키지에서 비슷한 데모(GeForce FX 5900 출시에 사용된 “Dusk”)를 제작했었다. 이 방식들은 여러 모델링 패키지에 일반적인 것이고 어떤 하나의 작업흐름에만 제한되지 않는다. 이 두 데모에서는 정점이 행렬의 가중된 배열에 영향을 받는 (색인된) 스키닝과 Dawn의 얼굴에 감정을 나타내는데 사용된 가중된 모프 타겟 방식이 사용되었다.

 

4.3 Morph Targets

Using morph targets is a common way to represent complex mesh deformation, and the NVIDIA demo team has created a variety of demos using this technique. The "Zoltar" demo and the "Yeah! The Movie" demo (content provided by Spellcraft Studio) started with 30 mesh interpolants per second, then removed mesh keys based on an accumulated error scheme. This allowed us to reduce the file size and the memory footprint?up to two-thirds of the original keys could be removed with little to no visible artifacts. In this type of mesh interpolation, there are only two interpolants active at any given time, and they are animated sequentially.

 

모프 타겟을 사용하는 것은 복잡한 메쉬 변형을 나타내는 일반적인 방식이다. NVIDIA 데모 팁은 이 기법을 사용하여 여러가지의 데모를 제작해왔다. “Zoltar” 데모와 “Yeah! The Movie” 데모(Spellcraft Studio에서 제공한 컨텐츠)는 초당 30개의 메쉬를 보간하여 누적된 오류 체계를 기반으로 메쉬 키를 제거하였다. 이로 인해 우리는 파일 크기와 메모리 공간을 줄일 수 있었다 —눈에 보이는 결함이 거의 없이 원래의 키 중 2/3 이상이 제거될 수 있었다. 이런 종류의 메쉬 보간에서, 어떤 주어진 시간에서든 2개의 보간만이 활성화되고, 순차적으로 애니메이션된다.

 

Alternatively, morph targets can be used in parallel. Dawn is a standard example of how this approach can be useful. Beginning with a neutral head (27,000 triangles), our artist created 50 copies of that head and modeled them into an array of morph targets, as shown in Figure 4-2. Approximately 30 of those heads corresponded to emotions (such as happy, sad, thoughtful, and so on), and 20 more were modifiers (such as left eyebrow up, right eyebrow up, smirk, and so on). In this style of animation, the morph target weights will probably not add to 1, because you may have (0.8 * happy + 1.0 * ear_wiggle), for example?Dawn is a fairy, after all.

 

또는, 모프 타겟은 병렬로 사용될 수 있다. Dawn은 이런 접근법이 어떻게 유용할 수 있는지를 보여주는 기본적인 예제이다. 기본 머리(27,000개의 삼각형)로 시작해서, 우리의 아티스트들은 그 머리를 50개를 복사해서 그림 4-2처럼 모프 타겟의 배열에 그것들을 모델링했다. 그들 중 대략 30개가 감정(기쁨, 슬픔, 사색 같은)을 나타내는 것이었고, 20개 이상은 수정자(왼쪽 눈썹이 올라간 것, 오른쪽 눈썹이 올라간 것, 히죽히죽 웃는 것 등등)였다. 모프 타겟 가중치는 아마 합이 1이 되지 않을 것이다. 예를 들어, (0.8 * happy + 1.0 * ear_wiggle) 처럼 할 수도 있기 때문이다. 어쨌든, Dawn은 요정이다.

 

 

Figure 4-2 Emotional Blend Targets (Blend Shapes)

 

Although such complex emotional faces could have been made entirely of blends of more elemental modifiers, our artist found it more intuitive to model the face in the pose he desired, because it is hard to model an element such as an eyebrow creasing, without seeing how the eyes, cheeks, and mouth work together. This combination also helps with hardware register limitations, described later.

 

비록 감정을 나타내는 복잡한 얼굴을 전적으로 더 많은 성분의 수정자를 혼합하여 만들 수 있을지라도, 우리의 아티스트들은 원하는 포즈로 얼굴을 모델링하는 것이 더 직관적이라는 것을 발견했다. 왜냐하면 눈, 뺨, 입이 어떻게 함께 움직이는지 신경쓰지 않고 눈썹을 움직이는 것 같은 성분을 모델링하는 것은 어렵기 때문이다. 이 조합은 또한 하드웨어 레지스터 제한에 도움을 준다. 이것은 후에 설명할 것이다.

 

4.3.1 Morph Targets in a High-Level Language

Luckily, the implementation of morph targets in HLSL or Cg is simple. Assuming that vertexIn is our structure containing per-vertex data, applying morph targets in a linear or serial fashion is easy:

 

다행히, HLSL이나 Cg에서 모프 타겟을 구현하는 것은 간단하다. 정점당 데이터를 가지고 있는 구조체를 vertexIn 라고 하면, 선형 혹은 직렬 방식에 모프 타겟을 적용하는 것은 쉽다.

 

float4 position = (1.0f - interp) * vertexIn.prevPositionKey +
                    interp * vertexIn.nextPositionKey;

 

In this code, interp is a constant input parameter in the shader, but prevPositionKey and nextPositionKey are the positions at the prior time and next time, respectively. When applying morph targets in parallel, we find the spatial difference between the morph target and the neutral pose, which results in a difference vector. We then weight that difference vector by a scalar. The result is that a weight of 1.0 will apply the per-vertex offsets to achieve that morph target, but each morph target can be applied separately. The application of each morph target is just a single "multiply-add" instruction:

 

이 코드에서 interp 쉐이더에서 상수 입력 매개변수이지만, prevPositionKey와 nextPositionKey는 각각 이전 시간과 다음 시간에서의 위치이다. 병렬로 모프 타겟을 작용할 때, 우리는 모프 타겟과 기본 포즈 사이의 공간적 차이로 인해 차이 벡터가 발생하는 것을 발견했다. 그래서 우리는 차이 벡터에 스칼라값으로 가중치를 준다. 그 결과 1.0의 가중치는 그 모프 타겟을 이루기 위해 정점당 오프셋을 적용할 것이다. 하지만 각 모프 타겟은 따로따로 적용될 수 있다.

 

// vertexIn.positionDiffN = position morph target N - neutralPosition
   float4 position = neutralPosition;
position += weight0 * vertexIn.positionDiff0;
position += weight1 * vertexIn.positionDiff1;
position += weight2 * vertexIn.positionDiff2;
. . .
 

4.3.2 Morph Target Implementation

We wanted our morph targets to influence both the vertex position and the basis (that is, the normal, binormal, and tangent) so that they might influence the lighting performed in the fragment shader. At first it would seem that one would just execute the previous lines for position, normal, binormal, and tangent, but it is easy to run out of vertex input registers. When we wrote the "Dawn" and "Dusk" demos, the GPU could map a maximum of 16 per-vertex input attributes. The mesh must begin with the neutral position, normal, binormal, texture coordinate, bone weights, and bone indices (described later), leaving 10 inputs open for morph targets. We might have mapped the tangent as well, but we opted to take the cross product of the normal and binormal in order to save one extra input.

 

우리는 우리의 모프 타겟이 정점의 위치와 주성분(즉, 법선, 종법선, 탄젠트) 모두에게 영향을 주어 단편 쉐이더에서 수행되는 조명에 영향을 줄 수 있길 바랬다. 처음엔 위치, 법선, 종법선, 탄젠트마다 단지 위의 라인을 실행하면 될 것으로 보일 것이다. 하지만 정점 입력 레지스터가 부족하기 쉽다. 우리가 “Dawn”과 “Dusk” 데모를 만들고 있을 때, GPU는 정점당 최대 16개의 입력 속성을 맵핑할 수 있었다. 메쉬는 기본 위치, 법선, 종법선, 텍스쳐 좌표, 뼈대 가중치, 뼈대 인덱스(후에 설명한다) 정보를 가지고 있기 때문에 10개의 입력을 모프 타겟을 위해 사용할 수 있다. 탄젠트도 입력에 넣을 수도 있지만, 하나의 입력을 아끼기 위해 법선과 종법선을 외적하여 탄젠트를 구하기로 했다.

 

Because each difference vector takes one input, we might have 10 blend shapes that influence position, five blend shapes that influence position and normal, three position-normal-binormal blend shapes, or two position-normal-binormal-tangent blend shapes. We ultimately chose to have our vertex shader apply five blend shapes that modified the position and normal. The vertex shader would then orthonormalize the neutral tangent against the new normal (that is, subtract the collinear elements of the new normal from the neutral tangent and then normalize) and take the cross product for the binormal. Orthonormalization is a reasonable approximation for meshes that do not twist around the surface normal:

 

각 차이 벡터는 하나의 입력을 사용하기 때문에, 위치에 영향을 주는 10개의 형태를 혼합하거나, 위치와 법선에 영향을 주는 5개의 형태를 혼합하거나, 3개의 위치-법선-종법선 형태를 혼합하거나, 2개의 위치-법선-종법선-탄젠트 형태를 혼합할 수 있다. 우리는 최종적으로 위치와 법선을 변경하는 5개의 형태를 혼합하는 정점 쉐이더를 만들기로 했다. 정점 쉐이더는 기본 탄젠트를 새로운 법선에 대해 수직정규화하고(즉, 기본 탄젠트에서 새 법선과 동일 선상의 벡터를 뺀 다음 정규화) 종법선을 구하기 위해 외적 한다. 수직정규화는 표면 법선이 꼬이지 않은 메쉬를 위한 알맞은 근사이다.

 

// assumes normal is the post-morph-target result
   // normalize only needed if not performed in fragment shader
   float3 tangent = vertexIn.neutralTangent - dot(vertexIn.neutralTangent,
                                               normal) * normal;
tangent = normalize(tangent);

Thus, we had a data set with 50 morph targets, but only five could be active (that is, with weight greater than 0) at any given time. We did not wish to burden the CPU with copying data into the mesh every time a different blend shape became active, so we allocated a mesh with vertex channels for neutralPosition, neutralNormal, neutralBinormal, textureCoord, and 50 * (positionDiff, NormalDiff). on a per-frame basis, we merely changed the names of the vertex input attributes so that those that should be active became the valid inputs and those that were inactive were ignored. For each frame, we would find those five position and normal pairs and map those into the vertex shader, allowing all other vertex data to go unused.

 

그러므로, 우리는 50개의 모프 타겟으로된 데이터 세트가 있었지만, 어떤 주어진 시간에서든 5개만이 활성화될 수 있었다(즉, 가중치가 0보다 큰 것만). 우리는 다른 형태가 혼합될 때마다 메쉬에 데이터를 복사하여 CPU에 부담을 주길 원하지 않았다. 그래서 우리는 neutralPosition, neutralNormal, neutralBinormal, textureCoord, 50 * (positionDiff, NormalDiff)에 대한 정점 채널이 있는 메쉬를 할당했다. 매 프레임마다, 우리는 단지 정점 입력 속성의 이름을 바꾸기만 했다. 그로 인해 활성화되어야 하는 것은 유효한 입력이 되고 비활성화되어야 하는 것은 무시된다. 매 프레임에 따라, 5개의 위치, 법선 쌍을 찾아서 정점 쉐이더에 맵핑했다. 따라서 다른 모든 정점 데이터를 사용되지 않는다.

 

Note that the .w components of the positionDiff and normalDiff were not really storing any useful interpolants. We took advantage of this fact and stored a scalar self-occlusion term in the .w of the neutralNormal and the occlusion difference in each of the normal targets. When extracting the resulting normal, we just used the .xyz modifier to the register, which allowed us to compute a dynamic occlusion term that changed based on whether Dawn's eyes and mouth were open or closed, without any additional instructions. This provided for a soft shadow used in the lighting of her skin (as described in detail in Chapter 3, "Skin in the 'Dawn' Demo").

 

positionDiff 와 normalDiff 의 .w 성분은 어떠한 유용한 값도 가지고 있지 않다는 것을 주목하라. 우리는 이 점을 이용해서 neutralNormal의 .w 에 스칼라 자기-폐색 항을 저장하고 각 법선 타겟에 폐색 차이를 저장했다. 결과 법선을 이끌어낼 때는, 단지 레지스터에 .xyz 수정자를 사용하기만 하면 되기 때문에 어떠한 추가적인 명령어 없이 Dawn의 눈과 입이 열렸는지 닫혔는지에 따라 변하는 동적 폐색항을 계산할 수 있었다. 이것은 피부의 조명에 사용된 부드러운 그림자를 위해 제공되었다(자세한 것은 챕터3, “Skin in the 'Dawn' Demo”에 설명되어 있다).

 

On the content-creation side, our animator had no difficulty remaining within the limit of five active blend shapes, because he primarily animated between three or so emotional faces and then added the elemental modifiers for complexity. We separated the head mesh from the rest of the body mesh because we did not want the added work of doing the math or storing the zero difference that, say, the happy face would apply to Dawn's elbow. The result remained seamless?despite the fact that the head was doing morph targets and skinning while the body was doing just skinning?because the outermost vertices of the face mesh were untouched by any of the emotional blend shapes. They were still modified by the skinning described next, but the weights were identical to the matching vertices in the body mesh. This ensured that no visible artifact resulted.

 

컨텐츠 제작 측면에서, 우리의 애니메이터들은 5개의 활성화된 형태를 혼합하는 제한으로 인한 어려움을 겪지 않았다. 왜냐하면 그는 주로 3개 정도의 감정이 있는 얼굴을 애니메이션해서 복잡성을 위해 성분의 수정자를 추가했다. 우리는 머리 메쉬를 몸체 메쉬에서 분리시켰다. 행복한 표정의 얼굴이 Dawn의 팔꿈치에 적용되는 것과 같이 차이가 없는 것을 계산하거나 저장하느라 추가적인 작업이 발생하는 것을 원하지 않았기 때문이다. 몸체가 스키닝만 되는 반면 얼굴은 모프 타겟과 스키닝이 되고 있었음에도 불구하고 결과는 결함이 남아있다. 얼굴 메쉬의 가장 바깥 정점은 어떠한 감정이 있는 형태의 혼합이든 건드려지지 않기 때문이다. 그것들은 다음에 설명된 스키닝에 의해 수정되긴 하지만 가중치가 몸 메쉬에 알맞은 정점과 동일했다. 이로 인해 눈에 보이지 않는 결함이 나타날 것이 확실했다.

 

4.4 Skinning

Skinning is a method of mesh deformation in which each vertex of that mesh is assigned an array of matrices that act upon it along with weights (that should add up to 1.0) that describe how bound to that matrix the vertex should be. For example, vertices on the bicep may be acted upon only by the shoulder joint, but a vertex on the elbow may be 50 percent shoulder joint and 50 percent elbow joint, becoming 100 percent elbow joint for vertices beyond the curve of the elbow.

 

스키닝은 정점이 행렬에 얼마나 영향을 받는지를 나타내는 가중치값(합이 1.0이 되는)에 따라 작용하는 행렬의 배열을 각 정점에 지정하는 메쉬 변형의 한 방식이다. 예를 들면, 이두근에 있는 정점은 어깨 관절에 의해서만 작동할 것이다. 하지만 팔꿈치에 있는 정점은 어깨 관절이 50%, 팔꿈치 관절이 50%가 될 것이고, 팔꿈치 굴곡 너머에 있는 정점은 팔꿈치 관절이 100%가 될 것이다.

 

Preparing a mesh for skinning usually involves creating a neutral state for the mesh, called a bind pose. This pose keeps the arms and legs somewhat separated and avoids creases as much as possible, as shown in Figure 4-3. First, we create a transform hierarchy that matches this mesh, and then we assign matrix influences based on distance?usually with the help of animation tools, which can do this reasonably well. Almost always, the result must be massaged to handle problems around shoulders, elbows, hips, and the like. This skeleton can then be animated through a variety of techniques. We used a combination of key-frame animation, inverse kinematics, and motion capture, as supported in our content-creation tool.

 

스키닝을 위한 메쉬를 준비하는 것은 보통 바인드 포즈라고 불리는 중립 상태의 메쉬를 생성하는 것을 포함한다. 이 포즈는 그림 4-3과 같이 팔과 다리를 약간 벌리고 가능한한 구부리는 것을 피한다. 우선, 우리는 이 메쉬에 맞는 변환 계층을 생성한 다음, 거리에 기반하여 행렬 영향을 지정한다. 보통 이것을 제대로 잘 수행할 수 있는 애니메이션 툴을 사용한다. 거의 항상 어깨, 팔꿈치, 엉덩이 같은 곳 주위의 문제점을 다루기 위해 결과물을 조작해야 한다. 그런 후에, 여러 기법을 통해 이 뼈대를 애니메이션할 수 있다. 우리는 우리의 컨텐츠-생성 툴에서 제공하는 키프레임 애니메이션, 역기구학, 모션 캡쳐를 조합하여 사용했다.

 

fig04-03.jpg

Figure 4-3 Dawn's Bind Pose

 

A skinned vertex is the weighted summation of that vertex being put through its active joints, or:

 

스키닝된 정점은 활성화된 관절에 연결된 정점의 가중된 합이다.

 

ch04_eqn001.jpg

 

Conceptually, this equation takes the vertex from its neutral position into a weighted model space and back into world space for each matrix and then blends the results. The concatenated ch04_eqn002.jpg matrices are stored as constant parameters, and the matrix indices and weights are passed as vertex properties. The application of four-bone skinning looks like this:

 

개념적으로, 이 방정식은 정점을 중립 위치에서 가중된 모델 공간으로 변환하고 각 행렬에 대해 다시 월드 공간으로 변환한 다음 결과를 혼합한다. 연결된  ch04_eqn002.jpg 행렬은 상수 매개변수로 저장되고, 행렬 인덱스와 가중치는 정점 속성으로 전달된다. 4-뼈 스키닝은 다음과 같다.

 

float4 skin(float4x4 bones[98],
            float4   boneWeights0,
            float4   boneIndices0)
{
  float4 result = boneWeights0.x * mul(bones[boneIndices.x], position);
  result = result + boneWeights0.y * mul(bones[boneIndices.y],
                                         position);
  result = result + boneWeights0.z * mul(bones[boneIndices.z],
                                         position);
  result = result + boneWeights0.w * mul(bones[boneIndices.w],
                                         position);
  return result;
}

In the "Dawn" demo, we drive a mesh of more than 180,000 triangles with a skeleton of 98 bones. We found that four matrices per vertex was more than enough to drive the body and head, so each vertex had to have four bone indices and four bone weights stored as vertex input attributes (the last two of the 16 xyzw vertex registers mentioned in Section 4.3.2). We sorted bone weights and bone indices so that we could rewrite the vertex shader to artificially truncate the number of bones acting on the vertex if we required higher vertex performance. Note that if you do this, you must also rescale the active bone weights so that they continue to add up to 1.

 

“Dawn”데모에서, 우리는 98개의 뼈와180,000개 이상의 삼각형으로된 메쉬를 다룬다. 우리는 몸체와 머리를 다루는데 정점당 4개의 행렬이면 충분하다는 것을 발견했다. 그래서 각 정점은 정점 입력 속성으로 저장된 4개의 뼈 인덱스와 뼈 가중치를 가진다(16개의 xyzw 정점 레지스터 중 마지막 2개는 섹션 4.3.2에 설명되어 있다). 우리는 뼈 가중치와 인덱스를 저장했기 때문에, 더 높은 정점 성능이 필요하면 정점에 작동하는 뼈의 수를 인위적으로 줄여서 정점 쉐이더를 재작성할 수 있다. 이렇게 할 때에 활성화된 뼈 가중치를 합이 1이 되도록 재설정해야 한다는 것을 주의하라.

 

4.4.1 Accumulated Matrix Skinning

When skinning, one must apply the matrix and its bind pose inverse not only to the position, but also to the normal, binormal, and tangent for lighting to be correct. If your hierarchy cannot assume that scales are the same across x, y, and z, then you must apply the inverse transpose of this concatenated matrix. If scales are uniform, then the inverse is the transpose, so the matrix remains unchanged. Nonuniform scales create problems in a variety of areas, so our engine does not permit them.

 

스키닝을 적용할 때, 올바른 조명을 위해 행렬와 바인드 포즈 역행렬을 위치 뿐만 아니라 법선, 종법선, 탄젠트에도 적용해야 한다. 만약 당신의 계층이 x, y, z가 같은 스케일이라고 가정할 수 없다면, 이 연결된 행렬의 역전치를 적용해야 한다. 만약 스케일이 동일하다면, 역과 전치는 동일하기 때문에 행렬은 변하지 않는다. 동일하지 않는 스케일은 여러 곳에서 문제를 일으킨다. 그래서 우리 엔진은 그것을 허용하지 않는다.

 

If we call the skin function from the previous code, we must call mul for each matrix for each vertex property. In current hardware, multiplying a point by a matrix is implemented as four dot products and three adds, and vector-multiply is three dot products and two adds. Thus, four-bone skinning of position, normal, binormal, and tangent results in:

 

만약 이전 코드로부터 skin 함수를 호출한다면, 각 정점 속성의 각 행렬에 대해 mul 함수를 호출해야 한다. 현재 하드웨어에서, 한 점과 행렬의 곱은 4번의 내적과 3번의 덥셈으로 구현되고, 벡터 곱은 3번의 내적과 2번의 덧셈으로 되어있다. 그러므로, 위치, 법선, 종법선, 탄젠트의 4-뼈 스키닝은 다음과 같이 된다.

 

ch04_eqn003.jpg

 

An unintuitive technique that creates the sum of the weighted matrices can be trivially implemented in HLSL or Cg as follows:

 

가중된 행렬의 합을 생성하는 비직관적인 기법은 HLSL이나 Cg에서  평범하게 다음과 같이 구현될 수 있다.

 

float4x4 accumulate_skin(float4x4 bones[98],
	float4   boneWeights0,
                         float4   boneIndices0)
{
  float4x4 result = boneWeights0.x * bones[boneIndices0.x];
  result = result + boneWeights0.y * bones[boneIndices0.y];
  result = result + boneWeights0.z * bones[boneIndices0.z];
  result = result + boneWeights0.w * bones[boneIndices0.w];
  return result;
}

Although this technique does burn instructions to build the accumulated matrix (16 multiplies and 12 adds), it now takes only a single matrix multiply to skin a point or vector. Skinning the same properties as before costs:

 

이 기법이 누적된 행렬을 생성하기 위해 명령어를 소비하기는 하지만(16번의 곱과 12번의 덧셈), 이제 점이나 벡터에 행렬을 한번만 곱하면 된다. 이전과 같은 속성의 스키닝이 소비하는 연산은 이제 다음과 같다.

 

ch04_eqn004.jpg

 

4.5 Conclusion

It is almost always beneficial to offload mesh animation from the CPU and take advantage of the programmable vertex pipeline offered by modern graphics hardware. Having seen the implementation of skinning and morph targets using shaders, however, it is clear that the inner loops are quite easy to implement using Streaming SIMD Extensions (SSE) instructions and the like, and that in those few cases where it is desirable to remain on the CPU, these same techniques work well.

 

메쉬 애니메이션을 CPU에서 빼내고 현대 그래픽 하드웨어에서 제공하는 프로그래밍 가능한 정점 파이프라인을 이용하는 것이 거의 항상 이득이 된다. 쉐이더를 사용하여 스키닝과 모프 타겟을 구현하는 것을 보았지만, 내부 루프는 Streaming SIMD Extensions (SSE) 명령어과 그와 비슷한 것을 사용하여 구현하는 것이 훨씬 쉽고, CPU에 남겨놓는 것이 바람직한 경우에도, 이와 같은 기법은 잘 작동한다.

 

In the case of the "Dawn" demo, morph targets were used to drive only the expressions on the head. If we had had more time, we would have used morph targets all over the body to solve problems with simple skinning. Even a well-skinned mesh has the problem that elbows, knees, and other joints lose volume when rotated. This is because the mesh bends but the joint does not get "fatter" to compensate for the pressing of flesh against flesh. A morph target or other mesh deformation applied either before or after the skinning step could provide this soft, fleshy deformation and create a more realistic result. We have done some work on reproducing the variety of mesh deformers provided in digital content-creation tools, and we look forward to applying them in the future.

 

“Dawn” 데모의 경우, 모프 타겟은 머리를 다루는데에만 사용되었다. 우리에게 더 많은 시간이 있었다면, 단순한 스키닝이 지닌 문제점을 해결하기 위해 몸 전체에 모프 타겟을 사용했을 것이다. 잘 스키닝된 메쉬 조차도 팔꿈치, 무릎, 다른 관절들이 회전할 때 부피가 작아지는 문제점을 가지고 있다. 이것은 메쉬는 구부러지지만 살끼리 눌려지는 것을 보완하기 위해 관절이 “더 굵어지지” 않기 때문이다. 스키닝 단계 이전이나 이후에 모프 타겟이나 다른 메쉬 변형을 적용하면 부드럽고 살찐 변형을 제공하고 더 사실적은 결과를 생성할 수 있다. 우리는 디지털 컨텐츠-생성 툴에서 제공된 여러 메쉬 변형기를 재현하는 작업을 해왔고, 미래에 그것들을 적용하길 기대하고 있다.

 

4.6 References

Alias Systems. Maya 5.0 Devkit. /devkit/animEngine/

Alias Systems. Maya 5.0 Documentation.

Eberly, David H. 2001. 3D Game Engine Design, pp. 356?358. Academic Press.

Gritz, Larry, Tony Apodaca, Matt Pharr, Dan Goldman, Hayden Landis, Guido Quaroni, and Rob Bredow. 2002. "RenderMan in Production." Course 16, SIGGRAPH 2002.

Hagland, Torgeir. 2000. "A Fast and Simple Skinning Technique." In Game Programming Gems, edited by Mark DeLoura. Charles River Media.


Copyright

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and Addison-Wesley was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals.

The authors and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein.

The publisher offers discounts on this book when ordered in quantity for bulk purchases and special sales. For more information, please contact:

      U.S. Corporate and Government Sales
      (800) 382-3419
      
corpsales@pearsontechgroup.com

For sales outside of the U.S., please contact:

      International Sales
      international@pearsoned.com

Visit Addison-Wesley on the Web: www.awprofessional.com

Library of Congress Control Number: 2004100582

GeForce™ and NVIDIA Quadro? are trademarks or registered trademarks of NVIDIA Corporation.
RenderMan? is a registered trademark of Pixar Animation Studios.
"Shadow Map Antialiasing" ? 2003 NVIDIA Corporation and Pixar Animation Studios.
"Cinematic Lighting" ? 2003 Pixar Animation Studios.
Dawn images ? 2002 NVIDIA Corporation. Vulcan images ? 2003 NVIDIA Corporation.

Copyright ? 2004 by NVIDIA Corporation.

All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. Printed in the United States of America. Published simultaneously in Canada.

For information on obtaining permission for use of material from this work, please submit a written request to:

      Pearson Education, Inc.
      Rights and Contracts Department
      One Lake Street
      Upper Saddle River, NJ 07458

Text printed on recycled and acid-free paper.

5 6 7 8 9 10 QWT 09 08 07

5th Printing September 2007