1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_BillboardUpdater.cpp
4
5 Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain proprietary
8 information of Nintendo and/or its licensed developers and are protected by
9 national and international copyright laws. They may not be disclosed to third
10 parties or copied or duplicated in any form, in whole or in part, without the
11 prior written consent of Nintendo.
12
13 The content herein is highly confidential and should be handled accordingly.
14
15 $Revision: 31311 $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/gfx/gfx_BillboardUpdater.h>
21 #include <nw/gfx/gfx_CalculatedTransform.h>
22 #include <nw/gfx/res/gfx_ResSkeleton.h>
23
24 namespace nw
25 {
26 namespace gfx
27 {
28
29 //----------------------------------------
30 BillboardUpdater*
Create(os::IAllocator * allocator)31 BillboardUpdater::Create(
32 os::IAllocator* allocator
33 )
34 {
35 NW_NULL_ASSERT(allocator);
36
37 void* updaterMemory = allocator->Alloc(sizeof(BillboardUpdater));
38 NW_NULL_ASSERT(updaterMemory);
39
40 return new(updaterMemory) BillboardUpdater(allocator);
41 }
42
43 //----------------------------------------
BillboardUpdater(os::IAllocator * allocator)44 BillboardUpdater::BillboardUpdater(
45 os::IAllocator* allocator
46 )
47 : GfxObject(allocator)
48 {
49 NW_NULL_ASSERT(allocator);
50 }
51
52 //----------------------------------------
~BillboardUpdater()53 BillboardUpdater::~BillboardUpdater()
54 {
55 }
56
57 //----------------------------------------
58 void
Update(math::MTX34 * worldMatrix,const math::MTX34 & viewMatrix,const math::MTX34 & inverseViewMatrix,const math::VEC3 & cameraPosition,const CalculatedTransform & worldTransform,const CalculatedTransform & localTransform,ResBone::BillboardMode billboardMode) const59 BillboardUpdater::Update(
60 math::MTX34* worldMatrix,
61 const math::MTX34& viewMatrix,
62 const math::MTX34& inverseViewMatrix,
63 const math::VEC3& cameraPosition,
64 const CalculatedTransform& worldTransform,
65 const CalculatedTransform& localTransform,
66 ResBone::BillboardMode billboardMode
67 ) const
68 {
69 NW_ASSERT( ResBone::BILLBOARD_MODE_OFF < billboardMode && billboardMode <= ResBone::BILLBOARD_MODE_Y_AXIAL_VIEWPOINT );
70
71 switch (billboardMode)
72 {
73 case ResBone::BILLBOARD_MODE_WORLD:
74 {
75 this->CalculateLocalMatrix(
76 worldMatrix,
77 worldTransform,
78 inverseViewMatrix.GetColumn(2)
79 );
80 }
81
82 break;
83 case ResBone::BILLBOARD_MODE_WORLD_VIEWPOINT:
84 {
85 this->CalculateLocalMatrix(
86 worldMatrix,
87 worldTransform,
88 cameraPosition - worldTransform.GetTranslate());
89 }
90
91 break;
92 case ResBone::BILLBOARD_MODE_SCREEN:
93 {
94 // localTransformにinverseViewMatrixを掛けるだけでは
95 // アニメーション以外の回転成分も適用されてしまうので
96 // ジョイントにビルボード設定を施したときなどにおかしな挙動になります。
97 // そこでlocalTransformのY軸成分とZ軸方向(0,0,1)から
98 // z軸中心の回転を考慮しつつ正面を向くようなlocalMatrixを生成します。
99 math::VEC3 zAxis(0.0f ,0.0f, 1.0f);
100 this->CalculateScreenLocalMatrix(
101 worldMatrix,
102 worldTransform,
103 inverseViewMatrix,
104 localTransform.TransformMatrix().GetColumn(1),
105 zAxis);
106 }
107
108 break;
109 case ResBone::BILLBOARD_MODE_SCREEN_VIEWPOINT:
110 {
111 // ワールド座標系における位置です
112 math::VEC3 wPos(worldTransform.GetTranslate());
113
114 // ビュー座標系における位置です。
115 math::VEC3 viewPos;
116 const f32 (*m)[4] = viewMatrix.m;
117 viewPos.x = - (m[0][0] * wPos.x + m[0][1] * wPos.y + m[0][2] * wPos.z + m[0][3]);
118 viewPos.y = - (m[1][0] * wPos.x + m[1][1] * wPos.y + m[1][2] * wPos.z + m[1][3]);
119 viewPos.z = - (m[2][0] * wPos.x + m[2][1] * wPos.y + m[2][2] * wPos.z + m[2][3]);
120 viewPos.SafeNormalize(math::VEC3(0.0f ,0.0f, 1.0f));
121
122 // localTransformのY軸成分とカメラ方向のベクトルを用いて
123 // localMatrixを計算します。
124 this->CalculateScreenLocalMatrix(
125 worldMatrix,
126 worldTransform,
127 inverseViewMatrix,
128 localTransform.TransformMatrix().GetColumn(1),
129 viewPos);
130 }
131
132 break;
133 case ResBone::BILLBOARD_MODE_Y_AXIAL:
134 {
135 // Y軸の代わりにZ軸を再計算します。それによって
136 // localMatrixのY軸成分は常にworldTransformのY軸成分になります。
137 this->CalculateLocalMatrix(
138 worldMatrix,
139 worldTransform,
140 inverseViewMatrix.GetColumn(2),
141 false);
142 }
143
144 break;
145 case ResBone::BILLBOARD_MODE_Y_AXIAL_VIEWPOINT:
146 {
147 // Y軸の代わりにZ軸を再計算します。それによって
148 // localMatrixのY軸成分は常にworldTransformのY軸成分になります。
149 this->CalculateLocalMatrix(
150 worldMatrix,
151 worldTransform,
152 cameraPosition - worldTransform.GetTranslate(),
153 false);
154 }
155
156 break;
157 default:
158 {
159 NW_FATAL_ERROR("Unsupported billboard type.");
160 }
161
162 break;
163 }
164 }
165
166 //----------------------------------------
167 void
CalculateLocalMatrix(math::MTX34 * localMatrix,const CalculatedTransform & transform,math::VEC3 zAxis,bool recalculateYAxis) const168 BillboardUpdater::CalculateLocalMatrix(
169 math::MTX34* localMatrix,
170 const CalculatedTransform& transform,
171 math::VEC3 zAxis,
172 bool recalculateYAxis) const
173 {
174 const math::MTX34& matrix = transform.TransformMatrix();
175 math::VEC3 &rz = zAxis;
176 rz.Normalize();
177
178 f32 (*const m)[4] = localMatrix->m;
179
180 if (transform.IsEnabledFlags(CalculatedTransform::FLAG_IS_IDENTITY))
181 {
182 math::VEC3 ry(0.0f, 1.0f, 0.0f);
183
184 math::VEC3 rx;
185 rx.Cross(ry, rz).SafeNormalize(math::VEC3(1.0f, 0.0f, 0.0f));
186 if (recalculateYAxis)
187 {
188 ry.Cross(rz,rx);
189 }
190 else
191 {
192 rz.Cross(rx,ry);
193 }
194
195 m[0][0] = rx.x;
196 m[0][1] = ry.x;
197 m[0][2] = rz.x;
198 m[0][3] = 0.0f;
199
200 m[1][0] = rx.y;
201 m[1][1] = ry.y;
202 m[1][2] = rz.y;
203 m[1][3] = 0.0f;
204
205 m[2][0] = rx.z;
206 m[2][1] = ry.z;
207 m[2][2] = rz.z;
208 m[2][3] = 0.0f;
209 }
210 else
211 {
212 math::VEC3 ry(matrix.GetColumn(1));
213
214 ry.SafeNormalize(math::VEC3(1.0f, 0.0f, 0.0f));
215
216 math::VEC3 rx;
217 rx.Cross(ry,rz).SafeNormalize(matrix.GetColumn(2));
218
219 if (recalculateYAxis)
220 {
221 ry.Cross(rz,rx);
222 }
223 else
224 {
225 rz.Cross(rx,ry);
226 }
227
228 m[0][0] = rx.x;
229 m[0][1] = ry.x;
230 m[0][2] = rz.x;
231 m[0][3] = matrix.m[0][3];
232
233 m[1][0] = rx.y;
234 m[1][1] = ry.y;
235 m[1][2] = rz.y;
236 m[1][3] = matrix.m[1][3];
237
238 m[2][0] = rx.z;
239 m[2][1] = ry.z;
240 m[2][2] = rz.z;
241 m[2][3] = matrix.m[2][3];
242 }
243 }
244
245 //----------------------------------------
246 void
CalculateScreenLocalMatrix(math::MTX34 * localMatrix,const CalculatedTransform & transform,const math::MTX34 & inverseViewMatrix,math::VEC3 yAxis,math::VEC3 & zAxis) const247 BillboardUpdater::CalculateScreenLocalMatrix(
248 math::MTX34* localMatrix,
249 const CalculatedTransform& transform,
250 const math::MTX34& inverseViewMatrix,
251 math::VEC3 yAxis,
252 math::VEC3& zAxis) const
253 {
254 const math::MTX34& matrix = transform.TransformMatrix();
255 math::VEC3 &rz = zAxis;
256 f32 (*const m)[4] = localMatrix->m;
257
258 if ( transform.IsEnabledFlags(CalculatedTransform::FLAG_IS_IDENTITY) )
259 {
260 math::VEC3 ry(0.0f,1.0f,0.0f);
261
262 math::VEC3 rx;
263 rx.Cross(ry, rz).Normalize();
264 ry.Cross(rz, rx);
265
266 m[0][0] = rx.x;
267 m[0][1] = ry.x;
268 m[0][2] = rz.x;
269 m[0][3] = 0.0f;
270
271 m[1][0] = rx.y;
272 m[1][1] = ry.y;
273 m[1][2] = rz.y;
274 m[1][3] = 0.0f;
275
276 m[2][0] = rx.z;
277 m[2][1] = ry.z;
278 m[2][2] = rz.z;
279 m[2][3] = 0.0f;
280 }
281 else
282 {
283 math::VEC3 &ry = yAxis;
284
285 math::VEC3Normalize(&ry, &ry);
286
287 math::VEC3 rx;
288 rx.Cross(ry,rz).Normalize();
289 ry.Cross(rz,rx);
290
291 m[0][0] = rx.x;
292 m[0][1] = ry.x;
293 m[0][2] = rz.x;
294 m[0][3] = matrix.m[0][3];
295
296 m[1][0] = rx.y;
297 m[1][1] = ry.y;
298 m[1][2] = rz.y;
299 m[1][3] = matrix.m[1][3];
300
301 m[2][0] = rx.z;
302 m[2][1] = ry.z;
303 m[2][2] = rz.z;
304 m[2][3] = matrix.m[2][3];
305 }
306
307 math::MTX33Mult(localMatrix, &inverseViewMatrix, localMatrix);
308
309 // この時点では平行移動成分はlocalTransformのものが用いられているので
310 // worldTransformの平行移動成分をセットします。
311 localMatrix->SetColumn(3, transform.GetTranslate());
312 }
313
314 } // namespace gfx
315 } // namespace nw
316