/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_BillboardUpdater.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include "precompiled.h" #include #include #include namespace nw { namespace gfx { //---------------------------------------- BillboardUpdater* BillboardUpdater::Create( os::IAllocator* allocator ) { NW_NULL_ASSERT(allocator); void* updaterMemory = allocator->Alloc(sizeof(BillboardUpdater)); NW_NULL_ASSERT(updaterMemory); return new(updaterMemory) BillboardUpdater(allocator); } //---------------------------------------- BillboardUpdater::BillboardUpdater( os::IAllocator* allocator ) : GfxObject(allocator) { NW_NULL_ASSERT(allocator); } //---------------------------------------- BillboardUpdater::~BillboardUpdater() { } //---------------------------------------- void BillboardUpdater::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 ) const { NW_ASSERT( ResBone::BILLBOARD_MODE_OFF < billboardMode && billboardMode <= ResBone::BILLBOARD_MODE_Y_AXIAL_VIEWPOINT ); switch (billboardMode) { case ResBone::BILLBOARD_MODE_WORLD: { this->CalculateLocalMatrix( worldMatrix, worldTransform, inverseViewMatrix.GetColumn(2) ); } break; case ResBone::BILLBOARD_MODE_WORLD_VIEWPOINT: { this->CalculateLocalMatrix( worldMatrix, worldTransform, cameraPosition - worldTransform.GetTranslate()); } break; case ResBone::BILLBOARD_MODE_SCREEN: { // localTransformにinverseViewMatrixを掛けるだけでは // アニメーション以外の回転成分も適用されてしまうので // ジョイントにビルボード設定を施したときなどにおかしな挙動になります。 // そこでlocalTransformのY軸成分とZ軸方向(0,0,1)から // z軸中心の回転を考慮しつつ正面を向くようなlocalMatrixを生成します。 math::VEC3 zAxis(0.0f ,0.0f, 1.0f); this->CalculateScreenLocalMatrix( worldMatrix, worldTransform, inverseViewMatrix, localTransform.TransformMatrix().GetColumn(1), zAxis); } break; case ResBone::BILLBOARD_MODE_SCREEN_VIEWPOINT: { // ワールド座標系における位置です math::VEC3 wPos(worldTransform.GetTranslate()); // ビュー座標系における位置です。 math::VEC3 viewPos; const f32 (*m)[4] = viewMatrix.m; viewPos.x = - (m[0][0] * wPos.x + m[0][1] * wPos.y + m[0][2] * wPos.z + m[0][3]); viewPos.y = - (m[1][0] * wPos.x + m[1][1] * wPos.y + m[1][2] * wPos.z + m[1][3]); viewPos.z = - (m[2][0] * wPos.x + m[2][1] * wPos.y + m[2][2] * wPos.z + m[2][3]); viewPos.SafeNormalize(math::VEC3(0.0f ,0.0f, 1.0f)); // localTransformのY軸成分とカメラ方向のベクトルを用いて // localMatrixを計算します。 this->CalculateScreenLocalMatrix( worldMatrix, worldTransform, inverseViewMatrix, localTransform.TransformMatrix().GetColumn(1), viewPos); } break; case ResBone::BILLBOARD_MODE_Y_AXIAL: { // Y軸の代わりにZ軸を再計算します。それによって // localMatrixのY軸成分は常にworldTransformのY軸成分になります。 this->CalculateLocalMatrix( worldMatrix, worldTransform, inverseViewMatrix.GetColumn(2), false); } break; case ResBone::BILLBOARD_MODE_Y_AXIAL_VIEWPOINT: { // Y軸の代わりにZ軸を再計算します。それによって // localMatrixのY軸成分は常にworldTransformのY軸成分になります。 this->CalculateLocalMatrix( worldMatrix, worldTransform, cameraPosition - worldTransform.GetTranslate(), false); } break; default: { NW_FATAL_ERROR("Unsupported billboard type."); } break; } } //---------------------------------------- void BillboardUpdater::CalculateLocalMatrix( math::MTX34* localMatrix, const CalculatedTransform& transform, math::VEC3 zAxis, bool recalculateYAxis) const { const math::MTX34& matrix = transform.TransformMatrix(); math::VEC3 &rz = zAxis; rz.Normalize(); f32 (*const m)[4] = localMatrix->m; if (transform.IsEnabledFlags(CalculatedTransform::FLAG_IS_IDENTITY)) { math::VEC3 ry(0.0f, 1.0f, 0.0f); math::VEC3 rx; rx.Cross(ry, rz).SafeNormalize(math::VEC3(1.0f, 0.0f, 0.0f)); if (recalculateYAxis) { ry.Cross(rz,rx); } else { rz.Cross(rx,ry); } m[0][0] = rx.x; m[0][1] = ry.x; m[0][2] = rz.x; m[0][3] = 0.0f; m[1][0] = rx.y; m[1][1] = ry.y; m[1][2] = rz.y; m[1][3] = 0.0f; m[2][0] = rx.z; m[2][1] = ry.z; m[2][2] = rz.z; m[2][3] = 0.0f; } else { math::VEC3 ry(matrix.GetColumn(1)); ry.SafeNormalize(math::VEC3(1.0f, 0.0f, 0.0f)); math::VEC3 rx; rx.Cross(ry,rz).SafeNormalize(matrix.GetColumn(2)); if (recalculateYAxis) { ry.Cross(rz,rx); } else { rz.Cross(rx,ry); } m[0][0] = rx.x; m[0][1] = ry.x; m[0][2] = rz.x; m[0][3] = matrix.m[0][3]; m[1][0] = rx.y; m[1][1] = ry.y; m[1][2] = rz.y; m[1][3] = matrix.m[1][3]; m[2][0] = rx.z; m[2][1] = ry.z; m[2][2] = rz.z; m[2][3] = matrix.m[2][3]; } } //---------------------------------------- void BillboardUpdater::CalculateScreenLocalMatrix( math::MTX34* localMatrix, const CalculatedTransform& transform, const math::MTX34& inverseViewMatrix, math::VEC3 yAxis, math::VEC3& zAxis) const { const math::MTX34& matrix = transform.TransformMatrix(); math::VEC3 &rz = zAxis; f32 (*const m)[4] = localMatrix->m; if ( transform.IsEnabledFlags(CalculatedTransform::FLAG_IS_IDENTITY) ) { math::VEC3 ry(0.0f,1.0f,0.0f); math::VEC3 rx; rx.Cross(ry, rz).Normalize(); ry.Cross(rz, rx); m[0][0] = rx.x; m[0][1] = ry.x; m[0][2] = rz.x; m[0][3] = 0.0f; m[1][0] = rx.y; m[1][1] = ry.y; m[1][2] = rz.y; m[1][3] = 0.0f; m[2][0] = rx.z; m[2][1] = ry.z; m[2][2] = rz.z; m[2][3] = 0.0f; } else { math::VEC3 &ry = yAxis; math::VEC3Normalize(&ry, &ry); math::VEC3 rx; rx.Cross(ry,rz).Normalize(); ry.Cross(rz,rx); m[0][0] = rx.x; m[0][1] = ry.x; m[0][2] = rz.x; m[0][3] = matrix.m[0][3]; m[1][0] = rx.y; m[1][1] = ry.y; m[1][2] = rz.y; m[1][3] = matrix.m[1][3]; m[2][0] = rx.z; m[2][1] = ry.z; m[2][2] = rz.z; m[2][3] = matrix.m[2][3]; } math::MTX33Mult(localMatrix, &inverseViewMatrix, localMatrix); // この時点では平行移動成分はlocalTransformのものが用いられているので // worldTransformの平行移動成分をセットします。 localMatrix->SetColumn(3, transform.GetTranslate()); } } // namespace gfx } // namespace nw