// mirror coordinate system will change the handedness of original coordinate system // // axis_mirror: defines the axis that coordinate system mirror on // Mat3 mirror_coordinate_system (CoordinateAxisType axis_mirror) { Mat3 t_mat; switch (axis_mirror) { case AXIS_X: case AXIS_MINUS_X: t_mat = Mat3(Vec3(-1, 0, 0), Vec3(0, 1, 0), Vec3(0, 0, 1)); break; case AXIS_Y: case AXIS_MINUS_Y: t_mat = Mat3(Vec3(1, 0, 0), Vec3(0, -1, 0), Vec3(0, 0, 1)); break; case AXIS_Z: case AXIS_MINUS_Z: t_mat = Mat3(Vec3(1, 0, 0), Vec3(0, 1, 0), Vec3(0, 0, -1)); break; default: t_mat = Mat3(); break; } return t_mat; }
void TrackballCameraController::Track(float x,float y) { // // Mat4 mat(1.0); // mat = glm::rotate(mat,y*mRotationScaler,mRight); // mat = glm::rotate(mat,x*mRotationScaler,Vec3(0.0f, glm::dot(mCamera->UpVec(), Vec3(0, 1, 0)) < 0 ? -1.0f : 1.0f, 0.0f)); // Vec3 pos = (mCamera->Eye())*Mat3(mat); // Vec3 target = mCamera->Tareget()*Mat3(mat); // Vec3 up = Vec3(0.0f, glm::dot(mCamera->UpVec(), Vec3(0, 1, 0)) < 0 ? -1.0f : 1.0f, 0.0f); // mRight = glm::normalize(glm::cross(up, -pos)); // mCamera->LookAt(pos, target, mCamera->UpVec()); /*Quat q = MathLib::rotation_axis(mRight, y * mRotationScaler); Mat4 mat = MathLib::transformation(mTarget, q); Vec3 pos = MathLib::transform_coord(mCamera->Eye(), mat); q = MathLib::rotation_axis(Vec3(0.0f, glm::dot(mCamera->UpVec(), Vec3(0, 1, 0)) < 0 ? -1.0f : 1.0f, 0.0f), x * mRotationScaler); mat = MathLib::transformation(mTarget, q); pos = MathLib::transform_coord(pos, mat); mRight = MathLib::transform_quat(mRight, q); Vec3 dir; if (mReverseTarget) { dir = pos - mTarget; } else { dir = mTarget - pos; } dir = glm::normalize(dir); Vec3 up = glm::cross(dir, mRight); mCamera->LookAt(pos, pos + dir, up);*/ Mat4 mat,matx,maty; mat = matx = maty = Mat4(1.0); matx = glm::rotate(matx,x*mRotationScaler,Vec3(0,1,0)); maty = glm::rotate(matx,y*mRotationScaler,Vec3(1,0,0)); mat = matx*maty; Vec3 pos = (mCamera->Eye())*Mat3(mat); Vec3 target = mCamera->Tareget()*Mat3(mat); Vec3 up = mCamera->UpVec()*Mat3(mat); //Vec3 up = Vec3(0.0f, glm::dot(mCamera->UpVec(), Vec3(0, 1, 0)) < 0 ? -1.0f : 1.0f, 0.0f); //mRight = glm::normalize(glm::cross(up, -pos)); mCamera->LookAt(pos, target,up); }
Mat3< T > Mat3< T >::operator -(const Mat3& m) const { return Mat3( e_[X0] - m.e_[X0], e_[Y0] - m.e_[Y0], e_[W0] - m.e_[W0], e_[X1] - m.e_[X1], e_[Y1] - m.e_[Y1], e_[W1] - m.e_[W1], e_[X2] - m.e_[X2], e_[Y2] - m.e_[Y2], e_[W2] - m.e_[W2] ); }
Mat3< T > Mat3< T >::operator *(const T t) const { return Mat3( e_[X0] * t, e_[Y0] * t, e_[W0] * t, e_[X1] * t, e_[Y1] * t, e_[W1] * t, e_[X2] * t, e_[Y2] * t, e_[W2] * t ); }
Mat3< T > Mat3< T >::getTranspose() const { return Mat3( e_[X0], e_[X1], e_[X2], e_[Y0], e_[Y1], e_[Y2], e_[W0], e_[W1], e_[W2] ); }
Mat3 Mat3::Transpose() const { return Mat3( m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8] ); }
bool GetShot(Shot* shot, Vec3 poi, Vec3 momentum) { if(blood_material != NULL) for (int i = 0; i < 8; ++i) { Particle* p = new Particle(corpse->game_state, poi, Random3D::RandomNormalizedVector(Random3D::Rand(5)) + momentum * Random3D::Rand(), NULL, blood_material, Random3D::Rand(0.05f, 0.15f), 0.25f); p->gravity = 9.8f; p->damp = 0.05f; corpse->game_state->Spawn(p); } Mat4 xform; { xform = rbi->GetTransformationMatrix(); float ori_values[] = {xform[0], xform[1], xform[2], xform[4], xform[5], xform[6], xform[8], xform[9], xform[10]}; Quaternion rigid_body_ori = Quaternion::FromRotationMatrix(Mat3(ori_values).Transpose()); Vec3 pos = xform.TransformVec3(0, 0, 0, 1); xform = Mat4::FromPositionAndOrientation(pos, rigid_body_ori.ToMat3().Transpose()); } Vec3 pos = xform.TransformVec3(0, 0, 0, 1); Vec3 x_axis = xform.TransformVec3(1, 0, 0, 0); Vec3 y_axis = xform.TransformVec3(0, 1, 0, 0); Vec3 z_axis = xform.TransformVec3(0, 0, 1, 0); Vec3 local_poi; local_poi = poi - pos; local_poi = Vec3(Vec3::Dot(local_poi, x_axis), Vec3::Dot(local_poi, y_axis), Vec3::Dot(local_poi, z_axis)); local_poi = local_poi.x * x_axis + local_poi.y * y_axis + local_poi.z * z_axis; rbi->Activate(); rbi->ApplyImpulse(momentum, local_poi); return true; }
Mat3 Vec3::outer(const Vec3 &_v ) const { return Mat3( m_x * _v.m_x, m_x * _v.m_y, m_x * _v.m_z, m_y * _v.m_x, m_y * _v.m_y, m_y * _v.m_z, m_z * _v.m_x, m_z * _v.m_y, m_z * _v.m_z ); }
// rotate coordinate system keeps the handedness of original coordinate system unchanged // // axis_to_x: defines the axis of the new cooridinate system that // coincide with the X axis of the original coordinate system. // axis_to_y: defines the axis of the new cooridinate system that // coincide with the Y axis of the original coordinate system. // Mat3 rotate_coordinate_system (CoordinateAxisType axis_to_x, CoordinateAxisType axis_to_y) { Mat3 t_mat; if (axis_to_x == AXIS_X && axis_to_y == AXIS_MINUS_Z) { t_mat = Mat3(Vec3(1, 0, 0), Vec3(0, 0, 1), Vec3(0, -1, 0)); } else if (axis_to_x == AXIS_X && axis_to_y == AXIS_MINUS_Y) { t_mat = Mat3(Vec3(1, 0, 0), Vec3(0, -1, 0), Vec3(0, 0, -1)); } else if (axis_to_x == AXIS_X && axis_to_y == AXIS_Z) { t_mat = Mat3(Vec3(1, 0, 0), Vec3(0, 0, -1), Vec3(0, 1, 0)); } else if (axis_to_x == AXIS_MINUS_Z && axis_to_y == AXIS_Y) { t_mat = Mat3(Vec3(0, 0, 1), Vec3(0, 1, 0), Vec3(-1, 0, 0)); } else if (axis_to_x == AXIS_MINUS_X && axis_to_y == AXIS_Y) { t_mat = Mat3(Vec3(-1, 0, 0), Vec3(0, 1, 0), Vec3(0, 0, -1)); } else if (axis_to_x == AXIS_Z && axis_to_y == AXIS_Y) { t_mat = Mat3(Vec3(0, 0, -1), Vec3(0, 1, 0), Vec3(1, 0, 0)); } else if (axis_to_x == AXIS_MINUS_Y && axis_to_y == AXIS_X) { t_mat = Mat3(Vec3(0, 1, 0), Vec3(-1, 0, 0), Vec3(0, 0, 1)); } else if (axis_to_x == AXIS_MINUS_X && axis_to_y == AXIS_MINUS_Y) { t_mat = Mat3(Vec3(-1, 0, 0), Vec3(0, -1, 0), Vec3(0, 0, 1)); } else if (axis_to_x == AXIS_Y && axis_to_y == AXIS_MINUS_X) { t_mat = Mat3(Vec3(0, -1, 0), Vec3(1, 0, 0), Vec3(0, 0, 1)); } else { t_mat = Mat3(); } return t_mat; }
Mat3< T > Mat3< T >::getIdentity() { const T n = static_cast< T >(0.0); const T u = static_cast< T >(1.0); return Mat3( u, n, n, n, u, n, n, n, u ); }
Mat3< T > Mat3<T>::getTranslation(const T x, const T y) { const T n = static_cast< T >(0.0); const T u = static_cast< T >(1.0); return Mat3( u, n, n, n, u, n, x, y, u ); }
Mat3< T > Mat3<T>::getScaling(const T x, const T y) { const T n = static_cast< T >(0.0); const T u = static_cast< T >(1.0); return Mat3( x, n, n, n, y, n, n, n, u ); }
void StageLayer::Render(Renderer *renderer) { // render if(!isVisible()) return; renderer->setStageLayer(this); this->setViewport(); this->visit(renderer, Mat3(), false); renderer->Flush(); }
void Rubbish::Update(TimingInfo time) { xform = rigid_body->GetTransformationMatrix(); float ori_values[] = {xform[0], xform[1], xform[2], xform[4], xform[5], xform[6], xform[8], xform[9], xform[10]}; Quaternion rigid_body_ori = Quaternion::FromRotationMatrix(Mat3(ori_values).Transpose()); Vec3 pos = xform.TransformVec3(0, 0, 0, 1); xform = Mat4::FromPositionAndOrientation(pos, rigid_body_ori.ToMat3().Transpose()); }
Mat3 Mat3::rotate(const float &theta) { #if defined RADIANS float cosT = cosf(theta); // theta in radians float sinT = sinf(theta); // theta in radians #elif defined DEGREES float cosT = cosf(theta * M_PI / 180.0f); // theta in degrees float sinT = sinf(theta * M_PI / 180.0f); // theta in degrees #endif #if defined RIGHTHANDED return Mat3( cosT, -sinT, 0.0f, sinT, cosT, 0.0f, 0.0f, 0.0f, 1.0f); #elif defined LEFTHANDED return Mat3( cosT, sinT, 0.0f, -sinT, cosT, 0.0f, 0.0f, 0.0f, 1.0f); #endif }
Mat3 Mat3::operator*(const Mat3 &m) const { return Mat3( d00*m.d00 + d01*m.d10 + d02*m.d20, d00*m.d01 + d01*m.d11 + d02*m.d21, d00*m.d02 + d01*m.d12 + d02*m.d22, d10*m.d00 + d11*m.d10 + d12*m.d20, d10*m.d01 + d11*m.d11 + d12*m.d21, d10*m.d02 + d11*m.d12 + d12*m.d22, d20*m.d00 + d21*m.d10 + d22*m.d20, d20*m.d01 + d21*m.d11 + d22*m.d21, d20*m.d02 + d21*m.d12 + d22*m.d22 ); }
Mat3< T > Mat3< T >::operator *(const Mat3& m) const { return Mat3( e_[X0] * m.e_[X0] + e_[X1] * m.e_[Y0] + e_[X2] * m.e_[W0], e_[Y0] * m.e_[X0] + e_[Y1] * m.e_[Y0] + e_[Y2] * m.e_[W0], e_[W0] * m.e_[X0] + e_[W1] * m.e_[Y0] + e_[W2] * m.e_[W0], e_[X0] * m.e_[X1] + e_[X1] * m.e_[Y1] + e_[X2] * m.e_[W1], e_[Y0] * m.e_[X1] + e_[Y1] * m.e_[Y1] + e_[Y2] * m.e_[W1], e_[W0] * m.e_[X1] + e_[W1] * m.e_[Y1] + e_[W2] * m.e_[W1], e_[X0] * m.e_[X2] + e_[X1] * m.e_[Y2] + e_[X2] * m.e_[W2], e_[Y0] * m.e_[X2] + e_[Y1] * m.e_[Y2] + e_[Y2] * m.e_[W2], e_[W0] * m.e_[X2] + e_[W1] * m.e_[Y2] + e_[W2] * m.e_[W2] ); }
Mat3 Mat3::inverse() { return Mat3( d11*d22 - d21*d12, -d01*d22 - d21*d02, d01*d12 - d11*d02, -d10*d22 - d20*d12, d00*d22 - d20*d02, -d00*d12 - d10*d02, d10*d21 - d20*d11, -d00*d21 - d20*d01, d00*d11 - d10*d01) /determinant(); }
Mat3< T > Mat3<T>::getRotation(const T r) { const T n = static_cast< T >(0.0); const T u = static_cast< T >(1.0); const T rad = r * Constants< T >::InvDeg360() * Constants< T >::Pi2(); const T c = std::cos(rad); const T s = std::sin(rad); return Mat3( c, s, n, -s, c, n, n, n, u ); }
Mat3< T > Mat3< T >::getInverse() const { const T invDet = static_cast< T >(1.0) / getDeterminant(); return Mat3( e_[Y1] * e_[W2] - e_[Y2] * e_[W1], e_[Y2] * e_[W0] - e_[Y0] * e_[W2], e_[Y0] * e_[W1] - e_[Y1] * e_[W0], e_[X2] * e_[W1] - e_[X1] * e_[W2], e_[X0] * e_[W2] - e_[X2] * e_[W0], e_[X1] * e_[W0] - e_[X0] * e_[W1], e_[X1] * e_[Y2] - e_[X2] * e_[Y1], e_[X2] * e_[Y0] - e_[X0] * e_[Y2], e_[X0] * e_[Y1] - e_[X1] * e_[Y0] ) * invDet; }
//============================================================================== void DebugDrawer::drawSphere(F32 radius, I complexity) { #if 1 Mat4 oldMMat = m_mMat; Mat4 oldVpMat = m_vpMat; setModelMatrix(m_mMat * Mat4(Vec4(0.0, 0.0, 0.0, 1.0), Mat3::getIdentity(), radius)); begin(GL_LINES); // Pre-calculate the sphere points5 F32 fi = getPi<F32>() / complexity; Vec3 prev(1.0, 0.0, 0.0); for(F32 th = fi; th < getPi<F32>() * 2.0 + fi; th += fi) { Vec3 p = Mat3(Euler(0.0, th, 0.0)) * Vec3(1.0, 0.0, 0.0); for(F32 th2 = 0.0; th2 < getPi<F32>(); th2 += fi) { Mat3 rot(Euler(th2, 0.0, 0.0)); Vec3 rotPrev = rot * prev; Vec3 rotP = rot * p; pushBackVertex(rotPrev); pushBackVertex(rotP); Mat3 rot2(Euler(0.0, 0.0, getPi<F32>() / 2)); pushBackVertex(rot2 * rotPrev); pushBackVertex(rot2 * rotP); } prev = p; } end(); m_mMat = oldMMat; m_vpMat = oldVpMat; #endif }
Mat3 Mat3::lookAt( const Vec3 &look, const Vec3 &up ) { /* Finally, let s = f x UP', and u = s x f. | s[0] s[1] s[2] | M = | u[0] u[1] u[2] | | -f[0] -f[1] -f[2] | */ const Vec3 f = normalize(look); const Vec3 s = cross(f, normalize(up)); const Vec3 u = cross(s, f); Mat3 m = Mat3( s.x, s.y, s.z, u.x, u.y, u.z, -f.x, -f.y, -f.z); return m; }
inline Mat3 Mat3::operator -() const { return Mat3(-_11, -_12, -_13, -_21, -_22, -_23, -_31, -_32, -_33); }
inline Mat3 Mat3::operator +(const Mat3 & mat) const { return Mat3(_11 + mat._11, _12 + mat._12, _13 + mat._13, _21 + mat._21, _22 + mat._22, _23 + mat._23, _31 + mat._31, _32 + mat._32, _33 + mat._33); }
inline Mat3 Mat3::operator -(const Mat3 & mat) const { return Mat3(_11 - mat._11, _12 - mat._12, _13 - mat._13, _21 - mat._21, _22 - mat._22, _23 - mat._23, _31 - mat._31, _32 - mat._32, _33 - mat._33); }
Error Dbg::run(RenderingContext& ctx) { ANKI_ASSERT(m_enabled); if(!m_initialized) { ANKI_CHECK(lazyInit()); m_initialized = true; } CommandBufferPtr& cmdb = ctx.m_commandBuffer; cmdb->beginRenderPass(m_fb); cmdb->setViewport(0, 0, m_r->getWidth(), m_r->getHeight()); FrustumComponent& camFrc = *ctx.m_frustumComponent; SceneNode& cam = camFrc.getSceneNode(); m_drawer->prepareFrame(cmdb); m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix()); m_drawer->setModelMatrix(Mat4::getIdentity()); // m_drawer->drawGrid(); SceneGraph& scene = cam.getSceneGraph(); SceneDebugDrawer sceneDrawer(m_drawer); camFrc.getVisibilityTestResults().iterateAll([&](SceneNode& node) { if(&node == &cam) { return; } // Set position MoveComponent* mv = node.tryGetComponent<MoveComponent>(); if(mv) { m_drawer->setModelMatrix(Mat4(mv->getWorldTransform())); } else { m_drawer->setModelMatrix(Mat4::getIdentity()); } // Spatial if(m_flags.get(DbgFlag::SPATIAL_COMPONENT)) { Error err = node.iterateComponentsOfType<SpatialComponent>([&](SpatialComponent& sp) -> Error { sceneDrawer.draw(sp); return ErrorCode::NONE; }); (void)err; } // Frustum if(m_flags.get(DbgFlag::FRUSTUM_COMPONENT)) { Error err = node.iterateComponentsOfType<FrustumComponent>([&](FrustumComponent& frc) -> Error { if(&frc != &camFrc) { sceneDrawer.draw(frc); } return ErrorCode::NONE; }); (void)err; } // Sector/portal if(m_flags.get(DbgFlag::SECTOR_COMPONENT)) { Error err = node.iterateComponentsOfType<SectorComponent>([&](SectorComponent& psc) -> Error { sceneDrawer.draw(psc); return ErrorCode::NONE; }); err = node.iterateComponentsOfType<PortalComponent>([&](PortalComponent& psc) -> Error { sceneDrawer.draw(psc); return ErrorCode::NONE; }); (void)err; } // Decal if(m_flags.get(DbgFlag::DECAL_COMPONENT)) { Error err = node.iterateComponentsOfType<DecalComponent>([&](DecalComponent& psc) -> Error { sceneDrawer.draw(psc); return ErrorCode::NONE; }); (void)err; } }); if(m_flags.get(DbgFlag::PHYSICS)) { PhysicsDebugDrawer phyd(m_drawer); m_drawer->setModelMatrix(Mat4::getIdentity()); phyd.drawWorld(scene.getPhysicsWorld()); } #if 0 { m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix()); m_drawer->setModelMatrix(Mat4::getIdentity()); CollisionDebugDrawer cd(m_drawer); Mat4 proj = camFrc.getProjectionMatrix(); m_drawer->setViewProjectionMatrix(camFrc.getViewProjectionMatrix()); Sphere s(Vec4(1.2, 2.0, -1.1, 0.0), 2.1); s.accept(cd); Transform trf = scene.findSceneNode("light0").getComponent<MoveComponent>().getWorldTransform(); Vec4 rayOrigin = trf.getOrigin(); Vec3 rayDir = -trf.getRotation().getZAxis().getNormalized(); m_drawer->setModelMatrix(Mat4::getIdentity()); m_drawer->drawLine(rayOrigin.xyz(), rayOrigin.xyz() + rayDir.xyz() * 10.0, Vec4(1.0, 1.0, 1.0, 1.0)); Array<Vec4, 2> intersectionPoints; U intersectionPointCount; s.intersectsRay(rayDir.xyz0(), rayOrigin, intersectionPoints, intersectionPointCount); for(U i = 0; i < intersectionPointCount; ++i) { m_drawer->drawLine(Vec3(0.0), intersectionPoints[i].xyz(), Vec4(0.0, 1.0, 0.0, 1.0)); } } #endif #if 0 { Clusterer c; c.init(getAllocator(), 16, 12, 30); const FrustumComponent& frc = scene.findSceneNode("cam0").getComponent<FrustumComponent>(); const MoveComponent& movc = scene.findSceneNode("cam0").getComponent<MoveComponent>(); ClustererPrepareInfo pinf; pinf.m_viewMat = frc.getViewMatrix(); pinf.m_projMat = frc.getProjectionMatrix(); pinf.m_camTrf = frc.getFrustum().getTransform(); c.prepare(m_r->getThreadPool(), pinf); class DD : public ClustererDebugDrawer { public: DebugDrawer* m_d; void operator()(const Vec3& lineA, const Vec3& lineB, const Vec3& color) { m_d->drawLine(lineA, lineB, color.xyz1()); } }; DD dd; dd.m_d = m_drawer; CollisionDebugDrawer cd(m_drawer); Sphere s(Vec4(1.0, 0.1, -1.2, 0.0), 1.2); PerspectiveFrustum fr(toRad(25.), toRad(35.), 0.1, 5.); fr.transform(Transform(Vec4(0., 1., 0., 0.), Mat3x4::getIdentity(), 1.0)); m_drawer->setModelMatrix(Mat4(movc.getWorldTransform())); // c.debugDraw(dd); if(frc.getFrustum().insideFrustum(fr)) { ClustererTestResult rez; c.initTestResults(getAllocator(), rez); Aabb sbox; fr.computeAabb(sbox); c.binPerspectiveFrustum(fr, sbox, rez); //c.bin(s, sbox, rez); c.debugDrawResult(rez, dd); } m_drawer->setColor(Vec4(1.0, 1.0, 0.0, 1.0)); frc.getFrustum().accept(cd); fr.accept(cd); } #endif #if 0 { CollisionDebugDrawer cd(m_drawer); Array<Vec3, 4> poly; poly[0] = Vec3(0.0, 0.0, 0.0); poly[1] = Vec3(2.5, 0.0, 0.0); Mat4 trf(Vec4(147.392776, -12.132728, 16.607138, 1.0), Mat3(Euler(toRad(45.0), toRad(0.0), toRad(120.0))), 1.0); Array<Vec3, 4> polyw; polyw[0] = trf.transform(poly[0]); polyw[1] = trf.transform(poly[1]); m_drawer->setModelMatrix(Mat4::getIdentity()); m_drawer->drawLine(polyw[0], polyw[1], Vec4(1.0)); Vec4 p0 = camFrc.getViewMatrix() * polyw[0].xyz1(); p0.w() = 0.0; Vec4 p1 = camFrc.getViewMatrix() * polyw[1].xyz1(); p1.w() = 0.0; Vec4 r = p1 - p0; r.normalize(); Vec4 a = camFrc.getProjectionMatrix() * p0.xyz1(); a /= a.w(); Vec4 i; if(r.z() > 0) { // Plane near(Vec4(0, 0, -1, 0), camFrc.getFrustum().getNear() + // 0.001); // Bool in = near.intersectRay(p0, r * 100000.0, i); i.z() = -camFrc.getFrustum().getNear(); F32 t = (i.z() - p0.z()) / r.z(); i.x() = p0.x() + t * r.x(); i.y() = p0.y() + t * r.y(); i = camFrc.getProjectionMatrix() * i.xyz1(); i /= i.w(); } else { i = camFrc.getProjectionMatrix() * (r * 100000.0).xyz1(); i /= i.w(); } /*r *= 0.01; Vec4 b = polyw[0].xyz0() + r; b = camFrc.getViewProjectionMatrix() * b.xyz1(); Vec4 d = b / b.w();*/ m_drawer->setViewProjectionMatrix(Mat4::getIdentity()); m_drawer->drawLine( Vec3(a.xy(), 0.1), Vec3(i.xy(), 0.1), Vec4(1.0, 0, 0, 1)); } #endif m_drawer->finishFrame(); cmdb->endRenderPass(); return ErrorCode::NONE; }
Mat3 adjoint(const Mat3& m) { return Mat3(m[1]^m[2], m[2]^m[0], m[0]^m[1]); }
Mat3 diag(const Vec3& v) { return Mat3(Vec3(v[0],0,0), Vec3(0,v[1],0), Vec3(0,0,v[2])); }
Mat3 Mat3::I() { return Mat3(Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1)); }
/* Retrieves the upper 3x3 matrix of a 4x4 transformation matrix.*/ Mat3 upper3x3(const Mat4& m) { return Mat3(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, m.m21, m.m22); }