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