// 極座標から回転行列に変換. void CEphemeris::ConvertPolarToMatrix( const SPolarCoord& polar, izanagi::math::SMatrix44& mtx) { IZ_FLOAT latitude = IZ_DEG2RAD(polar.latitude); IZ_FLOAT longitude = IZ_DEG2RAD(polar.longitude); izanagi::math::SMatrix44 tmp; izanagi::math::SMatrix44::GetRotByZ(tmp, latitude); // NOTE // 真上(y軸+方向)から見た場合 => x-z平面 // z // | // | // +---->x // // 極座標を考える場合は、x-z平面は数学的に2次元で考えられて、すると、それはよくある x-y平面 とみなすことができる // すると、回転の方向は x->y に向けて、つまり反時計まわりとなる。 // しかし、左手座標系の回転は z->x に向けて、つまり時計まわりとなるため // 回転の方向に矛盾が生じる。 // そこで、正規化をする必要がある。 // TODO // 本来は、極座標を右手座標系に合わせる必要がある izanagi::math::SMatrix44::GetRotByY(mtx, IZ_MATH_PI2 - longitude); izanagi::math::SMatrix44::Mul(mtx, tmp, mtx); }
// 赤道座標から地平座標に変換. void CEphemeris::ConvertEquatorialToHorizontal( const izanagi::math::SVector4& equatorial, IZ_FLOAT latitude, IZ_FLOAT hourAngle, izanagi::math::SVector4& horizontal) { IZ_FLOAT lat = IZ_DEG2RAD(latitude); IZ_FLOAT hAngle = IZ_DEG2RAD(hourAngle); izanagi::math::SMatrix44 mtxLong; izanagi::math::SMatrix44::GetRotByY(mtxLong, -hAngle); izanagi::math::SMatrix44 mtxLat; izanagi::math::SMatrix44::GetRotByY(mtxLong, IZ_MATH_PI1_2 - lat); izanagi::math::SMatrix44::ApplyXYZ(horizontal, equatorial, mtxLong); izanagi::math::SMatrix44::ApplyXYZ(horizontal, horizontal, mtxLat); }
IZ_BOOL CBillboardYAxis::Render( izanagi::graph::CGraphicsDevice* device, izanagi::sample::CSampleCamera& camera) { izanagi::math::SMatrix44 mtx; izanagi::math::SMatrix44::SetUnit(mtx); izanagi::math::SMatrix44::RotByX(mtx, mtx, IZ_DEG2RAD(-90.0f)); izanagi::math::SVector4 dir = camera.GetDir(); if (dir.x == 0.0f) { } else { IZ_FLOAT deg = IZ_RAD2DEG(::atan2(dir.z, dir.x)); izanagi::math::SMatrix44::RotByY(mtx, mtx, -1.0f * IZ_DEG2RAD(deg) + IZ_MATH_PI1_2); } m_Shader->Begin(device, 0, IZ_FALSE); { if (m_Shader->BeginPass(0)) { _SetShaderParam( m_Shader, "g_mL2W", (void*)&mtx, sizeof(mtx)); _SetShaderParam( m_Shader, "g_mW2C", (void*)&camera.GetParam().mtxW2C, sizeof(camera.GetParam().mtxW2C)); // シェーダ設定 m_Shader->CommitChanges(device); m_Rect->Draw(device); } } m_Shader->End(device); return IZ_TRUE; }
// 極座標から直行座標に変換. void CEphemeris::ConvertPolarToRectangular( const SPolarCoord& polar, izanagi::math::SVector4& ortho) { IZ_FLOAT latitude = IZ_DEG2RAD(polar.latitude); IZ_FLOAT longitude = IZ_DEG2RAD(polar.longitude); IZ_FLOAT sinLat, cosLat; sinLat = izanagi::math::CMath::SinF(latitude); cosLat = izanagi::math::CMath::CosF(latitude); IZ_FLOAT sinLong, cosLong; sinLong = izanagi::math::CMath::SinF(longitude); cosLong = izanagi::math::CMath::CosF(longitude); ortho.x = polar.radius * cosLat * cosLong; ortho.y = polar.radius * sinLat; ortho.z = polar.radius * cosLat * sinLong; ortho.w = 0.0f; }
// 黄道座標から赤道座標に変換. void CEphemeris::ConvertElipticToEquatorial( const izanagi::math::SVector4& eliptic, izanagi::math::SVector4& equatorial) { izanagi::math::SMatrix44 mtx; izanagi::math::SMatrix44::GetRotByX(mtx, -IZ_DEG2RAD(23.43929f)); izanagi::math::SMatrix44::ApplyXYZ( equatorial, eliptic, mtx); }
IZ_BOOL CBillboard::Render( izanagi::graph::CGraphicsDevice* device, izanagi::sample::CSampleCamera& camera) { izanagi::math::SMatrix44 mtx; izanagi::math::SMatrix44::SetUnit(mtx); // 軸と並行になる向きにする izanagi::math::SMatrix44::GetRotByX(mtx, IZ_DEG2RAD(-90.0f)); // カメラに正対するようにする izanagi::math::SMatrix44 inv; { izanagi::math::SMatrix44::Copy(inv, camera.GetParam().mtxW2V); // 移動成分は消す inv.m[3][0] = inv.m[3][1] = inv.m[3][2] = 0.0f; // 逆行列にすることで、カメラのW2Vマトリクスと打ち消しあうようにする izanagi::math::SMatrix44::Inverse(inv, inv); } izanagi::math::SMatrix44::Mul(mtx, mtx, inv); m_Shader->Begin(device, 0, IZ_FALSE); { if (m_Shader->BeginPass(0)) { _SetShaderParam( m_Shader, "g_mL2W", (void*)&mtx, sizeof(mtx)); _SetShaderParam( m_Shader, "g_mW2C", (void*)&camera.GetParam().mtxW2C, sizeof(camera.GetParam().mtxW2C)); // シェーダ設定 m_Shader->CommitChanges(device); m_Rect->Draw(device); } } m_Shader->End(device); return IZ_TRUE; }
IZ_BOOL CColladaAnimation::CreateSlerp(IZ_UINT nNodeIdx) { IZ_ASSERT(nNodeIdx < m_AnmNodes.size()); SAnmNode& sAnmNode = m_AnmNodes[nNodeIdx]; std::vector<SQuatParam> tvQuatList; std::vector<SAnmChannel>::iterator itAnmChannel = sAnmNode.channels.begin(); for (; itAnmChannel != sAnmNode.channels.end(); ) { const SAnmChannel& sAnmChannel = *itAnmChannel; if (!(sAnmChannel.type & izanagi::E_ANM_TRANSFORM_TYPE_QUATERNION)) { itAnmChannel++; continue; } // TODO IZ_ASSERT((sAnmChannel.type & izanagi::E_ANM_TRANSFORM_TYPE_W) > 0); const SAnmInput* pKeyTime = sAnmChannel.FindInput(E_INPUT_SEMANTIC_INPUT); VRETURN(pKeyTime != IZ_NULL); const SAnmInput* pValue = sAnmChannel.FindInput(E_INPUT_SEMANTIC_OUTPUT); VRETURN(pValue != IZ_NULL); VRETURN((pValue->params.size() / pValue->stride) == pKeyTime->params.size()); // TODO IZ_ASSERT(pValue->stride == 1); const SJoint& sJoint = m_Joints[sAnmNode.idxJoint]; for (size_t nKey = 0; nKey < pKeyTime->params.size(); nKey++) { IZ_FLOAT fKeyTime = pKeyTime->params[nKey]; // Find target transform's param. std::vector<SQuatParam>::iterator itQuatParam; itQuatParam = std::find( tvQuatList.begin(), tvQuatList.end(), SQuatParam(sAnmChannel.transform.c_str(), fKeyTime)); if (itQuatParam != tvQuatList.end()) { // Replace parameter. SQuatParam& sQuatParams = *itQuatParam; sQuatParams.params[3] = IZ_DEG2RAD(pValue->params[nKey]); } else { // Create new transform's param. std::vector<SJointTransform>::const_reverse_iterator rit = sJoint.transforms.rbegin(); for (; rit != sJoint.transforms.rend(); rit++) { const SJointTransform& sJointTransform = *rit; SQuatParam sQuatParams(sJointTransform.name, fKeyTime); if (sJointTransform.type == E_TRANSFROM_TYPE_QUARTANION) { VRETURN(sJointTransform.param.size() == 4); sQuatParams.params[0] = sJointTransform.param[0]; sQuatParams.params[1] = sJointTransform.param[1]; sQuatParams.params[2] = sJointTransform.param[2]; if (sJointTransform.name == sAnmChannel.transform) { sQuatParams.params[3] = IZ_DEG2RAD(pValue->params[nKey]); } else { sQuatParams.params[3] = IZ_DEG2RAD(sJointTransform.param[3]); } sQuatParams.idx = static_cast<IZ_UINT>(tvQuatList.size()); tvQuatList.push_back(sQuatParams); } } } } // Remove sAnmChannel. itAnmChannel = sAnmNode.channels.erase(itAnmChannel); } if (!tvQuatList.empty()) { // Sort by time. std::sort( tvQuatList.begin(), tvQuatList.end(), SSortQuatParam()); SAnmChannel sAnmChannel; { sAnmChannel.type = izanagi::E_ANM_TRANSFORM_TYPE_QUATERNION_XYZW; sAnmChannel.interp = izanagi::E_ANM_INTERP_TYPE_SLERP; // Inputs are times and quartanions. sAnmChannel.inputs.resize(2); // Get times. std::set<IZ_FLOAT> times; for (size_t i = 0; i < tvQuatList.size(); i++) { const SQuatParam& sQuatParam = tvQuatList[i]; times.insert(sQuatParam.time); } SAnmInput& sAnmInput = sAnmChannel.inputs[0]; { sAnmInput.semantic = E_INPUT_SEMANTIC_INPUT; sAnmInput.stride = 1; } for (std::set<IZ_FLOAT>::const_iterator it = times.begin(); it != times.end(); it++) { sAnmInput.params.push_back(*it); } } // For quartanion. SAnmInput& sAnmInput = sAnmChannel.inputs[1]; { sAnmInput.semantic = E_INPUT_SEMANTIC_OUTPUT; sAnmInput.stride = 4; sAnmInput.params.reserve(4 * sAnmChannel.inputs[0].params.size()); } // Compute new quartanion. IZ_FLOAT fPrevTime = IZ_FLOAT_MAX; izanagi::math::SMatrix44 mtx; for (size_t i = 0; i < tvQuatList.size(); i++) { const SQuatParam& sQuatParam = tvQuatList[i]; IZ_FLOAT x = sQuatParam.params[0]; IZ_FLOAT y = sQuatParam.params[1]; IZ_FLOAT z = sQuatParam.params[2]; IZ_FLOAT angle = sQuatParam.params[3]; if (fPrevTime == sQuatParam.time) { _RotateAxis( mtx, mtx, x, y, z, angle); } else { if (i > 0) { izanagi::math::SQuat quat; izanagi::math::SQuat::QuatFromMatrix(quat, mtx); izanagi::math::SQuat::Normalize(quat, quat); sAnmInput.params.push_back(quat.x); sAnmInput.params.push_back(quat.y); sAnmInput.params.push_back(quat.z); sAnmInput.params.push_back(quat.w); } izanagi::math::SMatrix44::SetUnit(mtx); _RotateAxis( mtx, mtx, x, y, z, angle); fPrevTime = sQuatParam.time; } } { izanagi::math::SQuat quat; izanagi::math::SQuat::QuatFromMatrix(quat, mtx); izanagi::math::SQuat::Normalize(quat, quat); sAnmInput.params.push_back(quat.x); sAnmInput.params.push_back(quat.y); sAnmInput.params.push_back(quat.z); sAnmInput.params.push_back(quat.w); } // Add new channel. sAnmNode.channels.push_back(sAnmChannel); } return IZ_TRUE; }
StateChangeView::StateChangeView(izanagi::CVectorCamera& camera) : StateBase(camera) { izanagi::CVectorCamera tmpCam; // Low { #if 0 tmpCam.Init( izanagi::math::CVector4(0.0f, 5.0f, -Configure::InnerRadius + Configure::CameraDistance, 1.0f), izanagi::math::CVector4(0.0f, 5.0f, -Configure::InnerRadius, 1.0f), 1.0f, 500.0f, izanagi::math::CMath::Deg2Rad(60.0f), 1.0f); tmpCam.Update(); izanagi::math::SMatrix44::Copy(m_ViewMtx[ViewState_Low], tmpCam.GetTransform()); #else izanagi::math::SMatrix44::Copy(m_ViewMtx[ViewState_Low], camera.GetTransform()); #endif } // Mid { izanagi::math::CVector4 v(0.0f, 0.0f, Configure::CameraDistance, 0.0f); izanagi::math::SMatrix44 mtx; izanagi::math::SMatrix44::GetRotByX(mtx, IZ_DEG2RAD(-30.0f)); izanagi::math::SMatrix44::Apply(v, v, mtx); tmpCam.Init( izanagi::math::CVector4(0.0f, v.y, -Configure::InnerRadius + v.z, 1.0f), izanagi::math::CVector4(0.0f, 15.0f, -Configure::InnerRadius + Configure::RadiusDiff + Configure::RadiusDiff * 0.5f, 1.0f), 1.0f, 500.0f, izanagi::math::CMath::Deg2Rad(60.0f), 1.0f); tmpCam.Update(); izanagi::math::SMatrix44::Copy(m_ViewMtx[ViewState_Mid], tmpCam.GetTransform()); } // High { izanagi::math::CVector4 v(0.0f, 0.0f, Configure::CameraDistance, 0.0f); izanagi::math::SMatrix44 mtx; izanagi::math::SMatrix44::GetRotByX(mtx, IZ_DEG2RAD(-55.0f)); izanagi::math::SMatrix44::Apply(v, v, mtx); tmpCam.Init( izanagi::math::CVector4(0.0f, v.y, -Configure::InnerRadius + v.z, 1.0f), izanagi::math::CVector4(0.0f, 25.0f, -Configure::InnerRadius + Configure::RadiusDiff * 0.5f, 1.0f), 1.0f, 500.0f, izanagi::math::CMath::Deg2Rad(60.0f), 1.0f); tmpCam.Update(); izanagi::math::SMatrix44::Copy(m_ViewMtx[ViewState_High], tmpCam.GetTransform()); } m_State = ViewState_Low; m_IsAnimating = IZ_FALSE; m_Timeline.Init( Configure::ChangeViewDuration, 0.0f); m_Timeline.EnableLoop(IZ_FALSE); m_Timeline.AutoReverse(IZ_FALSE); }