1
0
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:
Ykkrosh 2014-06-01 18:05:46 +00:00
parent 3b0fee9073
commit fe3315376c
15 changed files with 292 additions and 13 deletions

View File

@ -0,0 +1,7 @@
!!ARBfp1.0
PARAM color = program.local[0];
MOV result.color, color;
END

View 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

View 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>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<effect>
<technique>
<require shaders="arb"/>
<pass shader="arb/overlay_solid"/>
</technique>
</effect>

View File

@ -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)

View File

@ -93,26 +93,21 @@ bool CFrustum::DoesSegmentIntersect(const CVector3D& startRef, const CVector3D &
}
return false;
}
bool CFrustum::IsSphereVisible (const CVector3D &center, 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

View File

@ -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

View File

@ -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]; }

View 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

View File

@ -107,6 +107,7 @@ X(murkiness)
X(normalMap)
X(normalMap2)
X(objectColor)
X(overlay_solid)
X(particle)
X(particle_solid)
X(playerColor)

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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.
*/