forked from 0ad/0ad
Add BoundingSphere, SOverlaySphere.
BoundingSphere is similar to a bounding box, but more spherical. SOverlaySphere is useful for visualising BoundingSphere (it's quite inefficient and should only be used for debug functionality). Normalise the camera frustum clipping planes, so that IsSphereVisible gives the correct result. This was SVN commit r15261.
This commit is contained in:
parent
3b0fee9073
commit
fe3315376c
7
binaries/data/mods/public/shaders/arb/overlay_solid.fp
Normal file
7
binaries/data/mods/public/shaders/arb/overlay_solid.fp
Normal file
@ -0,0 +1,7 @@
|
||||
!!ARBfp1.0
|
||||
|
||||
PARAM color = program.local[0];
|
||||
|
||||
MOV result.color, color;
|
||||
|
||||
END
|
17
binaries/data/mods/public/shaders/arb/overlay_solid.vp
Normal file
17
binaries/data/mods/public/shaders/arb/overlay_solid.vp
Normal file
@ -0,0 +1,17 @@
|
||||
!!ARBvp1.0
|
||||
|
||||
PARAM transform[4] = { program.local[0..3] };
|
||||
|
||||
TEMP position;
|
||||
|
||||
DP4 position.x, transform[0], vertex.position;
|
||||
DP4 position.y, transform[1], vertex.position;
|
||||
DP4 position.z, transform[2], vertex.position;
|
||||
MOV position.w, 1.0;
|
||||
|
||||
DP4 result.position.x, state.matrix.mvp.row[0], position;
|
||||
DP4 result.position.y, state.matrix.mvp.row[1], position;
|
||||
DP4 result.position.z, state.matrix.mvp.row[2], position;
|
||||
DP4 result.position.w, state.matrix.mvp.row[3], position;
|
||||
|
||||
END
|
13
binaries/data/mods/public/shaders/arb/overlay_solid.xml
Normal file
13
binaries/data/mods/public/shaders/arb/overlay_solid.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<program type="arb">
|
||||
|
||||
<vertex file="arb/overlay_solid.vp">
|
||||
<uniform name="transform" loc="0" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
</vertex>
|
||||
|
||||
<fragment file="arb/overlay_solid.fp">
|
||||
<uniform name="color" loc="0" type="vec4"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<effect>
|
||||
|
||||
<technique>
|
||||
<require shaders="arb"/>
|
||||
<pass shader="arb/overlay_solid"/>
|
||||
</technique>
|
||||
|
||||
</effect>
|
@ -126,11 +126,16 @@ void CCamera::UpdateFrustum(const CBoundingBoxAligned& scissor)
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Y = -scissor[0].Z*MatFinal._42 + MatFinal._32;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Norm.Z = -scissor[0].Z*MatFinal._43 + MatFinal._33;
|
||||
m_ViewFrustum.m_aPlanes[5].m_Dist = -scissor[0].Z*MatFinal._44 + MatFinal._34;
|
||||
|
||||
for (size_t i = 0; i < 6; ++i)
|
||||
m_ViewFrustum.m_aPlanes[i].Normalize();
|
||||
}
|
||||
|
||||
void CCamera::ClipFrustum(const CPlane& clipPlane)
|
||||
{
|
||||
m_ViewFrustum.AddPlane(clipPlane);
|
||||
CPlane normClipPlane = clipPlane;
|
||||
normClipPlane.Normalize();
|
||||
m_ViewFrustum.AddPlane(normClipPlane);
|
||||
}
|
||||
|
||||
void CCamera::SetViewPort(const SViewPort& viewport)
|
||||
|
@ -93,26 +93,21 @@ bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D &
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFrustum::IsSphereVisible (const CVector3D ¢er, float radius) const
|
||||
{
|
||||
for (size_t i=0; i<m_NumPlanes; i++)
|
||||
for (size_t i = 0; i < m_NumPlanes; i++)
|
||||
{
|
||||
float Dist = m_aPlanes[i].DistanceToPlane (center);
|
||||
|
||||
//is it behind the plane
|
||||
if (Dist < 0)
|
||||
{
|
||||
//if non of it falls in front its outside the
|
||||
//frustum
|
||||
if (-Dist > radius)
|
||||
return false;
|
||||
}
|
||||
float Dist = m_aPlanes[i].DistanceToPlane(center);
|
||||
// If none of the sphere is in front of the plane, then
|
||||
// it is outside the frustum
|
||||
if (-Dist > radius)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CFrustum::IsBoxVisible (const CVector3D &position,const CBoundingBoxAligned &bounds) const
|
||||
{
|
||||
//basically for every plane we calculate the furthest point
|
||||
|
@ -154,6 +154,15 @@ struct SOverlayQuad
|
||||
CColor m_Color;
|
||||
};
|
||||
|
||||
struct SOverlaySphere
|
||||
{
|
||||
SOverlaySphere() : m_Radius(0) { }
|
||||
|
||||
CVector3D m_Center;
|
||||
float m_Radius;
|
||||
CColor m_Color;
|
||||
};
|
||||
|
||||
// TODO: OverlayText
|
||||
|
||||
#endif // INCLUDED_GRAPHICS_OVERLAY
|
||||
|
@ -55,6 +55,15 @@ public:
|
||||
*/
|
||||
void Transform(const CMatrix3D& m, CBoundingBoxOriented& result) const;
|
||||
|
||||
/**
|
||||
* Translates these bounds by @p v, and writes the result to @p result.
|
||||
*/
|
||||
void Translate(const CVector3D& v, CBoundingBoxAligned& result) const
|
||||
{
|
||||
result.m_Data[0] = m_Data[0] + v;
|
||||
result.m_Data[1] = m_Data[1] + v;
|
||||
}
|
||||
|
||||
CVector3D& operator[](int index) { return m_Data[index]; }
|
||||
const CVector3D& operator[](int index) const { return m_Data[index]; }
|
||||
|
||||
|
60
source/maths/BoundingSphere.h
Normal file
60
source/maths/BoundingSphere.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2014 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_BOUNDINGSPHERE
|
||||
#define INCLUDED_BOUNDINGSPHERE
|
||||
|
||||
#include "maths/BoundingBoxAligned.h"
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
class CBoundingSphere
|
||||
{
|
||||
private:
|
||||
CVector3D m_Center;
|
||||
float m_Radius;
|
||||
|
||||
public:
|
||||
CBoundingSphere() : m_Radius(0) { }
|
||||
|
||||
CBoundingSphere(const CVector3D& center, float radius) : m_Center(center), m_Radius(radius) { }
|
||||
|
||||
/**
|
||||
* Construct a bounding sphere that encompasses a bounding box
|
||||
* swept through all possible rotations around the origin.
|
||||
*/
|
||||
static CBoundingSphere FromSweptBox(const CBoundingBoxAligned& bbox)
|
||||
{
|
||||
float maxX = std::max(fabsf(bbox[0].X), fabsf(bbox[1].X));
|
||||
float maxY = std::max(fabsf(bbox[0].Y), fabsf(bbox[1].Y));
|
||||
float maxZ = std::max(fabsf(bbox[0].Z), fabsf(bbox[1].Z));
|
||||
float radius = sqrtf(maxX*maxX + maxY*maxY + maxZ*maxZ);
|
||||
|
||||
return CBoundingSphere(CVector3D(0.f, 0.f, 0.f), radius);
|
||||
}
|
||||
|
||||
const CVector3D& GetCenter()
|
||||
{
|
||||
return m_Center;
|
||||
}
|
||||
|
||||
float GetRadius() const
|
||||
{
|
||||
return m_Radius;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INCLUDED_BOUNDINGSPHERE
|
@ -107,6 +107,7 @@ X(murkiness)
|
||||
X(normalMap)
|
||||
X(normalMap2)
|
||||
X(objectColor)
|
||||
X(overlay_solid)
|
||||
X(particle)
|
||||
X(particle_solid)
|
||||
X(playerColor)
|
||||
|
@ -88,6 +88,7 @@ struct OverlayRendererInternals
|
||||
std::vector<SOverlayTexturedLine*> texlines;
|
||||
std::vector<SOverlaySprite*> sprites;
|
||||
std::vector<SOverlayQuad*> quads;
|
||||
std::vector<SOverlaySphere*> spheres;
|
||||
|
||||
QuadBatchMap quadBatchMap;
|
||||
|
||||
@ -111,6 +112,11 @@ struct OverlayRendererInternals
|
||||
CShaderDefines defsOverlayLineAlwaysVisible;
|
||||
CShaderDefines defsQuadOverlay;
|
||||
|
||||
// Geometry for a unit sphere
|
||||
std::vector<float> sphereVertexes;
|
||||
std::vector<u16> sphereIndexes;
|
||||
void GenerateSphere();
|
||||
|
||||
/// Performs one-time setup. Called from CRenderer::Open, after graphics capabilities have
|
||||
/// been detected. Note that no VBOs must be created before this is called, since the shader
|
||||
/// path and graphics capabilities are not guaranteed to be stable before this point.
|
||||
@ -223,12 +229,19 @@ void OverlayRenderer::Submit(SOverlayQuad* overlay)
|
||||
m->quads.push_back(overlay);
|
||||
}
|
||||
|
||||
void OverlayRenderer::Submit(SOverlaySphere* overlay)
|
||||
{
|
||||
m->spheres.push_back(overlay);
|
||||
}
|
||||
|
||||
void OverlayRenderer::EndFrame()
|
||||
{
|
||||
m->lines.clear();
|
||||
m->texlines.clear();
|
||||
m->sprites.clear();
|
||||
m->quads.clear();
|
||||
m->spheres.clear();
|
||||
|
||||
// this should leave the capacity unchanged, which is okay since it
|
||||
// won't be very large or very variable
|
||||
|
||||
@ -384,6 +397,7 @@ void OverlayRenderer::RenderOverlaysAfterWater()
|
||||
|
||||
RenderTexturedOverlayLines();
|
||||
RenderQuadOverlays();
|
||||
RenderSphereOverlays();
|
||||
}
|
||||
|
||||
void OverlayRenderer::RenderTexturedOverlayLines()
|
||||
@ -629,3 +643,118 @@ void OverlayRenderer::RenderForegroundOverlays(const CCamera& viewCamera)
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TessellateSphereFace(const CVector3D& a, u16 ai,
|
||||
const CVector3D& b, u16 bi,
|
||||
const CVector3D& c, u16 ci,
|
||||
std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
indexes.push_back(ai);
|
||||
indexes.push_back(bi);
|
||||
indexes.push_back(ci);
|
||||
}
|
||||
else
|
||||
{
|
||||
CVector3D d = (a + b).Normalized();
|
||||
CVector3D e = (b + c).Normalized();
|
||||
CVector3D f = (c + a).Normalized();
|
||||
int di = vertexes.size() / 3; vertexes.push_back(d.X); vertexes.push_back(d.Y); vertexes.push_back(d.Z);
|
||||
int ei = vertexes.size() / 3; vertexes.push_back(e.X); vertexes.push_back(e.Y); vertexes.push_back(e.Z);
|
||||
int fi = vertexes.size() / 3; vertexes.push_back(f.X); vertexes.push_back(f.Y); vertexes.push_back(f.Z);
|
||||
TessellateSphereFace(a,ai, d,di, f,fi, vertexes, indexes, level-1);
|
||||
TessellateSphereFace(d,di, b,bi, e,ei, vertexes, indexes, level-1);
|
||||
TessellateSphereFace(f,fi, e,ei, c,ci, vertexes, indexes, level-1);
|
||||
TessellateSphereFace(d,di, e,ei, f,fi, vertexes, indexes, level-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void TessellateSphere(std::vector<float>& vertexes, std::vector<u16>& indexes, int level)
|
||||
{
|
||||
/* Start with a tetrahedron, then tessellate */
|
||||
float s = sqrtf(0.5f);
|
||||
#define VERT(a,b,c) vertexes.push_back(a); vertexes.push_back(b); vertexes.push_back(c);
|
||||
VERT(-s, 0, -s);
|
||||
VERT( s, 0, -s);
|
||||
VERT( s, 0, s);
|
||||
VERT(-s, 0, s);
|
||||
VERT( 0, -1, 0);
|
||||
VERT( 0, 1, 0);
|
||||
#define FACE(a,b,c) \
|
||||
TessellateSphereFace( \
|
||||
CVector3D(vertexes[a*3], vertexes[a*3+1], vertexes[a*3+2]), a, \
|
||||
CVector3D(vertexes[b*3], vertexes[b*3+1], vertexes[b*3+2]), b, \
|
||||
CVector3D(vertexes[c*3], vertexes[c*3+1], vertexes[c*3+2]), c, \
|
||||
vertexes, indexes, level);
|
||||
FACE(0,4,1);
|
||||
FACE(1,4,2);
|
||||
FACE(2,4,3);
|
||||
FACE(3,4,0);
|
||||
FACE(1,5,0);
|
||||
FACE(2,5,1);
|
||||
FACE(3,5,2);
|
||||
FACE(0,5,3);
|
||||
#undef FACE
|
||||
#undef VERT
|
||||
}
|
||||
|
||||
void OverlayRendererInternals::GenerateSphere()
|
||||
{
|
||||
if (sphereVertexes.empty())
|
||||
TessellateSphere(sphereVertexes, sphereIndexes, 3);
|
||||
}
|
||||
|
||||
void OverlayRenderer::RenderSphereOverlays()
|
||||
{
|
||||
PROFILE3_GPU("overlays (spheres)");
|
||||
|
||||
if (g_Renderer.GetRenderPath() != CRenderer::RP_SHADER)
|
||||
return;
|
||||
|
||||
if (m->spheres.empty())
|
||||
return;
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glDepthMask(0);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
CShaderProgramPtr shader;
|
||||
CShaderTechniquePtr tech;
|
||||
|
||||
tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid);
|
||||
tech->BeginPass();
|
||||
shader = tech->GetShader();
|
||||
|
||||
m->GenerateSphere();
|
||||
|
||||
shader->VertexPointer(3, GL_FLOAT, 0, &m->sphereVertexes[0]);
|
||||
|
||||
for (size_t i = 0; i < m->spheres.size(); ++i)
|
||||
{
|
||||
SOverlaySphere* sphere = m->spheres[i];
|
||||
|
||||
CMatrix3D transform;
|
||||
transform.SetIdentity();
|
||||
transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius);
|
||||
transform.Translate(sphere->m_Center);
|
||||
|
||||
shader->Uniform(str_transform, transform);
|
||||
|
||||
shader->Uniform(str_color, sphere->m_Color);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, m->sphereIndexes.size(), GL_UNSIGNED_SHORT, &m->sphereIndexes[0]);
|
||||
|
||||
g_Renderer.GetStats().m_DrawCalls++;
|
||||
g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3;
|
||||
}
|
||||
|
||||
tech->EndPass();
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glDepthMask(1);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ struct SOverlayLine;
|
||||
struct SOverlayTexturedLine;
|
||||
struct SOverlaySprite;
|
||||
struct SOverlayQuad;
|
||||
struct SOverlaySphere;
|
||||
class CCamera;
|
||||
|
||||
struct OverlayRendererInternals;
|
||||
@ -74,6 +75,13 @@ public:
|
||||
*/
|
||||
void Submit(SOverlayQuad* overlay);
|
||||
|
||||
/**
|
||||
* Add a sphere overlay for rendering in this frame.
|
||||
* @param overlay Must be non-null. The pointed-to object must remain valid at least
|
||||
* until the end of the frame.
|
||||
*/
|
||||
void Submit(SOverlaySphere* overlay);
|
||||
|
||||
/**
|
||||
* Prepare internal data structures for rendering.
|
||||
* Must be called after all Submit calls for a frame, and before
|
||||
@ -132,6 +140,11 @@ private:
|
||||
*/
|
||||
void RenderQuadOverlays();
|
||||
|
||||
/**
|
||||
* Helper method; batch-renders all sphere quad overlays.
|
||||
*/
|
||||
void RenderSphereOverlays();
|
||||
|
||||
private:
|
||||
OverlayRendererInternals* m;
|
||||
};
|
||||
|
@ -1749,6 +1749,11 @@ void CRenderer::Submit(SOverlayQuad* overlay)
|
||||
m->overlayRenderer.Submit(overlay);
|
||||
}
|
||||
|
||||
void CRenderer::Submit(SOverlaySphere* overlay)
|
||||
{
|
||||
m->overlayRenderer.Submit(overlay);
|
||||
}
|
||||
|
||||
void CRenderer::Submit(CModelDecal* decal)
|
||||
{
|
||||
m->terrainRenderer.Submit(decal);
|
||||
|
@ -354,6 +354,7 @@ protected:
|
||||
void Submit(SOverlayQuad* overlay);
|
||||
void Submit(CModelDecal* decal);
|
||||
void Submit(CParticleEmitter* emitter);
|
||||
void Submit(SOverlaySphere* overlay);
|
||||
void SubmitNonRecursive(CModel* model);
|
||||
//END: Implementation of SceneCollector
|
||||
|
||||
|
@ -40,6 +40,7 @@ struct SOverlayLine;
|
||||
struct SOverlayTexturedLine;
|
||||
struct SOverlaySprite;
|
||||
struct SOverlayQuad;
|
||||
struct SOverlaySphere;
|
||||
|
||||
class SceneCollector;
|
||||
|
||||
@ -109,6 +110,11 @@ public:
|
||||
*/
|
||||
virtual void Submit(SOverlayQuad* overlay) = 0;
|
||||
|
||||
/**
|
||||
* Submit a sphere overlay.
|
||||
*/
|
||||
virtual void Submit(SOverlaySphere* overlay) = 0;
|
||||
|
||||
/**
|
||||
* Submit a terrain decal.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user