Added the ability to do accurate raycasts against billboards
This commit is contained in:
parent
1fedc8f616
commit
373426a98f
|
@ -1,7 +1,8 @@
|
|||
#include "CQuaternion.h"
|
||||
#include <cmath>
|
||||
#include <math.h>
|
||||
#include <Common/Math.h>
|
||||
#include "Math.h"
|
||||
#include "CMatrix4f.h"
|
||||
|
||||
CQuaternion::CQuaternion()
|
||||
{
|
||||
|
@ -137,5 +138,58 @@ CQuaternion CQuaternion::FromAxisAngle(float angle, CVector3f axis)
|
|||
|
||||
}
|
||||
|
||||
CQuaternion CQuaternion::FromRotationMatrix(const CMatrix4f& RotMtx)
|
||||
{
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||
CQuaternion out;
|
||||
float trace = RotMtx[0][0] + RotMtx[1][1] + RotMtx[2][2];
|
||||
|
||||
if (trace > 0.f)
|
||||
{
|
||||
float s = Math::Sqrt(trace + 1.f) * 2; // s = 4*w
|
||||
out.w = 0.25f * s;
|
||||
out.x = (RotMtx[2][1] - RotMtx[1][2]) / s;
|
||||
out.y = (RotMtx[0][2] - RotMtx[2][0]) / s;
|
||||
out.z = (RotMtx[1][0] - RotMtx[0][1]) / s;
|
||||
}
|
||||
|
||||
else if ((RotMtx[0][0] > RotMtx[1][1]) && (RotMtx[0][0] > RotMtx[2][2]))
|
||||
{
|
||||
float s = Math::Sqrt(1.f + RotMtx[0][0] - RotMtx[1][1] - RotMtx[2][2]) * 2; // s = 4*x
|
||||
out.w = (RotMtx[2][1] - RotMtx[1][2]) / s;
|
||||
out.x = 0.25f * s;
|
||||
out.y = (RotMtx[0][1] + RotMtx[1][0]) / s;
|
||||
out.z = (RotMtx[0][2] + RotMtx[2][0]) / s;
|
||||
}
|
||||
|
||||
else if (RotMtx[1][1] > RotMtx[2][2]) {
|
||||
float s = Math::Sqrt(1.f + RotMtx[1][1] - RotMtx[0][0] - RotMtx[2][2]) * 2; // s = 4*y
|
||||
out.w = (RotMtx[0][2] - RotMtx[2][0]) / s;
|
||||
out.x = (RotMtx[0][1] + RotMtx[1][0]) / s;
|
||||
out.y = 0.25f * s;
|
||||
out.z = (RotMtx[1][2] + RotMtx[2][1]) / s;
|
||||
}
|
||||
|
||||
else {
|
||||
float s = Math::Sqrt(1.f + RotMtx[2][2] - RotMtx[0][0] - RotMtx[1][1]) * 2; // S=4*qz
|
||||
out.w = (RotMtx[1][0] - RotMtx[0][1]) / s;
|
||||
out.x = (RotMtx[0][2] + RotMtx[2][0]) / s;
|
||||
out.y = (RotMtx[1][2] + RotMtx[2][1]) / s;
|
||||
out.z = 0.25f * s;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
CQuaternion CQuaternion::FromAxes(const CVector3f& X, const CVector3f& Y, const CVector3f& Z)
|
||||
{
|
||||
CMatrix4f RotMtx(X.x, Y.x, Z.x, 0.f,
|
||||
X.y, Y.y, Z.y, 0.f,
|
||||
X.z, Y.z, Z.z, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
return CQuaternion::FromRotationMatrix(RotMtx);
|
||||
}
|
||||
|
||||
CQuaternion CQuaternion::skIdentity = CQuaternion(1.f, 0.f, 0.f, 0.f);
|
||||
CQuaternion CQuaternion::skZero = CQuaternion(0.f, 0.f, 0.f, 0.f);
|
||||
|
|
|
@ -25,6 +25,8 @@ public:
|
|||
// Static
|
||||
static CQuaternion FromEuler(CVector3f euler);
|
||||
static CQuaternion FromAxisAngle(float angle, CVector3f axis);
|
||||
static CQuaternion FromRotationMatrix(const CMatrix4f& RotMtx);
|
||||
static CQuaternion FromAxes(const CVector3f& X, const CVector3f& Y, const CVector3f& Z);
|
||||
|
||||
static CQuaternion skIdentity;
|
||||
static CQuaternion skZero;
|
||||
|
|
|
@ -19,7 +19,7 @@ void CRayCollisionTester::AddNode(CSceneNode *pNode, u32 AssetIndex, float Dista
|
|||
Intersection.Distance = Distance;
|
||||
}
|
||||
|
||||
SRayIntersection CRayCollisionTester::TestNodes(ERenderOptions options)
|
||||
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& ViewInfo)
|
||||
{
|
||||
// Sort nodes by distance from ray
|
||||
mBoxIntersectList.sort(
|
||||
|
@ -43,7 +43,7 @@ SRayIntersection CRayCollisionTester::TestNodes(ERenderOptions options)
|
|||
|
||||
// Otherwise, more intersection tests...
|
||||
CSceneNode *pNode = Intersection.pNode;
|
||||
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex, options);
|
||||
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex, ViewInfo);
|
||||
|
||||
if (MidResult.Hit)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "CVector3f.h"
|
||||
#include "SRayIntersection.h"
|
||||
#include "types.h"
|
||||
#include <Core/ERenderOptions.h>
|
||||
#include <Core/SViewInfo.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
|
@ -22,7 +22,7 @@ public:
|
|||
~CRayCollisionTester();
|
||||
const CRay& Ray() const;
|
||||
void AddNode(CSceneNode *pNode, u32 AssetIndex, float Distance);
|
||||
SRayIntersection TestNodes(ERenderOptions options);
|
||||
SRayIntersection TestNodes(const SViewInfo& ViewInfo);
|
||||
};
|
||||
|
||||
inline const CRay& CRayCollisionTester::Ray() const
|
||||
|
|
|
@ -15,6 +15,11 @@ float Pow(float Base, float Exponent)
|
|||
return pow(Base, Exponent);
|
||||
}
|
||||
|
||||
float Sqrt(float v)
|
||||
{
|
||||
return sqrtf(v);
|
||||
}
|
||||
|
||||
float Distance(const CVector3f& A, const CVector3f& B)
|
||||
{
|
||||
return sqrtf( Pow(B.x - A.x, 2.f) +
|
||||
|
|
|
@ -15,6 +15,8 @@ float Abs(float v);
|
|||
|
||||
float Pow(float Base, float Exponent);
|
||||
|
||||
float Sqrt(float v);
|
||||
|
||||
float Distance(const CVector3f& A, const CVector3f& B);
|
||||
|
||||
float DegreesToRadians(float deg);
|
||||
|
|
|
@ -163,13 +163,6 @@ void CCamera::LoadMatrices()
|
|||
CGraphics::UpdateMVPBlock();
|
||||
}
|
||||
|
||||
void CCamera::LoadRotationOnlyMatrices()
|
||||
{
|
||||
CGraphics::sMVPBlock.ViewMatrix = RotationOnlyViewMatrix();
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
|
||||
CGraphics::UpdateMVPBlock();
|
||||
}
|
||||
|
||||
// ************ GETTERS ************
|
||||
CVector3f CCamera::Position() const
|
||||
{
|
||||
|
@ -181,6 +174,16 @@ CVector3f CCamera::Direction() const
|
|||
return mDirection;
|
||||
}
|
||||
|
||||
CVector3f CCamera::UpVector() const
|
||||
{
|
||||
return mUpVector;
|
||||
}
|
||||
|
||||
CVector3f CCamera::RightVector() const
|
||||
{
|
||||
return mRightVector;
|
||||
}
|
||||
|
||||
float CCamera::Yaw() const
|
||||
{
|
||||
return mYaw;
|
||||
|
@ -204,17 +207,6 @@ const CMatrix4f& CCamera::ViewMatrix()
|
|||
return mCachedViewMatrix;
|
||||
}
|
||||
|
||||
CMatrix4f CCamera::RotationOnlyViewMatrix()
|
||||
{
|
||||
if (mViewOutdated)
|
||||
CalculateView();
|
||||
|
||||
return CMatrix4f(mCachedViewMatrix[0][0], mCachedViewMatrix[0][1], mCachedViewMatrix[0][2], 0.f,
|
||||
mCachedViewMatrix[1][0], mCachedViewMatrix[1][1], mCachedViewMatrix[1][2], 0.f,
|
||||
mCachedViewMatrix[2][0], mCachedViewMatrix[2][1], mCachedViewMatrix[2][2], 0.f,
|
||||
mCachedViewMatrix[3][0], mCachedViewMatrix[3][1], mCachedViewMatrix[3][2], 1.f);
|
||||
}
|
||||
|
||||
const CMatrix4f& CCamera::ProjectionMatrix()
|
||||
{
|
||||
if (mProjectionOutdated)
|
||||
|
@ -295,6 +287,14 @@ void CCamera::CalculateDirection()
|
|||
cos(mPitch) * sin(mYaw),
|
||||
sin(mPitch)
|
||||
);
|
||||
|
||||
mRightVector = CVector3f(
|
||||
cos(mYaw - Math::skHalfPi),
|
||||
sin(mYaw - Math::skHalfPi),
|
||||
0
|
||||
);
|
||||
|
||||
mUpVector = mRightVector.Cross(mDirection);
|
||||
}
|
||||
|
||||
void CCamera::CalculateView()
|
||||
|
@ -302,17 +302,9 @@ void CCamera::CalculateView()
|
|||
// todo: don't use glm
|
||||
CalculateDirection();
|
||||
|
||||
CVector3f Right(
|
||||
cos(mYaw - Math::skHalfPi),
|
||||
sin(mYaw - Math::skHalfPi),
|
||||
0
|
||||
);
|
||||
|
||||
CVector3f Up = Right.Cross(mDirection);
|
||||
|
||||
glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z);
|
||||
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z);
|
||||
glm::vec3 glmup(Up.x, Up.y, Up.z);
|
||||
glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z);
|
||||
mCachedViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
|
||||
mViewOutdated = false;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ class CCamera
|
|||
ECameraMoveMode mMode;
|
||||
CVector3f mPosition;
|
||||
CVector3f mDirection;
|
||||
CVector3f mRightVector;
|
||||
CVector3f mUpVector;
|
||||
float mAspectRatio;
|
||||
|
||||
float mYaw;
|
||||
|
@ -48,16 +50,16 @@ public:
|
|||
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
|
||||
CRay CastRay(CVector2f DeviceCoords);
|
||||
void LoadMatrices();
|
||||
void LoadRotationOnlyMatrices();
|
||||
|
||||
// Getters
|
||||
CVector3f Position() const;
|
||||
CVector3f Direction() const;
|
||||
CVector3f UpVector() const;
|
||||
CVector3f RightVector() const;
|
||||
float Yaw() const;
|
||||
float Pitch() const;
|
||||
float FieldOfView() const;
|
||||
const CMatrix4f& ViewMatrix();
|
||||
CMatrix4f RotationOnlyViewMatrix();
|
||||
const CMatrix4f& ProjectionMatrix();
|
||||
const CFrustumPlanes& FrustumPlanes();
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ void CRenderBucket::Add(const SRenderablePtr& ptr)
|
|||
mSize++;
|
||||
}
|
||||
|
||||
void CRenderBucket::Sort(CCamera& Camera)
|
||||
void CRenderBucket::Sort(CCamera* pCamera)
|
||||
{
|
||||
struct {
|
||||
CCamera *pCamera;
|
||||
|
@ -39,7 +39,7 @@ void CRenderBucket::Sort(CCamera& Camera)
|
|||
return (dotL > dotR);
|
||||
}
|
||||
} backToFront;
|
||||
backToFront.pCamera = &Camera;
|
||||
backToFront.pCamera = pCamera;
|
||||
|
||||
if (mSortType == BackToFront)
|
||||
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize, backToFront);
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
CRenderBucket();
|
||||
void SetSortType(ESortType Type);
|
||||
void Add(const SRenderablePtr& ptr);
|
||||
void Sort(CCamera& Camera);
|
||||
void Sort(CCamera* pCamera);
|
||||
void Clear();
|
||||
void Draw(ERenderOptions Options);
|
||||
};
|
||||
|
|
|
@ -54,7 +54,7 @@ void CRenderer::Init()
|
|||
}
|
||||
|
||||
// ************ GETTERS/SETTERS ************
|
||||
ERenderOptions CRenderer::RenderOptions()
|
||||
ERenderOptions CRenderer::RenderOptions() const
|
||||
{
|
||||
return mOptions;
|
||||
}
|
||||
|
@ -159,11 +159,10 @@ void CRenderer::SetViewportSize(u32 Width, u32 Height)
|
|||
}
|
||||
|
||||
// ************ RENDER ************
|
||||
void CRenderer::RenderBuckets(CCamera& Camera)
|
||||
void CRenderer::RenderBuckets(const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mInitialized) Init();
|
||||
mSceneFramebuffer.Bind();
|
||||
//Camera.LoadMatrices();
|
||||
|
||||
// Set backface culling
|
||||
if (mOptions & eEnableBackfaceCull) glEnable(GL_CULL_FACE);
|
||||
|
@ -175,7 +174,7 @@ void CRenderer::RenderBuckets(CCamera& Camera)
|
|||
|
||||
mOpaqueBucket.Draw(mOptions);
|
||||
mOpaqueBucket.Clear();
|
||||
mTransparentBucket.Sort(Camera);
|
||||
mTransparentBucket.Sort(ViewInfo.pCamera);
|
||||
mTransparentBucket.Draw(mOptions);
|
||||
mTransparentBucket.Clear();
|
||||
}
|
||||
|
@ -288,7 +287,7 @@ void CRenderer::RenderBloom()
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void CRenderer::RenderSky(CModel *pSkyboxModel, CCamera& Camera)
|
||||
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mInitialized) Init();
|
||||
if (!pSkyboxModel) return;
|
||||
|
@ -302,7 +301,10 @@ void CRenderer::RenderSky(CModel *pSkyboxModel, CCamera& Camera)
|
|||
CGraphics::UpdateVertexBlock();
|
||||
CGraphics::UpdatePixelBlock();
|
||||
CGraphics::UpdateLightBlock();
|
||||
Camera.LoadRotationOnlyMatrices();
|
||||
|
||||
// Load rotation-only view matrix
|
||||
CGraphics::sMVPBlock.ViewMatrix = ViewInfo.RotationOnlyViewMatrix;
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
glDepthRange(1.f, 1.f);
|
||||
pSkyboxModel->Draw(mOptions, 0);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "ERenderOptions.h"
|
||||
#include "ERenderCommand.h"
|
||||
#include "SRenderablePtr.h"
|
||||
#include "SViewInfo.h"
|
||||
#include <Common/CAABox.h>
|
||||
#include <Common/CColor.h>
|
||||
#include <Common/CMatrix4f.h>
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
void Init();
|
||||
|
||||
// Getters/Setters
|
||||
ERenderOptions RenderOptions();
|
||||
ERenderOptions RenderOptions() const;
|
||||
void ToggleWorld(bool b);
|
||||
void ToggleWorldCollision(bool b);
|
||||
void ToggleObjects(bool b);
|
||||
|
@ -71,9 +72,9 @@ public:
|
|||
void SetViewportSize(u32 Width, u32 Height);
|
||||
|
||||
// Render
|
||||
void RenderBuckets(CCamera& Camera);
|
||||
void RenderBuckets(const SViewInfo& ViewInfo);
|
||||
void RenderBloom();
|
||||
void RenderSky(CModel *pSkyboxModel, CCamera& Camera);
|
||||
void RenderSky(CModel *pSkyboxModel, const SViewInfo& ViewInfo);
|
||||
void AddOpaqueMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
|
||||
void AddTransparentMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
|
||||
void BeginFrame();
|
||||
|
|
|
@ -215,48 +215,50 @@ void CSceneManager::ClearScene()
|
|||
mNodeCount = 0;
|
||||
}
|
||||
|
||||
void CSceneManager::AddSceneToRenderer(CRenderer *pRenderer, CCamera& camera)
|
||||
void CSceneManager::AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
ERenderOptions options = pRenderer->RenderOptions();
|
||||
ERenderOptions Options = pRenderer->RenderOptions();
|
||||
|
||||
if (options & eDrawWorld)
|
||||
if (Options & eDrawWorld)
|
||||
{
|
||||
for (u32 n = 0; n < mModelNodes.size(); n++)
|
||||
if (mModelNodes[n]->IsVisible())
|
||||
mModelNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
||||
mModelNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||
|
||||
for (u32 n = 0; n < mStaticNodes.size(); n++)
|
||||
if (mStaticNodes[n]->IsVisible())
|
||||
mStaticNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
||||
mStaticNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||
}
|
||||
|
||||
if (options & eDrawWorldCollision)
|
||||
if (Options & eDrawWorldCollision)
|
||||
{
|
||||
for (u32 n = 0; n < mCollisionNodes.size(); n++)
|
||||
if (mCollisionNodes[n]->IsVisible())
|
||||
mCollisionNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
||||
mCollisionNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||
}
|
||||
|
||||
if (options & eDrawLights)
|
||||
if (Options & eDrawLights)
|
||||
{
|
||||
for (u32 n = 0; n < mLightNodes.size(); n++)
|
||||
if (mLightNodes[n]->IsVisible())
|
||||
mLightNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
||||
mLightNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||
}
|
||||
|
||||
if ((options & eDrawObjects) || (options & eDrawObjectCollision))
|
||||
if ((Options & eDrawObjects) || (Options & eDrawObjectCollision))
|
||||
{
|
||||
for (u32 n = 0; n < mScriptNodes.size(); n++)
|
||||
if (mScriptNodes[n]->IsVisible())
|
||||
mScriptNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
||||
mScriptNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray, ERenderOptions renderOptions)
|
||||
SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo)
|
||||
{
|
||||
// Terribly hacky stuff to avoid having tons of redundant code
|
||||
// because I'm too lazy to rewrite CSceneManager right now and fix it
|
||||
// (I'm probably going to do it soon...)
|
||||
ERenderOptions renderOptions = ViewInfo.pRenderer->RenderOptions();
|
||||
|
||||
std::vector<CSceneNode*> *pNodeVectors[5] = {
|
||||
reinterpret_cast<std::vector<CSceneNode*>*>(&mModelNodes),
|
||||
reinterpret_cast<std::vector<CSceneNode*>*>(&mStaticNodes),
|
||||
|
@ -283,7 +285,7 @@ SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray, ERenderOptions ren
|
|||
vec[iNode]->RayAABoxIntersectTest(Tester);
|
||||
}
|
||||
|
||||
return Tester.TestNodes(renderOptions);
|
||||
return Tester.TestNodes(ViewInfo);
|
||||
}
|
||||
|
||||
void CSceneManager::PickEnvironmentObjects()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "CAreaAttributes.h"
|
||||
#include "CRenderer.h"
|
||||
#include "SViewInfo.h"
|
||||
#include <Common/SRayIntersection.h>
|
||||
#include <Common/types.h>
|
||||
#include <Scene/CSceneNode.h>
|
||||
|
@ -57,8 +58,8 @@ public:
|
|||
void SetActiveArea(CGameArea *_area);
|
||||
void SetActiveWorld(CWorld *_world);
|
||||
void ClearScene();
|
||||
void AddSceneToRenderer(CRenderer *pRenderer, CCamera& camera);
|
||||
SRayIntersection SceneRayCast(const CRay& Ray, ERenderOptions renderOptions);
|
||||
void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
SRayIntersection SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo);
|
||||
void PickEnvironmentObjects();
|
||||
CScriptNode* ScriptNodeByID(u32 InstanceID);
|
||||
CScriptNode* NodeForObject(CScriptObject *pObj);
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
#define IRENDERABLE_H
|
||||
|
||||
#include "ERenderOptions.h"
|
||||
#include <Common/CAABox.h>
|
||||
#include "SViewInfo.h"
|
||||
#include <Common/types.h>
|
||||
#include <Core/CFrustumPlanes.h>
|
||||
|
||||
class CRenderer;
|
||||
|
||||
|
@ -13,7 +12,7 @@ class IRenderable
|
|||
public:
|
||||
IRenderable() {}
|
||||
virtual ~IRenderable() {}
|
||||
virtual void AddToRenderer(CRenderer* pRenderer, const CFrustumPlanes& frustum) = 0;
|
||||
virtual void AddToRenderer(CRenderer* pRenderer, const SViewInfo& ViewInfo) = 0;
|
||||
virtual void Draw(ERenderOptions /*options*/) {}
|
||||
virtual void DrawAsset(ERenderOptions /*options*/, u32 /*asset*/) {}
|
||||
virtual void DrawSelection() {}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef SVIEWINFO
|
||||
#define SVIEWINFO
|
||||
|
||||
#include "CFrustumPlanes.h"
|
||||
#include <Common/CMatrix4f.h>
|
||||
#include <Common/CRay.h>
|
||||
|
||||
struct SViewInfo
|
||||
{
|
||||
class CSceneManager *pScene;
|
||||
class CRenderer *pRenderer;
|
||||
|
||||
class CCamera *pCamera;
|
||||
CFrustumPlanes ViewFrustum;
|
||||
CMatrix4f RotationOnlyViewMatrix;
|
||||
};
|
||||
|
||||
#endif // SVIEWINFO
|
||||
|
|
@ -113,7 +113,6 @@ SOURCES += \
|
|||
Resource/model/SSurface.cpp \
|
||||
Common/CRayCollisionTester.cpp \
|
||||
Common/Math.cpp \
|
||||
Scene/CBoundingBoxNode.cpp \
|
||||
Core/Log.cpp \
|
||||
Common/CVector2i.cpp \
|
||||
UI/CNodeSelection.cpp \
|
||||
|
@ -273,7 +272,6 @@ HEADERS += \
|
|||
Common/CRayCollisionTester.h \
|
||||
Scene/ENodeType.h \
|
||||
Common/Math.h \
|
||||
Scene/CBoundingBoxNode.h \
|
||||
Core/Log.h \
|
||||
Scene/CRootNode.h \
|
||||
Common/CVector2i.h \
|
||||
|
@ -321,7 +319,8 @@ HEADERS += \
|
|||
UI/WAnimParamsEditor.h \
|
||||
Resource/CCollisionMeshGroup.h \
|
||||
Core/CFrustumPlanes.h \
|
||||
Core/CLightParameters.h
|
||||
Core/CLightParameters.h \
|
||||
Core/SViewInfo.h
|
||||
|
||||
FORMS += \
|
||||
UI/CStartWindow.ui \
|
||||
|
|
|
@ -152,6 +152,49 @@ void CTexture::Resize(u32 Width, u32 Height)
|
|||
}
|
||||
}
|
||||
|
||||
float CTexture::ReadTexelAlpha(const CVector2f& TexCoord)
|
||||
{
|
||||
// todo: support texel formats other than DXT1
|
||||
// DXT1 is definitely the most complicated one anyway; try reusing CTextureDecoder functions for other formats
|
||||
u32 TexelX = (u32) ((mWidth - 1) * TexCoord.x);
|
||||
u32 TexelY = (u32) ((mHeight - 1) * (1.f - fmodf(TexCoord.y, 1.f)));
|
||||
|
||||
if (mTexelFormat == eDXT1 && mBufferExists)
|
||||
{
|
||||
CMemoryInStream Buffer(mImgDataBuffer, mImgDataSize, IOUtil::SystemEndianness);
|
||||
|
||||
// 8 bytes per 4x4 16-pixel block, left-to-right top-to-bottom
|
||||
u32 BlockIdxX = TexelX / 4;
|
||||
u32 BlockIdxY = TexelY / 4;
|
||||
u32 BlocksPerRow = mWidth / 4;
|
||||
|
||||
u32 BufferPos = (8 * BlockIdxX) + (8 * BlockIdxY * BlocksPerRow);
|
||||
Buffer.Seek(BufferPos, SEEK_SET);
|
||||
|
||||
u16 PaletteA = Buffer.ReadShort();
|
||||
u16 PaletteB = Buffer.ReadShort();
|
||||
|
||||
if (PaletteA > PaletteB)
|
||||
{
|
||||
// No palette colors have alpha
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
// We only care about alpha, which is only present on palette index 3.
|
||||
// We don't need to calculate/decode the actual palette colors.
|
||||
u32 BlockCol = (TexelX & 0xF) / 4;
|
||||
u32 BlockRow = (TexelY & 0xF) / 4;
|
||||
|
||||
Buffer.Seek(BlockRow, SEEK_CUR);
|
||||
u8 Row = Buffer.ReadByte();
|
||||
u8 Shift = (u8) (6 - (BlockCol * 2));
|
||||
u8 PaletteIndex = (Row >> Shift) & 0x3;
|
||||
return (PaletteIndex == 3 ? 0.f : 1.f);
|
||||
}
|
||||
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
bool CTexture::WriteDDS(COutputStream& out)
|
||||
{
|
||||
if (!out.IsValid()) return false;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CTEXTURE_H
|
||||
|
||||
#include <Common/types.h>
|
||||
#include <Common/CVector2f.h>
|
||||
#include <FileIO/FileIO.h>
|
||||
#include <gl/glew.h>
|
||||
#include "CResource.h"
|
||||
|
@ -35,6 +36,7 @@ public:
|
|||
bool BufferGL();
|
||||
void Bind(u32 GLTextureUnit);
|
||||
void Resize(u32 Width, u32 Height);
|
||||
float ReadTexelAlpha(const CVector2f& TexCoord);
|
||||
bool WriteDDS(COutputStream& out);
|
||||
|
||||
// Getters
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
#include "CBoundingBoxNode.h"
|
||||
|
||||
CBoundingBoxNode::CBoundingBoxNode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CBoundingBoxNode::~CBoundingBoxNode()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef CBOUNDINGBOXNODE_H
|
||||
#define CBOUNDINGBOXNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
|
||||
class CBoundingBoxNode
|
||||
{
|
||||
CColor mColor;
|
||||
|
||||
public:
|
||||
CBoundingBoxNode();
|
||||
~CBoundingBoxNode();
|
||||
|
||||
};
|
||||
|
||||
#endif // CBOUNDINGBOXNODE_H
|
|
@ -15,10 +15,10 @@ ENodeType CCollisionNode::NodeType()
|
|||
return eCollisionNode;
|
||||
}
|
||||
|
||||
void CCollisionNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
||||
void CCollisionNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mpCollision) return;
|
||||
if (!frustum.BoxInFrustum(AABox())) return;
|
||||
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
||||
|
@ -47,7 +47,7 @@ void CCollisionNode::DrawAsset(ERenderOptions /*Options*/, u32 /*asset*/)
|
|||
{
|
||||
}
|
||||
|
||||
SRayIntersection CCollisionNode::RayNodeIntersectTest(const CRay& /*Ray*/, u32 /*AssetID*/, ERenderOptions /*options*/)
|
||||
SRayIntersection CCollisionNode::RayNodeIntersectTest(const CRay& /*Ray*/, u32 /*AssetID*/, const SViewInfo& /*ViewInfo*/)
|
||||
{
|
||||
// todo
|
||||
SRayIntersection Result;
|
||||
|
|
|
@ -12,10 +12,10 @@ class CCollisionNode : public CSceneNode
|
|||
public:
|
||||
CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustumPlanes);
|
||||
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
|
||||
void SetCollision(CCollisionMeshGroup *pCollision);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "CLightNode.h"
|
||||
#include <Common/Math.h>
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CRenderer.h>
|
||||
|
@ -24,16 +25,16 @@ ENodeType CLightNode::NodeType()
|
|||
return eLightNode;
|
||||
}
|
||||
|
||||
void CLightNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
||||
void CLightNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!frustum.BoxInFrustum(AABox())) return;
|
||||
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||
|
||||
pRenderer->AddOpaqueMesh(this, 0, CAABox(mPosition + 0.5f, mPosition - 0.5f), eDrawMesh);
|
||||
}
|
||||
|
||||
void CLightNode::Draw(ERenderOptions /*Options*/)
|
||||
{
|
||||
CDrawUtil::DrawLightBillboard(mpLight->GetType(), mpLight->GetColor(), mPosition, mScale.xy() * CVector2f(0.75f), TintColor());
|
||||
CDrawUtil::DrawLightBillboard(mpLight->GetType(), mpLight->GetColor(), mPosition, BillboardScale(), TintColor());
|
||||
|
||||
// Below commented-out code is for light radius visualization as a bounding box
|
||||
/*float r = mLight->GetRadius();
|
||||
|
@ -45,24 +46,86 @@ void CLightNode::DrawAsset(ERenderOptions /*Options*/, u32 /*asset*/)
|
|||
{
|
||||
}
|
||||
|
||||
SRayIntersection CLightNode::RayNodeIntersectTest(const CRay& Ray, u32 /*AssetID*/, ERenderOptions options)
|
||||
void CLightNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
||||
{
|
||||
// Needs redo if I ever make these look like something other than boxes
|
||||
bool allowBackfaces = ((options & eEnableBackfaceCull) == 0);
|
||||
CVector2f BillScale = BillboardScale();
|
||||
float ScaleXY = (BillScale.x > BillScale.y ? BillScale.x : BillScale.y);
|
||||
|
||||
if (!allowBackfaces && (AABox().IsPointInBox(Ray.Origin())))
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
CAABox BillBox = CAABox(mPosition + CVector3f(-ScaleXY, -ScaleXY, -BillScale.y),
|
||||
mPosition + CVector3f( ScaleXY, ScaleXY, BillScale.y));
|
||||
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
std::pair<bool,float> BoxResult = BillBox.IntersectsRay(Tester.Ray());
|
||||
if (BoxResult.first) Tester.AddNode(this, 0, BoxResult.second);
|
||||
}
|
||||
|
||||
if (BoxResult.first)
|
||||
return SRayIntersection(true, BoxResult.second, this, 0);
|
||||
SRayIntersection CLightNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo)
|
||||
{
|
||||
// todo: come up with a better way to share this code between CScriptNode and CLightNode
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CTexture *pBillboard = CDrawUtil::GetLightTexture(mpLight->GetType());
|
||||
|
||||
if (!pBillboard)
|
||||
{
|
||||
out.Hit = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Step 1: check whether the ray intersects with the plane the billboard is on
|
||||
CPlane BillboardPlane(-ViewInfo.pCamera->Direction(), mPosition);
|
||||
std::pair<bool,float> PlaneTest = Math::RayPlaneIntersecton(Ray, BillboardPlane);
|
||||
|
||||
if (PlaneTest.first)
|
||||
{
|
||||
// Step 2: transform the hit point into the plane's local space
|
||||
CVector3f PlaneHitPoint = Ray.PointOnRay(PlaneTest.second);
|
||||
CVector3f RelHitPoint = PlaneHitPoint - mPosition;
|
||||
|
||||
CVector3f PlaneForward = -ViewInfo.pCamera->Direction();
|
||||
CVector3f PlaneRight = -ViewInfo.pCamera->RightVector();
|
||||
CVector3f PlaneUp = ViewInfo.pCamera->UpVector();
|
||||
CQuaternion PlaneRot = CQuaternion::FromAxes(PlaneRight, PlaneForward, PlaneUp);
|
||||
|
||||
CVector3f RotatedHitPoint = PlaneRot.Inverse() * RelHitPoint;
|
||||
CVector2f LocalHitPoint = RotatedHitPoint.xz() / BillboardScale();
|
||||
|
||||
// Step 3: check whether the transformed hit point is in the -1 to 1 range
|
||||
if ((LocalHitPoint.x >= -1.f) && (LocalHitPoint.x <= 1.f) && (LocalHitPoint.y >= -1.f) && (LocalHitPoint.y <= 1.f))
|
||||
{
|
||||
// Step 4: look up the hit texel and check whether it's transparent or opaque
|
||||
CVector2f TexCoord = (LocalHitPoint + CVector2f(1.f)) * 0.5f;
|
||||
TexCoord.x = -TexCoord.x + 1.f;
|
||||
float TexelAlpha = pBillboard->ReadTexelAlpha(TexCoord);
|
||||
|
||||
if (TexelAlpha < 0.25f)
|
||||
out.Hit = false;
|
||||
|
||||
else
|
||||
{
|
||||
// It's opaque... we have a hit!
|
||||
out.Hit = true;
|
||||
out.Distance = PlaneTest.second;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
}
|
||||
|
||||
else
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
out.Hit = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
CLight* CLightNode::Light()
|
||||
{
|
||||
return mpLight;
|
||||
}
|
||||
|
||||
CVector2f CLightNode::BillboardScale()
|
||||
{
|
||||
return mScale.xz() * 0.75f;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,13 @@ class CLightNode : public CSceneNode
|
|||
public:
|
||||
CLightNode(CSceneManager *pScene, CSceneNode *pParent = 0, CLight *Light = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
||||
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options);
|
||||
void RayAABoxIntersectTest(CRayCollisionTester& Tester);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
|
||||
CLight* Light();
|
||||
CVector2f BillboardScale();
|
||||
};
|
||||
|
||||
#endif // CLIGHTNODE_H
|
||||
|
|
|
@ -16,10 +16,10 @@ ENodeType CModelNode::NodeType()
|
|||
return eModelNode;
|
||||
}
|
||||
|
||||
void CModelNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
||||
void CModelNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
if (!frustum.BoxInFrustum(AABox())) return;
|
||||
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||
|
||||
if (!mpModel->HasTransparency(mActiveMatSet))
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
@ -30,7 +30,7 @@ void CModelNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frust
|
|||
|
||||
for (u32 iSurf = 0; iSurf < SurfaceCount; iSurf++)
|
||||
{
|
||||
if (frustum.BoxInFrustum(mpModel->GetSurfaceAABox(iSurf).Transformed(Transform())))
|
||||
if (ViewInfo.ViewFrustum.BoxInFrustum(mpModel->GetSurfaceAABox(iSurf).Transformed(Transform())))
|
||||
{
|
||||
if (!mpModel->IsSurfaceTransparent(iSurf, mActiveMatSet))
|
||||
pRenderer->AddOpaqueMesh(this, iSurf, mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()), eDrawAsset);
|
||||
|
@ -109,13 +109,14 @@ void CModelNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
|||
}
|
||||
}
|
||||
|
||||
SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options)
|
||||
SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo)
|
||||
{
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
ERenderOptions options = ViewInfo.pRenderer->RenderOptions();
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||
|
||||
if (Result.first)
|
||||
|
|
|
@ -16,11 +16,11 @@ public:
|
|||
explicit CModelNode(CSceneManager *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
|
||||
|
||||
virtual ENodeType NodeType();
|
||||
virtual void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
||||
virtual void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
virtual void Draw(ERenderOptions Options);
|
||||
virtual void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
virtual void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
|
||||
|
||||
void SetModel(CModel *pModel);
|
||||
void SetMatSet(u32 MatSet);
|
||||
|
|
|
@ -15,12 +15,12 @@ public:
|
|||
return eRootNode;
|
||||
}
|
||||
|
||||
inline void AddToRenderer(CRenderer *, const CFrustumPlanes&) {}
|
||||
inline void AddToRenderer(CRenderer *, const SViewInfo&) {}
|
||||
inline void Draw(ERenderOptions) {}
|
||||
inline void DrawAsset(ERenderOptions, u32) {}
|
||||
inline void RayAABoxIntersectTest(CRayCollisionTester &) {}
|
||||
|
||||
inline SRayIntersection RayNodeIntersectTest(const CRay &, u32, ERenderOptions) {
|
||||
inline SRayIntersection RayNodeIntersectTest(const CRay &, u32, const SViewInfo&) {
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
virtual void DrawAsset(ERenderOptions options, u32 asset) = 0;
|
||||
virtual void DrawSelection();
|
||||
virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, ERenderOptions options) = 0;
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo) = 0;
|
||||
virtual bool IsVisible() const;
|
||||
|
||||
void Unparent();
|
||||
|
|
|
@ -101,18 +101,18 @@ TString CScriptNode::PrefixedName() const
|
|||
return "[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->InstanceName();
|
||||
}
|
||||
|
||||
void CScriptNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
||||
void CScriptNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mpInstance) return;
|
||||
|
||||
ERenderOptions options = pRenderer->RenderOptions();
|
||||
|
||||
if (options & eDrawObjectCollision)
|
||||
mpCollisionNode->AddToRenderer(pRenderer, frustum);
|
||||
mpCollisionNode->AddToRenderer(pRenderer, ViewInfo);
|
||||
|
||||
if (options & eDrawObjects)
|
||||
{
|
||||
if (frustum.BoxInFrustum(AABox()))
|
||||
if (ViewInfo.ViewFrustum.BoxInFrustum(AABox()))
|
||||
{
|
||||
if (!mpActiveModel)
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
@ -131,7 +131,7 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frus
|
|||
|
||||
for (u32 s = 0; s < SubmeshCount; s++)
|
||||
{
|
||||
if (frustum.BoxInFrustum(mpActiveModel->GetSurfaceAABox(s).Transformed(Transform())))
|
||||
if (ViewInfo.ViewFrustum.BoxInFrustum(mpActiveModel->GetSurfaceAABox(s).Transformed(Transform())))
|
||||
{
|
||||
if (!mpActiveModel->IsSurfaceTransparent(s, 0))
|
||||
pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset);
|
||||
|
@ -152,7 +152,7 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frus
|
|||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||
|
||||
if (mHasVolumePreview)
|
||||
mpVolumePreviewNode->AddToRenderer(pRenderer, frustum);
|
||||
mpVolumePreviewNode->AddToRenderer(pRenderer, ViewInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ void CScriptNode::Draw(ERenderOptions Options)
|
|||
// Draw billboard
|
||||
else if (mpBillboard)
|
||||
{
|
||||
CDrawUtil::DrawBillboard(mpBillboard, mPosition, mScale.xy() * CVector2f(0.75f), TintColor());
|
||||
CDrawUtil::DrawBillboard(mpBillboard, mPosition, BillboardScale(), TintColor());
|
||||
}
|
||||
|
||||
// If no model or billboard, default to drawing a purple box
|
||||
|
@ -243,27 +243,44 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
|||
return;
|
||||
|
||||
const CRay& Ray = Tester.Ray();
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (BoxResult.first)
|
||||
if (mpActiveModel || !mpBillboard)
|
||||
{
|
||||
if (mpActiveModel)
|
||||
{
|
||||
for (u32 iSurf = 0; iSurf < mpActiveModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
std::pair<bool,float> SurfResult = mpActiveModel->GetSurfaceAABox(iSurf).Transformed(Transform()).IntersectsRay(Ray);
|
||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (SurfResult.first)
|
||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
||||
if (BoxResult.first)
|
||||
{
|
||||
if (mpActiveModel)
|
||||
{
|
||||
for (u32 iSurf = 0; iSurf < mpActiveModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
std::pair<bool,float> SurfResult = mpActiveModel->GetSurfaceAABox(iSurf).Transformed(Transform()).IntersectsRay(Ray);
|
||||
|
||||
if (SurfResult.first)
|
||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
||||
}
|
||||
}
|
||||
else Tester.AddNode(this, 0, BoxResult.second);
|
||||
}
|
||||
else Tester.AddNode(this, 0, BoxResult.second);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Because the billboard rotates a lot, expand the AABox on the X/Y axes to cover any possible orientation
|
||||
CVector2f BillScale = BillboardScale();
|
||||
float ScaleXY = (BillScale.x > BillScale.y ? BillScale.x : BillScale.y);
|
||||
|
||||
CAABox BillBox = CAABox(mPosition + CVector3f(-ScaleXY, -ScaleXY, -BillScale.y),
|
||||
mPosition + CVector3f( ScaleXY, ScaleXY, BillScale.y));
|
||||
|
||||
std::pair<bool,float> BoxResult = BillBox.IntersectsRay(Ray);
|
||||
if (BoxResult.first) Tester.AddNode(this, 0, BoxResult.second);
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options)
|
||||
SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo)
|
||||
{
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
ERenderOptions options = ViewInfo.pRenderer->RenderOptions();
|
||||
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
|
@ -271,20 +288,75 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID,
|
|||
|
||||
if (options & eDrawObjects)
|
||||
{
|
||||
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||
|
||||
if (Result.first)
|
||||
// Model test
|
||||
if (mpActiveModel || !mpBillboard)
|
||||
{
|
||||
out.Hit = true;
|
||||
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
||||
|
||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
out.Hit = true;
|
||||
|
||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
}
|
||||
|
||||
// Billboard test
|
||||
// todo: come up with a better way to share this code between CScriptNode and CLightNode
|
||||
else
|
||||
out.Hit = false;
|
||||
{
|
||||
// Step 1: check whether the ray intersects with the plane the billboard is on
|
||||
CPlane BillboardPlane(-ViewInfo.pCamera->Direction(), mPosition);
|
||||
std::pair<bool,float> PlaneTest = Math::RayPlaneIntersecton(Ray, BillboardPlane);
|
||||
|
||||
if (PlaneTest.first)
|
||||
{
|
||||
// Step 2: transform the hit point into the plane's local space
|
||||
CVector3f PlaneHitPoint = Ray.PointOnRay(PlaneTest.second);
|
||||
CVector3f RelHitPoint = PlaneHitPoint - mPosition;
|
||||
|
||||
CVector3f PlaneForward = -ViewInfo.pCamera->Direction();
|
||||
CVector3f PlaneRight = -ViewInfo.pCamera->RightVector();
|
||||
CVector3f PlaneUp = ViewInfo.pCamera->UpVector();
|
||||
CQuaternion PlaneRot = CQuaternion::FromAxes(PlaneRight, PlaneForward, PlaneUp);
|
||||
|
||||
CVector3f RotatedHitPoint = PlaneRot.Inverse() * RelHitPoint;
|
||||
CVector2f LocalHitPoint = RotatedHitPoint.xz() / BillboardScale();
|
||||
|
||||
// Step 3: check whether the transformed hit point is in the -1 to 1 range
|
||||
if ((LocalHitPoint.x >= -1.f) && (LocalHitPoint.x <= 1.f) && (LocalHitPoint.y >= -1.f) && (LocalHitPoint.y <= 1.f))
|
||||
{
|
||||
// Step 4: look up the hit texel and check whether it's transparent or opaque
|
||||
CVector2f TexCoord = (LocalHitPoint + CVector2f(1.f)) * 0.5f;
|
||||
TexCoord.x = -TexCoord.x + 1.f;
|
||||
float TexelAlpha = mpBillboard->ReadTexelAlpha(TexCoord);
|
||||
|
||||
if (TexelAlpha < 0.25f)
|
||||
out.Hit = false;
|
||||
|
||||
else
|
||||
{
|
||||
// It's opaque... we have a hit!
|
||||
out.Hit = true;
|
||||
out.Distance = PlaneTest.second;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
}
|
||||
|
||||
else
|
||||
out.Hit = false;
|
||||
}
|
||||
}
|
||||
else out.Hit = false;
|
||||
|
||||
|
@ -380,3 +452,9 @@ CAABox CScriptNode::PreviewVolumeAABox()
|
|||
else
|
||||
return mpVolumePreviewNode->AABox();
|
||||
}
|
||||
|
||||
CVector2f CScriptNode::BillboardScale()
|
||||
{
|
||||
CVector2f out = (mpInstance->Template()->ScaleType() == CScriptTemplate::eScaleEnabled ? mScale.xz() : CVector2f(1.f));
|
||||
return out * 0.5f;
|
||||
}
|
||||
|
|
|
@ -26,18 +26,19 @@ public:
|
|||
CScriptNode(CSceneManager *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0);
|
||||
ENodeType NodeType();
|
||||
TString PrefixedName() const;
|
||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
||||
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 Asset);
|
||||
void DrawSelection();
|
||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
|
||||
bool IsVisible() const;
|
||||
CScriptObject* Object();
|
||||
CModel* ActiveModel();
|
||||
void GeneratePosition();
|
||||
bool HasPreviewVolume();
|
||||
CAABox PreviewVolumeAABox();
|
||||
CVector2f BillboardScale();
|
||||
};
|
||||
|
||||
#endif // CSCRIPTNODE_H
|
||||
|
|
|
@ -19,11 +19,11 @@ ENodeType CStaticNode::NodeType()
|
|||
return eStaticNode;
|
||||
}
|
||||
|
||||
void CStaticNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
||||
void CStaticNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||
{
|
||||
if (!mpModel) return;
|
||||
if (mpModel->IsOccluder()) return;
|
||||
if (!frustum.BoxInFrustum(AABox())) return;
|
||||
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||
|
||||
if (!mpModel->IsTransparent())
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
|
@ -33,7 +33,7 @@ void CStaticNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frus
|
|||
u32 sm_count = mpModel->GetSurfaceCount();
|
||||
for (u32 s = 0; s < sm_count; s++)
|
||||
{
|
||||
if (frustum.BoxInFrustum(mpModel->GetSurfaceAABox(s).Transformed(Transform())))
|
||||
if (ViewInfo.ViewFrustum.BoxInFrustum(mpModel->GetSurfaceAABox(s).Transformed(Transform())))
|
||||
pRenderer->AddTransparentMesh(this, s, mpModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset);
|
||||
}
|
||||
}
|
||||
|
@ -90,13 +90,14 @@ void CStaticNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
|||
}
|
||||
}
|
||||
|
||||
SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options)
|
||||
SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo)
|
||||
{
|
||||
SRayIntersection out;
|
||||
out.pNode = this;
|
||||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
ERenderOptions options = ViewInfo.pRenderer->RenderOptions();
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||
|
||||
if (Result.first)
|
||||
|
|
|
@ -11,11 +11,11 @@ class CStaticNode : public CSceneNode
|
|||
public:
|
||||
CStaticNode(CSceneManager *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0);
|
||||
ENodeType NodeType();
|
||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
||||
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
void Draw(ERenderOptions Options);
|
||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, ERenderOptions options);
|
||||
SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
|
||||
};
|
||||
|
||||
#endif // CSTATICNODE_H
|
||||
|
|
|
@ -14,6 +14,7 @@ CBasicViewport::CBasicViewport(QWidget *pParent) :
|
|||
{
|
||||
setMouseTracking(true);
|
||||
mCamera.SetAspectRatio((float) width() / height());
|
||||
mViewInfo.pCamera = &mCamera;
|
||||
}
|
||||
|
||||
CBasicViewport::~CBasicViewport()
|
||||
|
@ -47,9 +48,11 @@ void CBasicViewport::paintGL()
|
|||
glViewport(0, 0, width(), height());
|
||||
glLineWidth(1.f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
mViewInfo.ViewFrustum = mCamera.FrustumPlanes();
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = mCamera.ProjectionMatrix();
|
||||
|
||||
// Actual rendering is intended to be handled by subclassing CBasicViewport and
|
||||
// reimplementing Render().
|
||||
// reimplementing Paint().
|
||||
Paint();
|
||||
|
||||
// Finally, draw XYZ axes in the corner
|
||||
|
@ -247,6 +250,15 @@ void CBasicViewport::ProcessInput()
|
|||
if (IsKeyboardInputActive())
|
||||
mCamera.ProcessKeyInput((EKeyInputs) mKeysPressed, DeltaTime);
|
||||
|
||||
// Update view info
|
||||
const CMatrix4f& View = mCamera.ViewMatrix();
|
||||
mViewInfo.RotationOnlyViewMatrix = CMatrix4f(View[0][0], View[0][1], View[0][2], 0.f,
|
||||
View[1][0], View[1][1], View[1][2], 0.f,
|
||||
View[2][0], View[2][1], View[2][2], 0.f,
|
||||
View[3][0], View[3][1], View[3][2], 1.f);
|
||||
|
||||
mViewInfo.ViewFrustum = mCamera.FrustumPlanes();
|
||||
|
||||
// Check user input
|
||||
CheckUserInput();
|
||||
}
|
||||
|
@ -259,10 +271,6 @@ void CBasicViewport::Render()
|
|||
}
|
||||
|
||||
// ************ PRIVATE ************
|
||||
void CBasicViewport::ProcessInput(double /*DeltaTime*/)
|
||||
{
|
||||
}
|
||||
|
||||
void CBasicViewport::DrawAxes()
|
||||
{
|
||||
// Draw 64x64 axes in lower-left corner with 8px margins
|
||||
|
@ -272,7 +280,7 @@ void CBasicViewport::DrawAxes()
|
|||
glDepthRange(0.f, 1.f);
|
||||
|
||||
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(mCamera.Direction() * 5).ToMatrix4f();
|
||||
CGraphics::sMVPBlock.ViewMatrix = mCamera.RotationOnlyViewMatrix();
|
||||
CGraphics::sMVPBlock.ViewMatrix = mViewInfo.RotationOnlyViewMatrix;
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = Math::OrthographicMatrix(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f);
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QOpenGLWidget>
|
||||
|
||||
#include <Core/CRenderer.h>
|
||||
#include <Core/SViewInfo.h>
|
||||
#include <Common/CRay.h>
|
||||
#include <Common/CTimer.h>
|
||||
#include <Common/CVector2i.h>
|
||||
|
@ -23,6 +24,7 @@ protected:
|
|||
CCamera mCamera;
|
||||
CTimer mFrameTimer;
|
||||
double mLastDrawTime;
|
||||
SViewInfo mViewInfo;
|
||||
|
||||
// Cursor settings
|
||||
QCursor mCursorState;
|
||||
|
@ -55,7 +57,6 @@ public:
|
|||
bool IsCursorVisible();
|
||||
bool IsMouseInputActive();
|
||||
bool IsKeyboardInputActive();
|
||||
CRenderer* Renderer();
|
||||
CCamera& Camera();
|
||||
CRay CastRay();
|
||||
CVector2f MouseDeviceCoordinates();
|
||||
|
@ -74,7 +75,6 @@ protected slots:
|
|||
virtual void OnMouseRelease(QMouseEvent* /*pEvent*/) {}
|
||||
|
||||
private:
|
||||
void ProcessInput(double DeltaTime);
|
||||
void DrawAxes();
|
||||
};
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ CGizmo::~CGizmo()
|
|||
{
|
||||
}
|
||||
|
||||
void CGizmo::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes&)
|
||||
void CGizmo::AddToRenderer(CRenderer *pRenderer, const SViewInfo&)
|
||||
{
|
||||
// Transform is updated every frame even if the user doesn't modify the gizmo
|
||||
// in order to account for scale changes based on camera distance
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
CGizmo();
|
||||
~CGizmo();
|
||||
|
||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
||||
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||
void DrawAsset(ERenderOptions options, u32 asset);
|
||||
|
||||
void IncrementSize();
|
||||
|
|
|
@ -49,8 +49,8 @@ void CModelEditorViewport::Paint()
|
|||
else if (mMode == eDrawMesh)
|
||||
{
|
||||
CDrawUtil::DrawGrid();
|
||||
mpModelNode->AddToRenderer(mpRenderer, mCamera.FrustumPlanes());
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
mpModelNode->AddToRenderer(mpRenderer, mViewInfo);
|
||||
mpRenderer->RenderBuckets(mViewInfo);
|
||||
}
|
||||
|
||||
else if (mMode == eDrawSphere)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "CSceneViewport.h"
|
||||
#include "undo/UndoCommands.h"
|
||||
#include <Core/SViewInfo.h>
|
||||
|
||||
CSceneViewport::CSceneViewport(QWidget *pParent)
|
||||
: CBasicViewport(pParent),
|
||||
|
@ -13,6 +14,9 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
|
|||
mpRenderer = new CRenderer();
|
||||
mpRenderer->SetClearColor(CColor::skBlack);
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
|
||||
mViewInfo.pScene = mpScene;
|
||||
mViewInfo.pRenderer = mpRenderer;
|
||||
}
|
||||
|
||||
CSceneViewport::~CSceneViewport()
|
||||
|
@ -77,7 +81,7 @@ void CSceneViewport::SceneRayCast(const CRay& ray)
|
|||
return;
|
||||
}
|
||||
|
||||
SRayIntersection result = mpScene->SceneRayCast(ray, mpRenderer->RenderOptions());
|
||||
SRayIntersection result = mpScene->SceneRayCast(ray, mViewInfo);
|
||||
|
||||
if (result.Hit)
|
||||
{
|
||||
|
@ -131,12 +135,12 @@ void CSceneViewport::Paint()
|
|||
if (mDrawSky)
|
||||
{
|
||||
CModel *pSky = mpScene->GetActiveSkybox();
|
||||
if (pSky) mpRenderer->RenderSky(pSky, mCamera);
|
||||
if (pSky) mpRenderer->RenderSky(pSky, mViewInfo);
|
||||
}
|
||||
|
||||
mCamera.LoadMatrices();
|
||||
mpScene->AddSceneToRenderer(mpRenderer, mCamera);
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
mpScene->AddSceneToRenderer(mpRenderer, mViewInfo);
|
||||
mpRenderer->RenderBuckets(mViewInfo);
|
||||
mpRenderer->RenderBloom();
|
||||
|
||||
if (mpEditor->IsGizmoVisible())
|
||||
|
@ -146,8 +150,8 @@ void CSceneViewport::Paint()
|
|||
|
||||
mpRenderer->ClearDepthBuffer();
|
||||
pGizmo->UpdateForCamera(mCamera);
|
||||
pGizmo->AddToRenderer(mpRenderer, mCamera.FrustumPlanes());
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
pGizmo->AddToRenderer(mpRenderer, mViewInfo);
|
||||
mpRenderer->RenderBuckets(mViewInfo);
|
||||
}
|
||||
|
||||
mpRenderer->EndFrame();
|
||||
|
|
Loading…
Reference in New Issue