diff options
Diffstat (limited to 'PhysX_3.4/Samples/SampleBase/SampleCamera.cpp')
| -rw-r--r-- | PhysX_3.4/Samples/SampleBase/SampleCamera.cpp | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp b/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp new file mode 100644 index 00000000..c86d55dd --- /dev/null +++ b/PhysX_3.4/Samples/SampleBase/SampleCamera.cpp @@ -0,0 +1,481 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#include "SampleCamera.h" +#include "SampleUtils.h" +#include "RenderPhysX3Debug.h" +#include "RendererColor.h" + +using namespace SampleRenderer; + +// PT: the base camera code should be the same for all cameras, regardless of how +// the camera is controlled. For example this should deal with VFC, etc. + +Camera::Camera() : + mProjMatrix (degtorad(45.0f), 1.0f, 1.0f, 100.0f), + mFOV (0.0f), + mNearPlane (0.0f), + mFarPlane (0.0f), + mDirtyProj (true), + mDirtyView (true) +{ + mViewMatrix = PxTransform(PxIdentity); + mPos = PxVec3(0); + mRot = PxVec3(0); + + mDrawDebugData = false; + mFreezeFrustum = false; + mPerformVFC = true; +} + +Camera::~Camera() +{ +} + +// PT: TODO: copied from SampleApplication. Refactor. +static PxMat33 EulerToMat33(const PxVec3 &e) +{ + float c1 = cosf(e.z); + float s1 = sinf(e.z); + float c2 = cosf(e.y); + float s2 = sinf(e.y); + float c3 = cosf(e.x); + float s3 = sinf(e.x); + PxMat33 m(PxVec3(c1*c2, -s1*c2, s2), + PxVec3((s1*c3)+(c1*s2*s3), (c1*c3)-(s1*s2*s3),-c2*s3), + PxVec3((s1*s3)-(c1*s2*c3), (c1*s3)+(s1*s2*c3), c2*c3)); + + return m; +} + +void Camera::updateInternals() +{ + if(mDirtyProj) + { + mDirtyProj = false; + mProjMatrix = RendererProjection(degtorad(mFOV), mViewport.computeRatio(), mNearPlane, mFarPlane); + } + if(mDirtyView) + { + mDirtyView = false; + + mViewMatrix.q = PxQuat(EulerToMat33(mRot)); + mViewMatrix.p = mPos; + } +} + +PxVec3 Camera::getViewDir() const +{ + const PxTransform& camPose = getViewMatrix(); + PxVec3 forward = PxMat33(camPose.q)[2]; + return -forward; +} + +void Camera::lookAt(const PxVec3& position, const PxVec3& target) +{ + PxVec3 dir, right, up; + Ps::computeBasis(position, target, dir, right, up); + + PxTransform view; + view.p = position; + view.q = PxQuat(PxMat33(-right, up, -dir)); + setView(view); +} + + + enum FrustumPlaneIndex + { + FRUSTUM_PLANE_LEFT = 0, //!< Left clipping plane + FRUSTUM_PLANE_RIGHT = 1, //!< Right clipping plane + FRUSTUM_PLANE_TOP = 2, //!< Top clipping plane + FRUSTUM_PLANE_BOTTOM = 3, //!< Bottom clipping plane + FRUSTUM_PLANE_NEAR = 4, //!< Near clipping plane + FRUSTUM_PLANE_FAR = 5, //!< Far clipping plane (must be last for infinite far clip) + + FRUSTUM_PLANE_FORCE_DWORD = 0x7fffffff + }; + +static PxMat44 convertViewMatrix(const PxTransform& eye) +{ + PxTransform viewMatrix = eye.getInverse(); + PxMat44 mat44 = PxMat44(viewMatrix).getTranspose(); + + float m[16]; + memcpy(m, mat44.front(), sizeof m); + + PxMat44 view44; + view44.column0.x = m[0]; + view44.column0.y = m[1]; + view44.column0.z = m[2]; + view44.column0.w = m[3]; + view44.column1.x = m[4]; + view44.column1.y = m[5]; + view44.column1.z = m[6]; + view44.column1.w = m[7]; + view44.column2.x = m[8]; + view44.column2.y = m[9]; + view44.column2.z = m[10]; + view44.column2.w = m[11]; + view44.column3.x = m[12]; + view44.column3.y = m[13]; + view44.column3.z = m[14]; + view44.column3.w = m[15]; + +PxMat44 tmpmat = view44.getTranspose(); view44 = tmpmat; + + return view44; +} + +static PxMat44 convertProjMatrix(const RendererProjection& proj) +{ + float renderProjMatrix[16]; + proj.getColumnMajor44(renderProjMatrix); + + PxMat44 proj44; + proj44.column0.x = renderProjMatrix[0]; + proj44.column0.y = renderProjMatrix[1]; + proj44.column0.z = renderProjMatrix[2]; + proj44.column0.w = renderProjMatrix[3]; + proj44.column1.x = renderProjMatrix[4]; + proj44.column1.y = renderProjMatrix[5]; + proj44.column1.z = renderProjMatrix[6]; + proj44.column1.w = renderProjMatrix[7]; + proj44.column2.x = renderProjMatrix[8]; + proj44.column2.y = renderProjMatrix[9]; + proj44.column2.z = renderProjMatrix[10]; + proj44.column2.w = renderProjMatrix[11]; + proj44.column3.x = renderProjMatrix[12]; + proj44.column3.y = renderProjMatrix[13]; + proj44.column3.z = renderProjMatrix[14]; + proj44.column3.w = renderProjMatrix[15]; + +//PxMat44 tmpmat = proj44.getTranspose(); proj44 = tmpmat; + + return proj44; +} + +void Camera::BuildFrustum() +{ + if(mFreezeFrustum) + return; + + // PT: a better way is to extract the planes from the view-proj matrix but it has some subtle differences with D3D/GL. + // Building the frustum explicitly is just easier here (although not as efficient) + + const PxReal ratio = mViewport.computeRatio(); + + const PxReal Tan = tanf(degtorad(0.5f * mFOV)) / ratio; + + const PxReal nearCoeff = mNearPlane * Tan; + const PxReal farCoeff = mFarPlane * Tan; + + const PxReal rightCoeff = ratio; + const PxReal upCoeff = 1.0f; + + const PxTransform& view = getViewMatrix(); + PxMat33 mat33(view.q); + PxVec3 right = mat33[0]; + PxVec3 up = mat33[1]; + PxVec3 forward =-mat33[2]; + + mFrustum[0] = mPos + forward*mNearPlane - right*nearCoeff*rightCoeff + up*nearCoeff*upCoeff; + mFrustum[1] = mPos + forward*mNearPlane - right*nearCoeff*rightCoeff - up*nearCoeff*upCoeff; + mFrustum[2] = mPos + forward*mNearPlane + right*nearCoeff*rightCoeff - up*nearCoeff*upCoeff; + mFrustum[3] = mPos + forward*mNearPlane + right*nearCoeff*rightCoeff + up*nearCoeff*upCoeff; + + mFrustum[4] = mPos + forward*mFarPlane - right*farCoeff*rightCoeff + up*farCoeff*upCoeff; + mFrustum[5] = mPos + forward*mFarPlane - right*farCoeff*rightCoeff - up*farCoeff*upCoeff; + mFrustum[6] = mPos + forward*mFarPlane + right*farCoeff*rightCoeff - up*farCoeff*upCoeff; + mFrustum[7] = mPos + forward*mFarPlane + right*farCoeff*rightCoeff + up*farCoeff*upCoeff; + + if(1) + { + mPlanes[0] = PxPlane(mFrustum[4], mFrustum[1], mFrustum[5]); + mPlanes[1] = PxPlane(mFrustum[6], mFrustum[3], mFrustum[7]); + mPlanes[2] = PxPlane(mFrustum[4], mFrustum[7], mFrustum[3]); + mPlanes[3] = PxPlane(mFrustum[1], mFrustum[6], mFrustum[5]); + mPlanes[4] = PxPlane(mFrustum[0], mFrustum[2], mFrustum[1]); + mPlanes[5] = PxPlane(mFrustum[5], mFrustum[7], mFrustum[4]); + + { + for(int i=0;i<6;i++) + { + mPlanes[i].n = -mPlanes[i].n; + mPlanes[i].d = -mPlanes[i].d; + } + } + } + + if(0) + { + // + const PxVec3 axisX(1.0f, 0.0f, 0.0f); + const PxVec3 axisY(0.0f, 1.0f, 0.0f); + const PxVec3 axisZ(0.0f, 0.0f, 1.0f); + + PxQuat RotX(degtorad(0.5f * mFOV), axisX); + PxQuat RotY(degtorad(0.5f * mFOV), axisY); + PxQuat RotZ(degtorad(0.5f * mFOV), axisZ); + + PxVec3 tmp1 = RotY.rotate(-axisX); + PxVec3 tmp11 = view.q.rotate(tmp1); // Plane0 + mPlanes[0].n = tmp11; + mPlanes[0].d = - mPos.dot(mPlanes[0].n); + // + + RotY = PxQuat(-degtorad(0.5f * mFOV), axisY); + + PxVec3 tmpy = RotY.rotate(axisX); + PxVec3 tmpyy = view.q.rotate(tmpy); // Plane1 + mPlanes[1].n = tmpyy; + mPlanes[1].d = - mPos.dot(mPlanes[1].n); + + // + + RotX = PxQuat(degtorad(0.5f * mFOV)/ratio, axisX); + PxVec3 tmpx = RotX.rotate(axisY); + PxVec3 tmpxx = view.q.rotate(tmpx); // Plane2? + mPlanes[2].n = tmpxx; + mPlanes[2].d = - mPos.dot(mPlanes[2].n); + + // + + RotX = PxQuat(-degtorad(0.5f * mFOV)/ratio, axisX); + tmpx = RotX.rotate(axisY); + tmpxx = view.q.rotate(tmpx); // -Plane3? + mPlanes[3].n = -tmpxx; + mPlanes[3].d = - mPos.dot(mPlanes[3].n); + + // + + mPlanes[4].n = -forward; + mPlanes[4].d = - (mPos.dot(mPlanes[4].n) + forward.dot(mPlanes[4].n)*mNearPlane); + + mPlanes[5].n = forward; + mPlanes[5].d = - (mPos.dot(mPlanes[5].n) + forward.dot(mPlanes[5].n)*mFarPlane); + } + + + if(0) + { + PxMat44 proj44 = convertProjMatrix(mProjMatrix); + PxMat44 view44 = convertViewMatrix(view); +// PxMat44 combo44 = view44 * proj44; + PxMat44 combo44 = proj44 * view44; + + PxReal combo[4][4]; + PxReal* dst = &combo[0][0]; + memcpy(dst, &combo44, sizeof(PxReal)*16); + + // D3D: + // -w' < x' < w' + // -w' < y' < w' + // 0 < z' < w' + // + // GL: + // -w' < x' < w' + // -w' < y' < w' + // -w' < z' < w' + + // Left clipping plane + mPlanes[FRUSTUM_PLANE_LEFT].n.x = -(combo[0][3] + combo[0][0]); + mPlanes[FRUSTUM_PLANE_LEFT].n.y = -(combo[1][3] + combo[1][0]); + mPlanes[FRUSTUM_PLANE_LEFT].n.z = -(combo[2][3] + combo[2][0]); + mPlanes[FRUSTUM_PLANE_LEFT].d = -(combo[3][3] + combo[3][0]); + + // Right clipping plane + mPlanes[FRUSTUM_PLANE_RIGHT].n.x = -(combo[0][3] - combo[0][0]); + mPlanes[FRUSTUM_PLANE_RIGHT].n.y = -(combo[1][3] - combo[1][0]); + mPlanes[FRUSTUM_PLANE_RIGHT].n.z = -(combo[2][3] - combo[2][0]); + mPlanes[FRUSTUM_PLANE_RIGHT].d = -(combo[3][3] - combo[3][0]); + + // Top clipping plane + mPlanes[FRUSTUM_PLANE_TOP].n.x = -(combo[0][3] - combo[0][1]); + mPlanes[FRUSTUM_PLANE_TOP].n.y = -(combo[1][3] - combo[1][1]); + mPlanes[FRUSTUM_PLANE_TOP].n.z = -(combo[2][3] - combo[2][1]); + mPlanes[FRUSTUM_PLANE_TOP].d = -(combo[3][3] - combo[3][1]); + + // Bottom clipping plane + mPlanes[FRUSTUM_PLANE_BOTTOM].n.x = -(combo[0][3] + combo[0][1]); + mPlanes[FRUSTUM_PLANE_BOTTOM].n.y = -(combo[1][3] + combo[1][1]); + mPlanes[FRUSTUM_PLANE_BOTTOM].n.z = -(combo[2][3] + combo[2][1]); + mPlanes[FRUSTUM_PLANE_BOTTOM].d = -(combo[3][3] + combo[3][1]); + + // Near clipping plane + if(1) + { + // OpenGL path + mPlanes[FRUSTUM_PLANE_NEAR].n.x = -(combo[0][3] + combo[0][2]); + mPlanes[FRUSTUM_PLANE_NEAR].n.y = -(combo[1][3] + combo[1][2]); + mPlanes[FRUSTUM_PLANE_NEAR].n.z = -(combo[2][3] + combo[2][2]); + mPlanes[FRUSTUM_PLANE_NEAR].d = -(combo[3][3] + combo[3][2]); + } + else + { + // D3D path + mPlanes[FRUSTUM_PLANE_NEAR].n.x = - combo[0][2]; + mPlanes[FRUSTUM_PLANE_NEAR].n.y = - combo[1][2]; + mPlanes[FRUSTUM_PLANE_NEAR].n.z = - combo[2][2]; + mPlanes[FRUSTUM_PLANE_NEAR].d = - combo[3][2]; + } + + // Far clipping plane (must be last for infinite far clip) + mPlanes[FRUSTUM_PLANE_FAR].n.x = -(combo[0][3] - combo[0][2]); + mPlanes[FRUSTUM_PLANE_FAR].n.y = -(combo[1][3] - combo[1][2]); + mPlanes[FRUSTUM_PLANE_FAR].n.z = -(combo[2][3] - combo[2][2]); + mPlanes[FRUSTUM_PLANE_FAR].d = -(combo[3][3] - combo[3][2]); + + // Normalize if needed + for(PxU32 i=0;i<6;i++) + { +// mPlanes[i].normalize(); + mPlanes[i].n.normalize(); +// mPlanes[i].normal = -mPlanes[i].normal; +// mPlanes[i].d = -mPlanes[i].d; + mPlanes[i].d *= 0.5f; + } + } +} + + // Following code from Umbra/dPVS. + + //------------------------------------------------------------------------ + // + // Function: DPVS::intersectAABBFrustum() + // + // Description: Determines whether an AABB intersects a frustum + // + // Parameters: a = reference to AABB (defined by minimum & maximum vectors) + // p = array of pre-normalized clipping planes + // outClipMask = output clip mask (if function returns 'true') + // inClipMask = input clip mask (indicates which planes are active) + // + // Returns: true if AABB intersects the frustum, false otherwise + // + // Intersection of AABB and a frustum. The frustum may + // contain 0-32 planes (active planes are defined by inClipMask). + // If AABB intersects the frustum, an output clip mask is returned + // as well (indicating which planes are crossed by the AABB). This + // information can be used to optimize testing of child nodes or + // objects inside the nodes (pass value as 'inClipMask' next time). + // + // This is a variant of the classic "fast" AABB/frustum + // intersection tester. AABBs that are not culled away by any single + // plane are classified as "intersecting" even though the AABB may + // actually be outside the convex volume formed by the planes. + //------------------------------------------------------------------------ + +static PX_FORCE_INLINE bool planesAABBOverlap(const PxBounds3& a, const PxPlane* p, PxU32& out_clip_mask, PxU32 in_clip_mask) + { + //------------------------------------------------------------------------ + // Convert the AABB from (minimum,maximum) form into (center,half-diagonal). + // Note that we could get rid of these six subtractions and three + // multiplications if the AABB was originally expressed in (center, + // half-diagonal) form. + //------------------------------------------------------------------------ + + PxVec3 m = a.getCenter(); // get center of AABB ((minimum+maximum)*0.5f) + PxVec3 d = a.maximum; d-=m; // get positive half-diagonal (maximum - center) + + //------------------------------------------------------------------------ + // Evaluate through all active frustum planes. We determine the relation + // between the AABB and a plane by using the concept of "near" and "far" + // vertices originally described by Zhang (and later by Moeller). Our + // variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point + // comparisons per plane. The routine early-exits if the AABB is found + // to be outside any of the planes. The loop also constructs a new output + // clip mask. Most FPUs have a native single-cycle fabsf() operation. + //------------------------------------------------------------------------ + + PxU32 Mask = 1; // current mask index (1,2,4,8,..) + PxU32 TmpOutClipMask = 0; // initialize output clip mask into empty. + + while(Mask<=in_clip_mask) // keep looping while we have active planes left... + { + if(in_clip_mask & Mask) // if clip plane is active, process it.. + { + const float NP = d.x*PxAbs(p->n.x) + d.y*PxAbs(p->n.y) + d.z*PxAbs(p->n.z); + const float MP = m.x*p->n.x + m.y*p->n.y + m.z*p->n.z + p->d; + + if(NP < MP) // near vertex behind the clip plane... + return false; // .. so there is no intersection.. + if((-NP) < MP) // near and far vertices on different sides of plane.. + TmpOutClipMask |= Mask; // .. so update the clip mask... + } + Mask+=Mask; // mk = (1<<plane) + p++; // advance to next plane + } + + out_clip_mask = TmpOutClipMask; // copy output value (temp used to resolve aliasing!) + return true; // indicate that AABB intersects frustum + } + +PlaneAABBCode Camera::cull(const PxBounds3& aabb) const +{ + const PxU32 nbFrustumPlanes = 6; // PT: can sometimes be 5 with infinite far clip plane + const PxU32 frustumPlanesMask = (1<<nbFrustumPlanes)-1; + + PxU32 outClipMask; + if(!planesAABBOverlap(aabb, mPlanes, outClipMask, frustumPlanesMask)) + return PLANEAABB_EXCLUSION; + + if(outClipMask) + return PLANEAABB_INTERSECT; + + return PLANEAABB_INCLUSION; +} + +void Camera::drawDebug(RenderPhysX3Debug* debug) +{ + if(mDrawDebugData) + { +/* for(PxU32 i=0;i<8;i++) + { + debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(1,0,0), RendererColor(255,0,0)); + debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(0,1,0), RendererColor(0, 255,0)); + debug->addLine(mFrustum[i], mFrustum[i]+PxVec3(0,0,1), RendererColor(0, 0, 255)); + }*/ + + const RendererColor lineColor(255, 255, 0); + debug->addLine(mFrustum[0], mFrustum[1], lineColor); + debug->addLine(mFrustum[1], mFrustum[2], lineColor); + debug->addLine(mFrustum[2], mFrustum[3], lineColor); + debug->addLine(mFrustum[3], mFrustum[0], lineColor); + + debug->addLine(mFrustum[4], mFrustum[5], lineColor); + debug->addLine(mFrustum[5], mFrustum[6], lineColor); + debug->addLine(mFrustum[6], mFrustum[7], lineColor); + debug->addLine(mFrustum[7], mFrustum[4], lineColor); + + debug->addLine(mFrustum[0], mFrustum[4], lineColor); + debug->addLine(mFrustum[3], mFrustum[7], lineColor); + debug->addLine(mFrustum[1], mFrustum[5], lineColor); + debug->addLine(mFrustum[6], mFrustum[2], lineColor); + } +} |