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 "CQuaternion.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <Common/Math.h>
|
#include "Math.h"
|
||||||
|
#include "CMatrix4f.h"
|
||||||
|
|
||||||
CQuaternion::CQuaternion()
|
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::skIdentity = CQuaternion(1.f, 0.f, 0.f, 0.f);
|
||||||
CQuaternion CQuaternion::skZero = CQuaternion(0.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
|
||||||
static CQuaternion FromEuler(CVector3f euler);
|
static CQuaternion FromEuler(CVector3f euler);
|
||||||
static CQuaternion FromAxisAngle(float angle, CVector3f axis);
|
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 skIdentity;
|
||||||
static CQuaternion skZero;
|
static CQuaternion skZero;
|
||||||
|
|
|
@ -19,7 +19,7 @@ void CRayCollisionTester::AddNode(CSceneNode *pNode, u32 AssetIndex, float Dista
|
||||||
Intersection.Distance = Distance;
|
Intersection.Distance = Distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
SRayIntersection CRayCollisionTester::TestNodes(ERenderOptions options)
|
SRayIntersection CRayCollisionTester::TestNodes(const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
// Sort nodes by distance from ray
|
// Sort nodes by distance from ray
|
||||||
mBoxIntersectList.sort(
|
mBoxIntersectList.sort(
|
||||||
|
@ -43,7 +43,7 @@ SRayIntersection CRayCollisionTester::TestNodes(ERenderOptions options)
|
||||||
|
|
||||||
// Otherwise, more intersection tests...
|
// Otherwise, more intersection tests...
|
||||||
CSceneNode *pNode = Intersection.pNode;
|
CSceneNode *pNode = Intersection.pNode;
|
||||||
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex, options);
|
SRayIntersection MidResult = pNode->RayNodeIntersectTest(mRay, Intersection.AssetIndex, ViewInfo);
|
||||||
|
|
||||||
if (MidResult.Hit)
|
if (MidResult.Hit)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "CVector3f.h"
|
#include "CVector3f.h"
|
||||||
#include "SRayIntersection.h"
|
#include "SRayIntersection.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <Core/ERenderOptions.h>
|
#include <Core/SViewInfo.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ public:
|
||||||
~CRayCollisionTester();
|
~CRayCollisionTester();
|
||||||
const CRay& Ray() const;
|
const CRay& Ray() const;
|
||||||
void AddNode(CSceneNode *pNode, u32 AssetIndex, float Distance);
|
void AddNode(CSceneNode *pNode, u32 AssetIndex, float Distance);
|
||||||
SRayIntersection TestNodes(ERenderOptions options);
|
SRayIntersection TestNodes(const SViewInfo& ViewInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const CRay& CRayCollisionTester::Ray() const
|
inline const CRay& CRayCollisionTester::Ray() const
|
||||||
|
|
|
@ -15,6 +15,11 @@ float Pow(float Base, float Exponent)
|
||||||
return pow(Base, Exponent);
|
return pow(Base, Exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Sqrt(float v)
|
||||||
|
{
|
||||||
|
return sqrtf(v);
|
||||||
|
}
|
||||||
|
|
||||||
float Distance(const CVector3f& A, const CVector3f& B)
|
float Distance(const CVector3f& A, const CVector3f& B)
|
||||||
{
|
{
|
||||||
return sqrtf( Pow(B.x - A.x, 2.f) +
|
return sqrtf( Pow(B.x - A.x, 2.f) +
|
||||||
|
|
|
@ -15,6 +15,8 @@ float Abs(float v);
|
||||||
|
|
||||||
float Pow(float Base, float Exponent);
|
float Pow(float Base, float Exponent);
|
||||||
|
|
||||||
|
float Sqrt(float v);
|
||||||
|
|
||||||
float Distance(const CVector3f& A, const CVector3f& B);
|
float Distance(const CVector3f& A, const CVector3f& B);
|
||||||
|
|
||||||
float DegreesToRadians(float deg);
|
float DegreesToRadians(float deg);
|
||||||
|
|
|
@ -163,13 +163,6 @@ void CCamera::LoadMatrices()
|
||||||
CGraphics::UpdateMVPBlock();
|
CGraphics::UpdateMVPBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCamera::LoadRotationOnlyMatrices()
|
|
||||||
{
|
|
||||||
CGraphics::sMVPBlock.ViewMatrix = RotationOnlyViewMatrix();
|
|
||||||
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
|
|
||||||
CGraphics::UpdateMVPBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ************ GETTERS ************
|
// ************ GETTERS ************
|
||||||
CVector3f CCamera::Position() const
|
CVector3f CCamera::Position() const
|
||||||
{
|
{
|
||||||
|
@ -181,6 +174,16 @@ CVector3f CCamera::Direction() const
|
||||||
return mDirection;
|
return mDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CVector3f CCamera::UpVector() const
|
||||||
|
{
|
||||||
|
return mUpVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVector3f CCamera::RightVector() const
|
||||||
|
{
|
||||||
|
return mRightVector;
|
||||||
|
}
|
||||||
|
|
||||||
float CCamera::Yaw() const
|
float CCamera::Yaw() const
|
||||||
{
|
{
|
||||||
return mYaw;
|
return mYaw;
|
||||||
|
@ -204,17 +207,6 @@ const CMatrix4f& CCamera::ViewMatrix()
|
||||||
return mCachedViewMatrix;
|
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()
|
const CMatrix4f& CCamera::ProjectionMatrix()
|
||||||
{
|
{
|
||||||
if (mProjectionOutdated)
|
if (mProjectionOutdated)
|
||||||
|
@ -295,6 +287,14 @@ void CCamera::CalculateDirection()
|
||||||
cos(mPitch) * sin(mYaw),
|
cos(mPitch) * sin(mYaw),
|
||||||
sin(mPitch)
|
sin(mPitch)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mRightVector = CVector3f(
|
||||||
|
cos(mYaw - Math::skHalfPi),
|
||||||
|
sin(mYaw - Math::skHalfPi),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
mUpVector = mRightVector.Cross(mDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCamera::CalculateView()
|
void CCamera::CalculateView()
|
||||||
|
@ -302,17 +302,9 @@ void CCamera::CalculateView()
|
||||||
// todo: don't use glm
|
// todo: don't use glm
|
||||||
CalculateDirection();
|
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 glmpos(mPosition.x, mPosition.y, mPosition.z);
|
||||||
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.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();
|
mCachedViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
|
||||||
mViewOutdated = false;
|
mViewOutdated = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ class CCamera
|
||||||
ECameraMoveMode mMode;
|
ECameraMoveMode mMode;
|
||||||
CVector3f mPosition;
|
CVector3f mPosition;
|
||||||
CVector3f mDirection;
|
CVector3f mDirection;
|
||||||
|
CVector3f mRightVector;
|
||||||
|
CVector3f mUpVector;
|
||||||
float mAspectRatio;
|
float mAspectRatio;
|
||||||
|
|
||||||
float mYaw;
|
float mYaw;
|
||||||
|
@ -48,16 +50,16 @@ public:
|
||||||
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
|
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
|
||||||
CRay CastRay(CVector2f DeviceCoords);
|
CRay CastRay(CVector2f DeviceCoords);
|
||||||
void LoadMatrices();
|
void LoadMatrices();
|
||||||
void LoadRotationOnlyMatrices();
|
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
CVector3f Position() const;
|
CVector3f Position() const;
|
||||||
CVector3f Direction() const;
|
CVector3f Direction() const;
|
||||||
|
CVector3f UpVector() const;
|
||||||
|
CVector3f RightVector() const;
|
||||||
float Yaw() const;
|
float Yaw() const;
|
||||||
float Pitch() const;
|
float Pitch() const;
|
||||||
float FieldOfView() const;
|
float FieldOfView() const;
|
||||||
const CMatrix4f& ViewMatrix();
|
const CMatrix4f& ViewMatrix();
|
||||||
CMatrix4f RotationOnlyViewMatrix();
|
|
||||||
const CMatrix4f& ProjectionMatrix();
|
const CMatrix4f& ProjectionMatrix();
|
||||||
const CFrustumPlanes& FrustumPlanes();
|
const CFrustumPlanes& FrustumPlanes();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ void CRenderBucket::Add(const SRenderablePtr& ptr)
|
||||||
mSize++;
|
mSize++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderBucket::Sort(CCamera& Camera)
|
void CRenderBucket::Sort(CCamera* pCamera)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
CCamera *pCamera;
|
CCamera *pCamera;
|
||||||
|
@ -39,7 +39,7 @@ void CRenderBucket::Sort(CCamera& Camera)
|
||||||
return (dotL > dotR);
|
return (dotL > dotR);
|
||||||
}
|
}
|
||||||
} backToFront;
|
} backToFront;
|
||||||
backToFront.pCamera = &Camera;
|
backToFront.pCamera = pCamera;
|
||||||
|
|
||||||
if (mSortType == BackToFront)
|
if (mSortType == BackToFront)
|
||||||
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize, backToFront);
|
std::stable_sort(mRenderables.begin(), mRenderables.begin() + mSize, backToFront);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
CRenderBucket();
|
CRenderBucket();
|
||||||
void SetSortType(ESortType Type);
|
void SetSortType(ESortType Type);
|
||||||
void Add(const SRenderablePtr& ptr);
|
void Add(const SRenderablePtr& ptr);
|
||||||
void Sort(CCamera& Camera);
|
void Sort(CCamera* pCamera);
|
||||||
void Clear();
|
void Clear();
|
||||||
void Draw(ERenderOptions Options);
|
void Draw(ERenderOptions Options);
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,7 +54,7 @@ void CRenderer::Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ GETTERS/SETTERS ************
|
// ************ GETTERS/SETTERS ************
|
||||||
ERenderOptions CRenderer::RenderOptions()
|
ERenderOptions CRenderer::RenderOptions() const
|
||||||
{
|
{
|
||||||
return mOptions;
|
return mOptions;
|
||||||
}
|
}
|
||||||
|
@ -159,11 +159,10 @@ void CRenderer::SetViewportSize(u32 Width, u32 Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ RENDER ************
|
// ************ RENDER ************
|
||||||
void CRenderer::RenderBuckets(CCamera& Camera)
|
void CRenderer::RenderBuckets(const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized) Init();
|
||||||
mSceneFramebuffer.Bind();
|
mSceneFramebuffer.Bind();
|
||||||
//Camera.LoadMatrices();
|
|
||||||
|
|
||||||
// Set backface culling
|
// Set backface culling
|
||||||
if (mOptions & eEnableBackfaceCull) glEnable(GL_CULL_FACE);
|
if (mOptions & eEnableBackfaceCull) glEnable(GL_CULL_FACE);
|
||||||
|
@ -175,7 +174,7 @@ void CRenderer::RenderBuckets(CCamera& Camera)
|
||||||
|
|
||||||
mOpaqueBucket.Draw(mOptions);
|
mOpaqueBucket.Draw(mOptions);
|
||||||
mOpaqueBucket.Clear();
|
mOpaqueBucket.Clear();
|
||||||
mTransparentBucket.Sort(Camera);
|
mTransparentBucket.Sort(ViewInfo.pCamera);
|
||||||
mTransparentBucket.Draw(mOptions);
|
mTransparentBucket.Draw(mOptions);
|
||||||
mTransparentBucket.Clear();
|
mTransparentBucket.Clear();
|
||||||
}
|
}
|
||||||
|
@ -288,7 +287,7 @@ void CRenderer::RenderBloom()
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRenderer::RenderSky(CModel *pSkyboxModel, CCamera& Camera)
|
void CRenderer::RenderSky(CModel *pSkyboxModel, const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
if (!mInitialized) Init();
|
if (!mInitialized) Init();
|
||||||
if (!pSkyboxModel) return;
|
if (!pSkyboxModel) return;
|
||||||
|
@ -302,7 +301,10 @@ void CRenderer::RenderSky(CModel *pSkyboxModel, CCamera& Camera)
|
||||||
CGraphics::UpdateVertexBlock();
|
CGraphics::UpdateVertexBlock();
|
||||||
CGraphics::UpdatePixelBlock();
|
CGraphics::UpdatePixelBlock();
|
||||||
CGraphics::UpdateLightBlock();
|
CGraphics::UpdateLightBlock();
|
||||||
Camera.LoadRotationOnlyMatrices();
|
|
||||||
|
// Load rotation-only view matrix
|
||||||
|
CGraphics::sMVPBlock.ViewMatrix = ViewInfo.RotationOnlyViewMatrix;
|
||||||
|
CGraphics::UpdateMVPBlock();
|
||||||
|
|
||||||
glDepthRange(1.f, 1.f);
|
glDepthRange(1.f, 1.f);
|
||||||
pSkyboxModel->Draw(mOptions, 0);
|
pSkyboxModel->Draw(mOptions, 0);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "ERenderOptions.h"
|
#include "ERenderOptions.h"
|
||||||
#include "ERenderCommand.h"
|
#include "ERenderCommand.h"
|
||||||
#include "SRenderablePtr.h"
|
#include "SRenderablePtr.h"
|
||||||
|
#include "SViewInfo.h"
|
||||||
#include <Common/CAABox.h>
|
#include <Common/CAABox.h>
|
||||||
#include <Common/CColor.h>
|
#include <Common/CColor.h>
|
||||||
#include <Common/CMatrix4f.h>
|
#include <Common/CMatrix4f.h>
|
||||||
|
@ -53,7 +54,7 @@ public:
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
// Getters/Setters
|
// Getters/Setters
|
||||||
ERenderOptions RenderOptions();
|
ERenderOptions RenderOptions() const;
|
||||||
void ToggleWorld(bool b);
|
void ToggleWorld(bool b);
|
||||||
void ToggleWorldCollision(bool b);
|
void ToggleWorldCollision(bool b);
|
||||||
void ToggleObjects(bool b);
|
void ToggleObjects(bool b);
|
||||||
|
@ -71,9 +72,9 @@ public:
|
||||||
void SetViewportSize(u32 Width, u32 Height);
|
void SetViewportSize(u32 Width, u32 Height);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
void RenderBuckets(CCamera& Camera);
|
void RenderBuckets(const SViewInfo& ViewInfo);
|
||||||
void RenderBloom();
|
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 AddOpaqueMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
|
||||||
void AddTransparentMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
|
void AddTransparentMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
|
||||||
void BeginFrame();
|
void BeginFrame();
|
||||||
|
|
|
@ -215,48 +215,50 @@ void CSceneManager::ClearScene()
|
||||||
mNodeCount = 0;
|
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++)
|
for (u32 n = 0; n < mModelNodes.size(); n++)
|
||||||
if (mModelNodes[n]->IsVisible())
|
if (mModelNodes[n]->IsVisible())
|
||||||
mModelNodes[n]->AddToRenderer(pRenderer, camera.FrustumPlanes());
|
mModelNodes[n]->AddToRenderer(pRenderer, ViewInfo);
|
||||||
|
|
||||||
for (u32 n = 0; n < mStaticNodes.size(); n++)
|
for (u32 n = 0; n < mStaticNodes.size(); n++)
|
||||||
if (mStaticNodes[n]->IsVisible())
|
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++)
|
for (u32 n = 0; n < mCollisionNodes.size(); n++)
|
||||||
if (mCollisionNodes[n]->IsVisible())
|
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++)
|
for (u32 n = 0; n < mLightNodes.size(); n++)
|
||||||
if (mLightNodes[n]->IsVisible())
|
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++)
|
for (u32 n = 0; n < mScriptNodes.size(); n++)
|
||||||
if (mScriptNodes[n]->IsVisible())
|
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
|
// Terribly hacky stuff to avoid having tons of redundant code
|
||||||
// because I'm too lazy to rewrite CSceneManager right now and fix it
|
// because I'm too lazy to rewrite CSceneManager right now and fix it
|
||||||
// (I'm probably going to do it soon...)
|
// (I'm probably going to do it soon...)
|
||||||
|
ERenderOptions renderOptions = ViewInfo.pRenderer->RenderOptions();
|
||||||
|
|
||||||
std::vector<CSceneNode*> *pNodeVectors[5] = {
|
std::vector<CSceneNode*> *pNodeVectors[5] = {
|
||||||
reinterpret_cast<std::vector<CSceneNode*>*>(&mModelNodes),
|
reinterpret_cast<std::vector<CSceneNode*>*>(&mModelNodes),
|
||||||
reinterpret_cast<std::vector<CSceneNode*>*>(&mStaticNodes),
|
reinterpret_cast<std::vector<CSceneNode*>*>(&mStaticNodes),
|
||||||
|
@ -283,7 +285,7 @@ SRayIntersection CSceneManager::SceneRayCast(const CRay& Ray, ERenderOptions ren
|
||||||
vec[iNode]->RayAABoxIntersectTest(Tester);
|
vec[iNode]->RayAABoxIntersectTest(Tester);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Tester.TestNodes(renderOptions);
|
return Tester.TestNodes(ViewInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSceneManager::PickEnvironmentObjects()
|
void CSceneManager::PickEnvironmentObjects()
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "CAreaAttributes.h"
|
#include "CAreaAttributes.h"
|
||||||
#include "CRenderer.h"
|
#include "CRenderer.h"
|
||||||
|
#include "SViewInfo.h"
|
||||||
#include <Common/SRayIntersection.h>
|
#include <Common/SRayIntersection.h>
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
#include <Scene/CSceneNode.h>
|
#include <Scene/CSceneNode.h>
|
||||||
|
@ -57,8 +58,8 @@ public:
|
||||||
void SetActiveArea(CGameArea *_area);
|
void SetActiveArea(CGameArea *_area);
|
||||||
void SetActiveWorld(CWorld *_world);
|
void SetActiveWorld(CWorld *_world);
|
||||||
void ClearScene();
|
void ClearScene();
|
||||||
void AddSceneToRenderer(CRenderer *pRenderer, CCamera& camera);
|
void AddSceneToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
SRayIntersection SceneRayCast(const CRay& Ray, ERenderOptions renderOptions);
|
SRayIntersection SceneRayCast(const CRay& Ray, const SViewInfo& ViewInfo);
|
||||||
void PickEnvironmentObjects();
|
void PickEnvironmentObjects();
|
||||||
CScriptNode* ScriptNodeByID(u32 InstanceID);
|
CScriptNode* ScriptNodeByID(u32 InstanceID);
|
||||||
CScriptNode* NodeForObject(CScriptObject *pObj);
|
CScriptNode* NodeForObject(CScriptObject *pObj);
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
#define IRENDERABLE_H
|
#define IRENDERABLE_H
|
||||||
|
|
||||||
#include "ERenderOptions.h"
|
#include "ERenderOptions.h"
|
||||||
#include <Common/CAABox.h>
|
#include "SViewInfo.h"
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
#include <Core/CFrustumPlanes.h>
|
|
||||||
|
|
||||||
class CRenderer;
|
class CRenderer;
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ class IRenderable
|
||||||
public:
|
public:
|
||||||
IRenderable() {}
|
IRenderable() {}
|
||||||
virtual ~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 Draw(ERenderOptions /*options*/) {}
|
||||||
virtual void DrawAsset(ERenderOptions /*options*/, u32 /*asset*/) {}
|
virtual void DrawAsset(ERenderOptions /*options*/, u32 /*asset*/) {}
|
||||||
virtual void DrawSelection() {}
|
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 \
|
Resource/model/SSurface.cpp \
|
||||||
Common/CRayCollisionTester.cpp \
|
Common/CRayCollisionTester.cpp \
|
||||||
Common/Math.cpp \
|
Common/Math.cpp \
|
||||||
Scene/CBoundingBoxNode.cpp \
|
|
||||||
Core/Log.cpp \
|
Core/Log.cpp \
|
||||||
Common/CVector2i.cpp \
|
Common/CVector2i.cpp \
|
||||||
UI/CNodeSelection.cpp \
|
UI/CNodeSelection.cpp \
|
||||||
|
@ -273,7 +272,6 @@ HEADERS += \
|
||||||
Common/CRayCollisionTester.h \
|
Common/CRayCollisionTester.h \
|
||||||
Scene/ENodeType.h \
|
Scene/ENodeType.h \
|
||||||
Common/Math.h \
|
Common/Math.h \
|
||||||
Scene/CBoundingBoxNode.h \
|
|
||||||
Core/Log.h \
|
Core/Log.h \
|
||||||
Scene/CRootNode.h \
|
Scene/CRootNode.h \
|
||||||
Common/CVector2i.h \
|
Common/CVector2i.h \
|
||||||
|
@ -321,7 +319,8 @@ HEADERS += \
|
||||||
UI/WAnimParamsEditor.h \
|
UI/WAnimParamsEditor.h \
|
||||||
Resource/CCollisionMeshGroup.h \
|
Resource/CCollisionMeshGroup.h \
|
||||||
Core/CFrustumPlanes.h \
|
Core/CFrustumPlanes.h \
|
||||||
Core/CLightParameters.h
|
Core/CLightParameters.h \
|
||||||
|
Core/SViewInfo.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
UI/CStartWindow.ui \
|
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)
|
bool CTexture::WriteDDS(COutputStream& out)
|
||||||
{
|
{
|
||||||
if (!out.IsValid()) return false;
|
if (!out.IsValid()) return false;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define CTEXTURE_H
|
#define CTEXTURE_H
|
||||||
|
|
||||||
#include <Common/types.h>
|
#include <Common/types.h>
|
||||||
|
#include <Common/CVector2f.h>
|
||||||
#include <FileIO/FileIO.h>
|
#include <FileIO/FileIO.h>
|
||||||
#include <gl/glew.h>
|
#include <gl/glew.h>
|
||||||
#include "CResource.h"
|
#include "CResource.h"
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
bool BufferGL();
|
bool BufferGL();
|
||||||
void Bind(u32 GLTextureUnit);
|
void Bind(u32 GLTextureUnit);
|
||||||
void Resize(u32 Width, u32 Height);
|
void Resize(u32 Width, u32 Height);
|
||||||
|
float ReadTexelAlpha(const CVector2f& TexCoord);
|
||||||
bool WriteDDS(COutputStream& out);
|
bool WriteDDS(COutputStream& out);
|
||||||
|
|
||||||
// Getters
|
// 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;
|
return eCollisionNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCollisionNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
void CCollisionNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
if (!mpCollision) return;
|
if (!mpCollision) return;
|
||||||
if (!frustum.BoxInFrustum(AABox())) return;
|
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||||
|
|
||||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
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
|
// todo
|
||||||
SRayIntersection Result;
|
SRayIntersection Result;
|
||||||
|
|
|
@ -12,10 +12,10 @@ class CCollisionNode : public CSceneNode
|
||||||
public:
|
public:
|
||||||
CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0);
|
CCollisionNode(CSceneManager *pScene, CSceneNode *pParent = 0, CCollisionMeshGroup *pCollision = 0);
|
||||||
ENodeType NodeType();
|
ENodeType NodeType();
|
||||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustumPlanes);
|
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
void Draw(ERenderOptions Options);
|
void Draw(ERenderOptions Options);
|
||||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
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);
|
void SetCollision(CCollisionMeshGroup *pCollision);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CLightNode.h"
|
#include "CLightNode.h"
|
||||||
|
#include <Common/Math.h>
|
||||||
#include <Core/CDrawUtil.h>
|
#include <Core/CDrawUtil.h>
|
||||||
#include <Core/CGraphics.h>
|
#include <Core/CGraphics.h>
|
||||||
#include <Core/CRenderer.h>
|
#include <Core/CRenderer.h>
|
||||||
|
@ -24,16 +25,16 @@ ENodeType CLightNode::NodeType()
|
||||||
return eLightNode;
|
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);
|
pRenderer->AddOpaqueMesh(this, 0, CAABox(mPosition + 0.5f, mPosition - 0.5f), eDrawMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLightNode::Draw(ERenderOptions /*Options*/)
|
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
|
// Below commented-out code is for light radius visualization as a bounding box
|
||||||
/*float r = mLight->GetRadius();
|
/*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
|
CVector2f BillScale = BillboardScale();
|
||||||
bool allowBackfaces = ((options & eEnableBackfaceCull) == 0);
|
float ScaleXY = (BillScale.x > BillScale.y ? BillScale.x : BillScale.y);
|
||||||
|
|
||||||
if (!allowBackfaces && (AABox().IsPointInBox(Ray.Origin())))
|
CAABox BillBox = CAABox(mPosition + CVector3f(-ScaleXY, -ScaleXY, -BillScale.y),
|
||||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
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)
|
SRayIntersection CLightNode::RayNodeIntersectTest(const CRay& Ray, u32 AssetID, const SViewInfo& ViewInfo)
|
||||||
return SRayIntersection(true, BoxResult.second, this, 0);
|
{
|
||||||
|
// 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
|
else
|
||||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
out.Hit = false;
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLight* CLightNode::Light()
|
CLight* CLightNode::Light()
|
||||||
{
|
{
|
||||||
return mpLight;
|
return mpLight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CVector2f CLightNode::BillboardScale()
|
||||||
|
{
|
||||||
|
return mScale.xz() * 0.75f;
|
||||||
|
}
|
||||||
|
|
|
@ -10,11 +10,13 @@ class CLightNode : public CSceneNode
|
||||||
public:
|
public:
|
||||||
CLightNode(CSceneManager *pScene, CSceneNode *pParent = 0, CLight *Light = 0);
|
CLightNode(CSceneManager *pScene, CSceneNode *pParent = 0, CLight *Light = 0);
|
||||||
ENodeType NodeType();
|
ENodeType NodeType();
|
||||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
void Draw(ERenderOptions Options);
|
void Draw(ERenderOptions Options);
|
||||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
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();
|
CLight* Light();
|
||||||
|
CVector2f BillboardScale();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLIGHTNODE_H
|
#endif // CLIGHTNODE_H
|
||||||
|
|
|
@ -16,10 +16,10 @@ ENodeType CModelNode::NodeType()
|
||||||
return eModelNode;
|
return eModelNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModelNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
void CModelNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
if (!mpModel) return;
|
if (!mpModel) return;
|
||||||
if (!frustum.BoxInFrustum(AABox())) return;
|
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||||
|
|
||||||
if (!mpModel->HasTransparency(mActiveMatSet))
|
if (!mpModel->HasTransparency(mActiveMatSet))
|
||||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
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++)
|
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))
|
if (!mpModel->IsSurfaceTransparent(iSurf, mActiveMatSet))
|
||||||
pRenderer->AddOpaqueMesh(this, iSurf, mpModel->GetSurfaceAABox(iSurf).Transformed(Transform()), eDrawAsset);
|
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;
|
SRayIntersection out;
|
||||||
out.pNode = this;
|
out.pNode = this;
|
||||||
out.AssetIndex = AssetID;
|
out.AssetIndex = AssetID;
|
||||||
|
|
||||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||||
|
ERenderOptions options = ViewInfo.pRenderer->RenderOptions();
|
||||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||||
|
|
||||||
if (Result.first)
|
if (Result.first)
|
||||||
|
|
|
@ -16,11 +16,11 @@ public:
|
||||||
explicit CModelNode(CSceneManager *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
|
explicit CModelNode(CSceneManager *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
|
||||||
|
|
||||||
virtual ENodeType NodeType();
|
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 Draw(ERenderOptions Options);
|
||||||
virtual void DrawAsset(ERenderOptions Options, u32 asset);
|
virtual void DrawAsset(ERenderOptions Options, u32 asset);
|
||||||
virtual void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
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 SetModel(CModel *pModel);
|
||||||
void SetMatSet(u32 MatSet);
|
void SetMatSet(u32 MatSet);
|
||||||
|
|
|
@ -15,12 +15,12 @@ public:
|
||||||
return eRootNode;
|
return eRootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void AddToRenderer(CRenderer *, const CFrustumPlanes&) {}
|
inline void AddToRenderer(CRenderer *, const SViewInfo&) {}
|
||||||
inline void Draw(ERenderOptions) {}
|
inline void Draw(ERenderOptions) {}
|
||||||
inline void DrawAsset(ERenderOptions, u32) {}
|
inline void DrawAsset(ERenderOptions, u32) {}
|
||||||
inline void RayAABoxIntersectTest(CRayCollisionTester &) {}
|
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);
|
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
virtual void DrawAsset(ERenderOptions options, u32 asset) = 0;
|
virtual void DrawAsset(ERenderOptions options, u32 asset) = 0;
|
||||||
virtual void DrawSelection();
|
virtual void DrawSelection();
|
||||||
virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester);
|
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;
|
virtual bool IsVisible() const;
|
||||||
|
|
||||||
void Unparent();
|
void Unparent();
|
||||||
|
|
|
@ -101,18 +101,18 @@ TString CScriptNode::PrefixedName() const
|
||||||
return "[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->InstanceName();
|
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;
|
if (!mpInstance) return;
|
||||||
|
|
||||||
ERenderOptions options = pRenderer->RenderOptions();
|
ERenderOptions options = pRenderer->RenderOptions();
|
||||||
|
|
||||||
if (options & eDrawObjectCollision)
|
if (options & eDrawObjectCollision)
|
||||||
mpCollisionNode->AddToRenderer(pRenderer, frustum);
|
mpCollisionNode->AddToRenderer(pRenderer, ViewInfo);
|
||||||
|
|
||||||
if (options & eDrawObjects)
|
if (options & eDrawObjects)
|
||||||
{
|
{
|
||||||
if (frustum.BoxInFrustum(AABox()))
|
if (ViewInfo.ViewFrustum.BoxInFrustum(AABox()))
|
||||||
{
|
{
|
||||||
if (!mpActiveModel)
|
if (!mpActiveModel)
|
||||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
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++)
|
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))
|
if (!mpActiveModel->IsSurfaceTransparent(s, 0))
|
||||||
pRenderer->AddOpaqueMesh(this, s, mpActiveModel->GetSurfaceAABox(s).Transformed(Transform()), eDrawAsset);
|
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);
|
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawSelection);
|
||||||
|
|
||||||
if (mHasVolumePreview)
|
if (mHasVolumePreview)
|
||||||
mpVolumePreviewNode->AddToRenderer(pRenderer, frustum);
|
mpVolumePreviewNode->AddToRenderer(pRenderer, ViewInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ void CScriptNode::Draw(ERenderOptions Options)
|
||||||
// Draw billboard
|
// Draw billboard
|
||||||
else if (mpBillboard)
|
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
|
// If no model or billboard, default to drawing a purple box
|
||||||
|
@ -243,27 +243,44 @@ void CScriptNode::RayAABoxIntersectTest(CRayCollisionTester &Tester)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const CRay& Ray = Tester.Ray();
|
const CRay& Ray = Tester.Ray();
|
||||||
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
|
||||||
|
|
||||||
if (BoxResult.first)
|
if (mpActiveModel || !mpBillboard)
|
||||||
{
|
{
|
||||||
if (mpActiveModel)
|
std::pair<bool,float> BoxResult = AABox().IntersectsRay(Ray);
|
||||||
{
|
|
||||||
for (u32 iSurf = 0; iSurf < mpActiveModel->GetSurfaceCount(); iSurf++)
|
|
||||||
{
|
|
||||||
std::pair<bool,float> SurfResult = mpActiveModel->GetSurfaceAABox(iSurf).Transformed(Transform()).IntersectsRay(Ray);
|
|
||||||
|
|
||||||
if (SurfResult.first)
|
if (BoxResult.first)
|
||||||
Tester.AddNode(this, iSurf, SurfResult.second);
|
{
|
||||||
|
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;
|
SRayIntersection out;
|
||||||
out.pNode = this;
|
out.pNode = this;
|
||||||
|
@ -271,20 +288,75 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID,
|
||||||
|
|
||||||
if (options & eDrawObjects)
|
if (options & eDrawObjects)
|
||||||
{
|
{
|
||||||
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
// Model test
|
||||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
if (mpActiveModel || !mpBillboard)
|
||||||
|
|
||||||
if (Result.first)
|
|
||||||
{
|
{
|
||||||
out.Hit = true;
|
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
||||||
|
|
||||||
CVector3f HitPoint = TransformedRay.PointOnRay(Result.second);
|
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||||
CVector3f WorldHitPoint = Transform() * HitPoint;
|
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||||
out.Distance = Math::Distance(Ray.Origin(), WorldHitPoint);
|
|
||||||
|
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
|
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;
|
else out.Hit = false;
|
||||||
|
|
||||||
|
@ -380,3 +452,9 @@ CAABox CScriptNode::PreviewVolumeAABox()
|
||||||
else
|
else
|
||||||
return mpVolumePreviewNode->AABox();
|
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);
|
CScriptNode(CSceneManager *pScene, CSceneNode *pParent = 0, CScriptObject *pObject = 0);
|
||||||
ENodeType NodeType();
|
ENodeType NodeType();
|
||||||
TString PrefixedName() const;
|
TString PrefixedName() const;
|
||||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
void Draw(ERenderOptions Options);
|
void Draw(ERenderOptions Options);
|
||||||
void DrawAsset(ERenderOptions Options, u32 Asset);
|
void DrawAsset(ERenderOptions Options, u32 Asset);
|
||||||
void DrawSelection();
|
void DrawSelection();
|
||||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
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;
|
bool IsVisible() const;
|
||||||
CScriptObject* Object();
|
CScriptObject* Object();
|
||||||
CModel* ActiveModel();
|
CModel* ActiveModel();
|
||||||
void GeneratePosition();
|
void GeneratePosition();
|
||||||
bool HasPreviewVolume();
|
bool HasPreviewVolume();
|
||||||
CAABox PreviewVolumeAABox();
|
CAABox PreviewVolumeAABox();
|
||||||
|
CVector2f BillboardScale();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CSCRIPTNODE_H
|
#endif // CSCRIPTNODE_H
|
||||||
|
|
|
@ -19,11 +19,11 @@ ENodeType CStaticNode::NodeType()
|
||||||
return eStaticNode;
|
return eStaticNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CStaticNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum)
|
void CStaticNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo)
|
||||||
{
|
{
|
||||||
if (!mpModel) return;
|
if (!mpModel) return;
|
||||||
if (mpModel->IsOccluder()) return;
|
if (mpModel->IsOccluder()) return;
|
||||||
if (!frustum.BoxInFrustum(AABox())) return;
|
if (!ViewInfo.ViewFrustum.BoxInFrustum(AABox())) return;
|
||||||
|
|
||||||
if (!mpModel->IsTransparent())
|
if (!mpModel->IsTransparent())
|
||||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||||
|
@ -33,7 +33,7 @@ void CStaticNode::AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frus
|
||||||
u32 sm_count = mpModel->GetSurfaceCount();
|
u32 sm_count = mpModel->GetSurfaceCount();
|
||||||
for (u32 s = 0; s < sm_count; s++)
|
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);
|
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;
|
SRayIntersection out;
|
||||||
out.pNode = this;
|
out.pNode = this;
|
||||||
out.AssetIndex = AssetID;
|
out.AssetIndex = AssetID;
|
||||||
|
|
||||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||||
|
ERenderOptions options = ViewInfo.pRenderer->RenderOptions();
|
||||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, ((options & eEnableBackfaceCull) == 0));
|
||||||
|
|
||||||
if (Result.first)
|
if (Result.first)
|
||||||
|
|
|
@ -11,11 +11,11 @@ class CStaticNode : public CSceneNode
|
||||||
public:
|
public:
|
||||||
CStaticNode(CSceneManager *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0);
|
CStaticNode(CSceneManager *pScene, CSceneNode *pParent = 0, CStaticModel *pModel = 0);
|
||||||
ENodeType NodeType();
|
ENodeType NodeType();
|
||||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
void Draw(ERenderOptions Options);
|
void Draw(ERenderOptions Options);
|
||||||
void DrawAsset(ERenderOptions Options, u32 asset);
|
void DrawAsset(ERenderOptions Options, u32 asset);
|
||||||
void RayAABoxIntersectTest(CRayCollisionTester &Tester);
|
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
|
#endif // CSTATICNODE_H
|
||||||
|
|
|
@ -14,6 +14,7 @@ CBasicViewport::CBasicViewport(QWidget *pParent) :
|
||||||
{
|
{
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
mCamera.SetAspectRatio((float) width() / height());
|
mCamera.SetAspectRatio((float) width() / height());
|
||||||
|
mViewInfo.pCamera = &mCamera;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBasicViewport::~CBasicViewport()
|
CBasicViewport::~CBasicViewport()
|
||||||
|
@ -47,9 +48,11 @@ void CBasicViewport::paintGL()
|
||||||
glViewport(0, 0, width(), height());
|
glViewport(0, 0, width(), height());
|
||||||
glLineWidth(1.f);
|
glLineWidth(1.f);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
mViewInfo.ViewFrustum = mCamera.FrustumPlanes();
|
||||||
|
CGraphics::sMVPBlock.ProjectionMatrix = mCamera.ProjectionMatrix();
|
||||||
|
|
||||||
// Actual rendering is intended to be handled by subclassing CBasicViewport and
|
// Actual rendering is intended to be handled by subclassing CBasicViewport and
|
||||||
// reimplementing Render().
|
// reimplementing Paint().
|
||||||
Paint();
|
Paint();
|
||||||
|
|
||||||
// Finally, draw XYZ axes in the corner
|
// Finally, draw XYZ axes in the corner
|
||||||
|
@ -247,6 +250,15 @@ void CBasicViewport::ProcessInput()
|
||||||
if (IsKeyboardInputActive())
|
if (IsKeyboardInputActive())
|
||||||
mCamera.ProcessKeyInput((EKeyInputs) mKeysPressed, DeltaTime);
|
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
|
// Check user input
|
||||||
CheckUserInput();
|
CheckUserInput();
|
||||||
}
|
}
|
||||||
|
@ -259,10 +271,6 @@ void CBasicViewport::Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ PRIVATE ************
|
// ************ PRIVATE ************
|
||||||
void CBasicViewport::ProcessInput(double /*DeltaTime*/)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBasicViewport::DrawAxes()
|
void CBasicViewport::DrawAxes()
|
||||||
{
|
{
|
||||||
// Draw 64x64 axes in lower-left corner with 8px margins
|
// Draw 64x64 axes in lower-left corner with 8px margins
|
||||||
|
@ -272,7 +280,7 @@ void CBasicViewport::DrawAxes()
|
||||||
glDepthRange(0.f, 1.f);
|
glDepthRange(0.f, 1.f);
|
||||||
|
|
||||||
CGraphics::sMVPBlock.ModelMatrix = CTransform4f::TranslationMatrix(mCamera.Direction() * 5).ToMatrix4f();
|
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::sMVPBlock.ProjectionMatrix = Math::OrthographicMatrix(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f);
|
||||||
CGraphics::UpdateMVPBlock();
|
CGraphics::UpdateMVPBlock();
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
|
||||||
#include <Core/CRenderer.h>
|
#include <Core/CRenderer.h>
|
||||||
|
#include <Core/SViewInfo.h>
|
||||||
#include <Common/CRay.h>
|
#include <Common/CRay.h>
|
||||||
#include <Common/CTimer.h>
|
#include <Common/CTimer.h>
|
||||||
#include <Common/CVector2i.h>
|
#include <Common/CVector2i.h>
|
||||||
|
@ -23,6 +24,7 @@ protected:
|
||||||
CCamera mCamera;
|
CCamera mCamera;
|
||||||
CTimer mFrameTimer;
|
CTimer mFrameTimer;
|
||||||
double mLastDrawTime;
|
double mLastDrawTime;
|
||||||
|
SViewInfo mViewInfo;
|
||||||
|
|
||||||
// Cursor settings
|
// Cursor settings
|
||||||
QCursor mCursorState;
|
QCursor mCursorState;
|
||||||
|
@ -55,7 +57,6 @@ public:
|
||||||
bool IsCursorVisible();
|
bool IsCursorVisible();
|
||||||
bool IsMouseInputActive();
|
bool IsMouseInputActive();
|
||||||
bool IsKeyboardInputActive();
|
bool IsKeyboardInputActive();
|
||||||
CRenderer* Renderer();
|
|
||||||
CCamera& Camera();
|
CCamera& Camera();
|
||||||
CRay CastRay();
|
CRay CastRay();
|
||||||
CVector2f MouseDeviceCoordinates();
|
CVector2f MouseDeviceCoordinates();
|
||||||
|
@ -74,7 +75,6 @@ protected slots:
|
||||||
virtual void OnMouseRelease(QMouseEvent* /*pEvent*/) {}
|
virtual void OnMouseRelease(QMouseEvent* /*pEvent*/) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ProcessInput(double DeltaTime);
|
|
||||||
void DrawAxes();
|
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
|
// 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
|
// in order to account for scale changes based on camera distance
|
||||||
|
|
|
@ -124,7 +124,7 @@ public:
|
||||||
CGizmo();
|
CGizmo();
|
||||||
~CGizmo();
|
~CGizmo();
|
||||||
|
|
||||||
void AddToRenderer(CRenderer *pRenderer, const CFrustumPlanes& frustum);
|
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& ViewInfo);
|
||||||
void DrawAsset(ERenderOptions options, u32 asset);
|
void DrawAsset(ERenderOptions options, u32 asset);
|
||||||
|
|
||||||
void IncrementSize();
|
void IncrementSize();
|
||||||
|
|
|
@ -49,8 +49,8 @@ void CModelEditorViewport::Paint()
|
||||||
else if (mMode == eDrawMesh)
|
else if (mMode == eDrawMesh)
|
||||||
{
|
{
|
||||||
CDrawUtil::DrawGrid();
|
CDrawUtil::DrawGrid();
|
||||||
mpModelNode->AddToRenderer(mpRenderer, mCamera.FrustumPlanes());
|
mpModelNode->AddToRenderer(mpRenderer, mViewInfo);
|
||||||
mpRenderer->RenderBuckets(mCamera);
|
mpRenderer->RenderBuckets(mViewInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (mMode == eDrawSphere)
|
else if (mMode == eDrawSphere)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "CSceneViewport.h"
|
#include "CSceneViewport.h"
|
||||||
#include "undo/UndoCommands.h"
|
#include "undo/UndoCommands.h"
|
||||||
|
#include <Core/SViewInfo.h>
|
||||||
|
|
||||||
CSceneViewport::CSceneViewport(QWidget *pParent)
|
CSceneViewport::CSceneViewport(QWidget *pParent)
|
||||||
: CBasicViewport(pParent),
|
: CBasicViewport(pParent),
|
||||||
|
@ -13,6 +14,9 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
|
||||||
mpRenderer = new CRenderer();
|
mpRenderer = new CRenderer();
|
||||||
mpRenderer->SetClearColor(CColor::skBlack);
|
mpRenderer->SetClearColor(CColor::skBlack);
|
||||||
mpRenderer->SetViewportSize(width(), height());
|
mpRenderer->SetViewportSize(width(), height());
|
||||||
|
|
||||||
|
mViewInfo.pScene = mpScene;
|
||||||
|
mViewInfo.pRenderer = mpRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSceneViewport::~CSceneViewport()
|
CSceneViewport::~CSceneViewport()
|
||||||
|
@ -77,7 +81,7 @@ void CSceneViewport::SceneRayCast(const CRay& ray)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SRayIntersection result = mpScene->SceneRayCast(ray, mpRenderer->RenderOptions());
|
SRayIntersection result = mpScene->SceneRayCast(ray, mViewInfo);
|
||||||
|
|
||||||
if (result.Hit)
|
if (result.Hit)
|
||||||
{
|
{
|
||||||
|
@ -131,12 +135,12 @@ void CSceneViewport::Paint()
|
||||||
if (mDrawSky)
|
if (mDrawSky)
|
||||||
{
|
{
|
||||||
CModel *pSky = mpScene->GetActiveSkybox();
|
CModel *pSky = mpScene->GetActiveSkybox();
|
||||||
if (pSky) mpRenderer->RenderSky(pSky, mCamera);
|
if (pSky) mpRenderer->RenderSky(pSky, mViewInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCamera.LoadMatrices();
|
mCamera.LoadMatrices();
|
||||||
mpScene->AddSceneToRenderer(mpRenderer, mCamera);
|
mpScene->AddSceneToRenderer(mpRenderer, mViewInfo);
|
||||||
mpRenderer->RenderBuckets(mCamera);
|
mpRenderer->RenderBuckets(mViewInfo);
|
||||||
mpRenderer->RenderBloom();
|
mpRenderer->RenderBloom();
|
||||||
|
|
||||||
if (mpEditor->IsGizmoVisible())
|
if (mpEditor->IsGizmoVisible())
|
||||||
|
@ -146,8 +150,8 @@ void CSceneViewport::Paint()
|
||||||
|
|
||||||
mpRenderer->ClearDepthBuffer();
|
mpRenderer->ClearDepthBuffer();
|
||||||
pGizmo->UpdateForCamera(mCamera);
|
pGizmo->UpdateForCamera(mCamera);
|
||||||
pGizmo->AddToRenderer(mpRenderer, mCamera.FrustumPlanes());
|
pGizmo->AddToRenderer(mpRenderer, mViewInfo);
|
||||||
mpRenderer->RenderBuckets(mCamera);
|
mpRenderer->RenderBuckets(mViewInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
mpRenderer->EndFrame();
|
mpRenderer->EndFrame();
|
||||||
|
|
Loading…
Reference in New Issue