Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Bolsee <benoit.bolsee@online.be>2009-04-14 00:08:33 +0400
committerBenoit Bolsee <benoit.bolsee@online.be>2009-04-14 00:08:33 +0400
commit0b8661ab4da1a7cfbc756640649a2d07bb36cc64 (patch)
tree6d171db30ddcba3d379dea04b2da9449203419a6 /source/gameengine/Physics
parent6f12e584a97f664c654ddfbe5f721d2a7be3d491 (diff)
BGE: Occlusion culling and other performance improvements.
Added occlusion culling capability in the BGE. More info: http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.49/Game_Engine#BGE_Scenegraph_improvement MSVC, scons, cmake, Makefile updated. Other minor performance improvements: - The rasterizer was computing the openGL model matrix of the objects too many times - DBVT view frustrum culling was not properly culling behind the near plane: Large objects behind the camera were sent to the GPU - Remove all references to mesh split/join feature as it is not yet functional
Diffstat (limited to 'source/gameengine/Physics')
-rw-r--r--source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/Bullet/CMakeLists.txt7
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp553
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/Bullet/Makefile7
-rw-r--r--source/gameengine/Physics/Bullet/SConscript14
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h4
9 files changed, 577 insertions, 16 deletions
diff --git a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
index e4aaef1803d..2e4709cf420 100644
--- a/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
+++ b/source/gameengine/Physics/BlOde/OdePhysicsEnvironment.h
@@ -55,7 +55,7 @@ public:
virtual void removeConstraint(void * constraintid);
virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
+ virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes) { return false; }
//gamelogic callbacks
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
index 6bab9858011..2cb2a540d97 100644
--- a/source/gameengine/Physics/Bullet/CMakeLists.txt
+++ b/source/gameengine/Physics/Bullet/CMakeLists.txt
@@ -30,11 +30,18 @@ SET(INC
.
../common
../../../../extern/bullet2/src
+ ../../../../extern/glew/include
../../../../intern/moto/include
../../../kernel/gen_system
../../../../intern/string
+ ../../../intern/SoundSystem
../../Rasterizer
+ ../../Ketsji
+ ../../Expressions
+ ../../GameLogic
+ ../../SceneGraph
../../../../source/blender/makesdna
+ ${PYTHON_INC}
)
BLENDERLIB(bf_bullet "${SRC}" "${INC}")
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index faf1ca42766..858416bae6a 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -33,6 +33,10 @@ subject to the following restrictions:
#include "PHY_IMotionState.h"
+#include "KX_GameObject.h"
+#include "RAS_MeshObject.h"
+#include "RAS_Polygon.h"
+#include "RAS_TexVert.h"
#define CCD_CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
@@ -47,7 +51,9 @@ btRaycastVehicle::btVehicleTuning gTuning;
#endif //NEW_BULLET_VEHICLE_SUPPORT
#include "LinearMath/btAabbUtil2.h"
-
+#include "MT_Matrix4x4.h"
+#include "MT_Vector3.h"
+#include "GL/glew.h"
#ifdef WIN32
void DrawRasterizerLine(const float* from,const float* to,int color);
@@ -1189,17 +1195,492 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallbac
return result.m_controller;
}
+// Handles occlusion culling.
+// The implementation is based on the CDTestFramework
+struct OcclusionBuffer
+{
+ struct WriteOCL
+ {
+ static inline bool Process(btScalar& q,btScalar v) { if(q<v) q=v;return(false); }
+ static inline void Occlusion(bool& flag) { flag = true; }
+ };
+ struct QueryOCL
+ {
+ static inline bool Process(btScalar& q,btScalar v) { return(q<=v); }
+ static inline void Occlusion(bool& flag) { }
+ };
+ btScalar* m_buffer;
+ size_t m_bufferSize;
+ bool m_initialized;
+ bool m_occlusion;
+ int m_sizes[2];
+ btScalar m_scales[2];
+ btScalar m_offsets[2];
+ btScalar m_wtc[16]; // world to clip transform
+ btScalar m_mtc[16]; // model to clip transform
+ // constructor: size=largest dimension of the buffer.
+ // Buffer size depends on aspect ratio
+ OcclusionBuffer()
+ {
+ m_initialized=false;
+ m_occlusion = false;
+ m_buffer == NULL;
+ m_bufferSize = 0;
+ }
+ // multiplication of column major matrices: m=m1*m2
+ template<typename T1, typename T2>
+ void CMmat4mul(btScalar* m, const T1* m1, const T2* m2)
+ {
+ m[ 0] = btScalar(m1[ 0]*m2[ 0]+m1[ 4]*m2[ 1]+m1[ 8]*m2[ 2]+m1[12]*m2[ 3]);
+ m[ 1] = btScalar(m1[ 1]*m2[ 0]+m1[ 5]*m2[ 1]+m1[ 9]*m2[ 2]+m1[13]*m2[ 3]);
+ m[ 2] = btScalar(m1[ 2]*m2[ 0]+m1[ 6]*m2[ 1]+m1[10]*m2[ 2]+m1[14]*m2[ 3]);
+ m[ 3] = btScalar(m1[ 3]*m2[ 0]+m1[ 7]*m2[ 1]+m1[11]*m2[ 2]+m1[15]*m2[ 3]);
+
+ m[ 4] = btScalar(m1[ 0]*m2[ 4]+m1[ 4]*m2[ 5]+m1[ 8]*m2[ 6]+m1[12]*m2[ 7]);
+ m[ 5] = btScalar(m1[ 1]*m2[ 4]+m1[ 5]*m2[ 5]+m1[ 9]*m2[ 6]+m1[13]*m2[ 7]);
+ m[ 6] = btScalar(m1[ 2]*m2[ 4]+m1[ 6]*m2[ 5]+m1[10]*m2[ 6]+m1[14]*m2[ 7]);
+ m[ 7] = btScalar(m1[ 3]*m2[ 4]+m1[ 7]*m2[ 5]+m1[11]*m2[ 6]+m1[15]*m2[ 7]);
+
+ m[ 8] = btScalar(m1[ 0]*m2[ 8]+m1[ 4]*m2[ 9]+m1[ 8]*m2[10]+m1[12]*m2[11]);
+ m[ 9] = btScalar(m1[ 1]*m2[ 8]+m1[ 5]*m2[ 9]+m1[ 9]*m2[10]+m1[13]*m2[11]);
+ m[10] = btScalar(m1[ 2]*m2[ 8]+m1[ 6]*m2[ 9]+m1[10]*m2[10]+m1[14]*m2[11]);
+ m[11] = btScalar(m1[ 3]*m2[ 8]+m1[ 7]*m2[ 9]+m1[11]*m2[10]+m1[15]*m2[11]);
+
+ m[12] = btScalar(m1[ 0]*m2[12]+m1[ 4]*m2[13]+m1[ 8]*m2[14]+m1[12]*m2[15]);
+ m[13] = btScalar(m1[ 1]*m2[12]+m1[ 5]*m2[13]+m1[ 9]*m2[14]+m1[13]*m2[15]);
+ m[14] = btScalar(m1[ 2]*m2[12]+m1[ 6]*m2[13]+m1[10]*m2[14]+m1[14]*m2[15]);
+ m[15] = btScalar(m1[ 3]*m2[12]+m1[ 7]*m2[13]+m1[11]*m2[14]+m1[15]*m2[15]);
+ }
+ void setup(int size)
+ {
+ m_initialized=false;
+ m_occlusion=false;
+ // compute the size of the buffer
+ GLint v[4];
+ GLdouble m[16],p[16];
+ int maxsize;
+ double ratio;
+ glGetIntegerv(GL_VIEWPORT,v);
+ maxsize = (v[2] > v[3]) ? v[2] : v[3];
+ assert(maxsize > 0);
+ ratio = 1.0/(2*maxsize);
+ // ensure even number
+ m_sizes[0] = 2*((int)(size*v[2]*ratio+0.5));
+ m_sizes[1] = 2*((int)(size*v[3]*ratio+0.5));
+ m_scales[0]=btScalar(m_sizes[0]/2);
+ m_scales[1]=btScalar(m_sizes[1]/2);
+ m_offsets[0]=m_scales[0]+0.5f;
+ m_offsets[1]=m_scales[1]+0.5f;
+ // prepare matrix
+ // at this time of the rendering, the modelview matrix is the
+ // world to camera transformation and the projection matrix is
+ // camera to clip transformation. combine both so that
+ glGetDoublev(GL_MODELVIEW_MATRIX,m);
+ glGetDoublev(GL_PROJECTION_MATRIX,p);
+ CMmat4mul(m_wtc,p,m);
+ }
+ void initialize()
+ {
+ size_t newsize = (m_sizes[0]*m_sizes[1])*sizeof(btScalar);
+ if (m_buffer)
+ {
+ // see if we can reuse
+ if (newsize > m_bufferSize)
+ {
+ free(m_buffer);
+ m_buffer = NULL;
+ m_bufferSize = 0;
+ }
+ }
+ if (!m_buffer)
+ {
+ m_buffer = (btScalar*)calloc(1, newsize);
+ m_bufferSize = newsize;
+ } else
+ {
+ // buffer exists already, just clears it
+ memset(m_buffer, 0, newsize);
+ }
+ // memory allocate must succeed
+ assert(m_buffer != NULL);
+ m_initialized = true;
+ m_occlusion = false;
+ }
+ void SetModelMatrix(double *fl)
+ {
+ CMmat4mul(m_mtc,m_wtc,fl);
+ if (!m_initialized)
+ initialize();
+ }
+
+ // transform a segment in world coordinate to clip coordinate
+ void transformW(const btVector3& x, btVector4& t)
+ {
+ t[0] = x[0]*m_wtc[0]+x[1]*m_wtc[4]+x[2]*m_wtc[8]+m_wtc[12];
+ t[1] = x[0]*m_wtc[1]+x[1]*m_wtc[5]+x[2]*m_wtc[9]+m_wtc[13];
+ t[2] = x[0]*m_wtc[2]+x[1]*m_wtc[6]+x[2]*m_wtc[10]+m_wtc[14];
+ t[3] = x[0]*m_wtc[3]+x[1]*m_wtc[7]+x[2]*m_wtc[11]+m_wtc[15];
+ }
+ void transformM(const float* x, btVector4& t)
+ {
+ t[0] = x[0]*m_mtc[0]+x[1]*m_mtc[4]+x[2]*m_mtc[8]+m_mtc[12];
+ t[1] = x[0]*m_mtc[1]+x[1]*m_mtc[5]+x[2]*m_mtc[9]+m_mtc[13];
+ t[2] = x[0]*m_mtc[2]+x[1]*m_mtc[6]+x[2]*m_mtc[10]+m_mtc[14];
+ t[3] = x[0]*m_mtc[3]+x[1]*m_mtc[7]+x[2]*m_mtc[11]+m_mtc[15];
+ }
+ // convert polygon to device coordinates
+ static bool project(btVector4* p,int n)
+ {
+ for(int i=0;i<n;++i)
+ {
+ const btScalar iw=1/p[i][3];
+ p[i][2]=1/p[i][3];
+ p[i][0]*=p[i][2];
+ p[i][1]*=p[i][2];
+ }
+ return(true);
+ }
+ // pi: closed polygon in clip coordinate, NP = number of segments
+ // po: same polygon with clipped segments removed
+ template <const int NP>
+ static int clip(const btVector4* pi,btVector4* po)
+ {
+ btScalar s[2*NP];
+ btVector4 pn[2*NP], *p;
+ int i, j, m, n, ni;
+ // deal with near clipping
+ for(i=0, m=0;i<NP;++i)
+ {
+ s[i]=pi[i][2]+pi[i][3];
+ if(s[i]<0) m+=1<<i;
+ }
+ if(m==((1<<NP)-1))
+ return(0);
+ if(m!=0)
+ {
+ for(i=NP-1,j=0,n=0;j<NP;i=j++)
+ {
+ const btVector4& a=pi[i];
+ const btVector4& b=pi[j];
+ const btScalar t=s[i]/(a[3]+a[2]-b[3]-b[2]);
+ if((t>0)&&(t<1))
+ {
+ pn[n][0] = a[0]+(b[0]-a[0])*t;
+ pn[n][1] = a[1]+(b[1]-a[1])*t;
+ pn[n][2] = a[2]+(b[2]-a[2])*t;
+ pn[n][3] = a[3]+(b[3]-a[3])*t;
+ ++n;
+ }
+ if(s[j]>0) pn[n++]=b;
+ }
+ // ready to test far clipping, start from the modified polygon
+ pi = pn;
+ ni = n;
+ } else
+ {
+ // no clipping on the near plane, keep same vector
+ ni = NP;
+ }
+ // now deal with far clipping
+ for(i=0, m=0;i<ni;++i)
+ {
+ s[i]=pi[i][2]-pi[i][3];
+ if(s[i]>0) m+=1<<i;
+ }
+ if(m==((1<<ni)-1))
+ return(0);
+ if(m!=0)
+ {
+ for(i=ni-1,j=0,n=0;j<ni;i=j++)
+ {
+ const btVector4& a=pi[i];
+ const btVector4& b=pi[j];
+ const btScalar t=s[i]/(a[2]-a[3]-b[2]+b[3]);
+ if((t>0)&&(t<1))
+ {
+ po[n][0] = a[0]+(b[0]-a[0])*t;
+ po[n][1] = a[1]+(b[1]-a[1])*t;
+ po[n][2] = a[2]+(b[2]-a[2])*t;
+ po[n][3] = a[3]+(b[3]-a[3])*t;
+ ++n;
+ }
+ if(s[j]<0) po[n++]=b;
+ }
+ return(n);
+ }
+ for(int i=0;i<ni;++i) po[i]=pi[i];
+ return(ni);
+ }
+ // write or check a triangle to buffer. a,b,c in device coordinates (-1,+1)
+ template <typename POLICY>
+ inline bool draw( const btVector4& a,
+ const btVector4& b,
+ const btVector4& c,
+ const float face,
+ const btScalar minarea)
+ {
+ const btScalar a2=cross(b-a,c-a)[2];
+ if((face*a2)<0.f || btFabs(a2)<minarea)
+ return false;
+ // further down we are normally going to write to the Zbuffer, mark it so
+ POLICY::Occlusion(m_occlusion);
+
+ int x[3], y[3], ib=1, ic=2;
+ btScalar z[3];
+ x[0]=(int)(a.x()*m_scales[0]+m_offsets[0]);
+ y[0]=(int)(a.y()*m_scales[1]+m_offsets[1]);
+ z[0]=a.z();
+ if (a2 < 0.f)
+ {
+ // negative aire is possible with double face => must
+ // change the order of b and c otherwise the algorithm doesn't work
+ ib=2;
+ ic=1;
+ }
+ x[ib]=(int)(b.x()*m_scales[0]+m_offsets[0]);
+ x[ic]=(int)(c.x()*m_scales[0]+m_offsets[0]);
+ y[ib]=(int)(b.y()*m_scales[1]+m_offsets[1]);
+ y[ic]=(int)(c.y()*m_scales[1]+m_offsets[1]);
+ z[ib]=b.z();
+ z[ic]=c.z();
+ const int mix=btMax(0,btMin(x[0],btMin(x[1],x[2])));
+ const int mxx=btMin(m_sizes[0],1+btMax(x[0],btMax(x[1],x[2])));
+ const int miy=btMax(0,btMin(y[0],btMin(y[1],y[2])));
+ const int mxy=btMin(m_sizes[1],1+btMax(y[0],btMax(y[1],y[2])));
+ const int width=mxx-mix;
+ const int height=mxy-miy;
+ if ((width*height) <= 1)
+ {
+ // degenerated in at most one single pixel
+ btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+ // use for loop to detect the case where width or height == 0
+ for(int iy=miy;iy<mxy;++iy)
+ {
+ for(int ix=mix;ix<mxx;++ix)
+ {
+ if(POLICY::Process(*scan,z[0]))
+ return(true);
+ if(POLICY::Process(*scan,z[1]))
+ return(true);
+ if(POLICY::Process(*scan,z[2]))
+ return(true);
+ }
+ }
+ } else if (width == 1)
+ {
+ // Degenerated in at least 2 vertical lines
+ // The algorithm below doesn't work when face has a single pixel width
+ // We cannot use general formulas because the plane is degenerated.
+ // We have to interpolate along the 3 edges that overlaps and process each pixel.
+ // sort the y coord to make formula simpler
+ int ytmp;
+ btScalar ztmp;
+ if (y[0] > y[1]) { ytmp=y[1];y[1]=y[0];y[0]=ytmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
+ if (y[0] > y[2]) { ytmp=y[2];y[2]=y[0];y[0]=ytmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
+ if (y[1] > y[2]) { ytmp=y[2];y[2]=y[1];y[1]=ytmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
+ int dy[]={ y[0]-y[1],
+ y[1]-y[2],
+ y[2]-y[0]};
+ btScalar dzy[3];
+ dzy[0] = (dy[0]) ? (z[0]-z[1])/dy[0] : btScalar(0.f);
+ dzy[1] = (dy[1]) ? (z[1]-z[2])/dy[1] : btScalar(0.f);
+ dzy[2] = (dy[2]) ? (z[2]-z[0])/dy[2] : btScalar(0.f);
+ btScalar v[3] = { dzy[0]*(miy-y[0])+z[0],
+ dzy[1]*(miy-y[1])+z[1],
+ dzy[2]*(miy-y[2])+z[2] };
+ dy[0] = y[1]-y[0];
+ dy[1] = y[0]-y[1];
+ dy[2] = y[2]-y[0];
+ btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+ for(int iy=miy;iy<mxy;++iy)
+ {
+ if(dy[0] >= 0 && POLICY::Process(*scan,v[0]))
+ return(true);
+ if(dy[1] >= 0 && POLICY::Process(*scan,v[1]))
+ return(true);
+ if(dy[2] >= 0 && POLICY::Process(*scan,v[2]))
+ return(true);
+ scan+=m_sizes[0];
+ v[0] += dzy[0]; v[1] += dzy[1]; v[2] += dzy[2];
+ dy[0]--; dy[1]++, dy[2]--;
+ }
+ } else if (height == 1)
+ {
+ // Degenerated in at least 2 horizontal lines
+ // The algorithm below doesn't work when face has a single pixel width
+ // We cannot use general formulas because the plane is degenerated.
+ // We have to interpolate along the 3 edges that overlaps and process each pixel.
+ int xtmp;
+ btScalar ztmp;
+ if (x[0] > x[1]) { xtmp=x[1];x[1]=x[0];x[0]=xtmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
+ if (x[0] > x[2]) { xtmp=x[2];x[2]=x[0];x[0]=xtmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
+ if (x[1] > x[2]) { xtmp=x[2];x[2]=x[1];x[1]=xtmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
+ int dx[]={ x[0]-x[1],
+ x[1]-x[2],
+ x[2]-x[0]};
+ btScalar dzx[3];
+ dzx[0] = (dx[0]) ? (z[0]-z[1])/dx[0] : btScalar(0.f);
+ dzx[1] = (dx[1]) ? (z[1]-z[2])/dx[1] : btScalar(0.f);
+ dzx[2] = (dx[2]) ? (z[2]-z[0])/dx[2] : btScalar(0.f);
+ btScalar v[3] = { dzx[0]*(mix-x[0])+z[0],
+ dzx[1]*(mix-x[1])+z[1],
+ dzx[2]*(mix-x[2])+z[2] };
+ dx[0] = x[1]-x[0];
+ dx[1] = x[0]-x[1];
+ dx[2] = x[2]-x[0];
+ btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+ for(int ix=mix;ix<mxx;++ix)
+ {
+ if(dx[0] >= 0 && POLICY::Process(*scan,v[0]))
+ return(true);
+ if(dx[1] >= 0 && POLICY::Process(*scan,v[1]))
+ return(true);
+ if(dx[2] >= 0 && POLICY::Process(*scan,v[2]))
+ return(true);
+ scan++;
+ v[0] += dzx[0]; v[1] += dzx[1]; v[2] += dzx[2];
+ dx[0]--; dx[1]++, dx[2]--;
+ }
+ } else
+ {
+ // general case
+ const int dx[]={ y[0]-y[1],
+ y[1]-y[2],
+ y[2]-y[0]};
+ const int dy[]={ x[1]-x[0]-dx[0]*width,
+ x[2]-x[1]-dx[1]*width,
+ x[0]-x[2]-dx[2]*width};
+ const int a=x[2]*y[0]+x[0]*y[1]-x[2]*y[1]-x[0]*y[2]+x[1]*y[2]-x[1]*y[0];
+ const btScalar ia=1/(btScalar)a;
+ const btScalar dzx=ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1]));
+ const btScalar dzy=ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width);
+ int c[]={ miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0],
+ miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1],
+ miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]};
+ btScalar v=ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2]));
+ btScalar* scan=&m_buffer[miy*m_sizes[0]];
+ for(int iy=miy;iy<mxy;++iy)
+ {
+ for(int ix=mix;ix<mxx;++ix)
+ {
+ if((c[0]>=0)&&(c[1]>=0)&&(c[2]>=0))
+ {
+ if(POLICY::Process(scan[ix],v))
+ return(true);
+ }
+ c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx;
+ }
+ c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy;
+ scan+=m_sizes[0];
+ }
+ }
+ return(false);
+ }
+ // clip than write or check a polygon
+ template <const int NP,typename POLICY>
+ inline bool clipDraw( const btVector4* p,
+ const float face,
+ btScalar minarea)
+ {
+ btVector4 o[NP*2];
+ int n=clip<NP>(p,o);
+ bool earlyexit=false;
+ if (n)
+ {
+ project(o,n);
+ for(int i=2;i<n && !earlyexit;++i)
+ {
+ earlyexit|=draw<POLICY>(o[0],o[i-1],o[i],face,minarea);
+ }
+ }
+ return(earlyexit);
+ }
+ // add a triangle (in model coordinate)
+ // face = 0.f if face is double side,
+ // = 1.f if face is single sided and scale is positive
+ // = -1.f if face is single sided and scale is negative
+ void appendOccluderM(const float* a,
+ const float* b,
+ const float* c,
+ const float face)
+ {
+ btVector4 p[3];
+ transformM(a,p[0]);
+ transformM(b,p[1]);
+ transformM(c,p[2]);
+ clipDraw<3,WriteOCL>(p,face,btScalar(0.f));
+ }
+ // add a quad (in model coordinate)
+ void appendOccluderM(const float* a,
+ const float* b,
+ const float* c,
+ const float* d,
+ const float face)
+ {
+ btVector4 p[4];
+ transformM(a,p[0]);
+ transformM(b,p[1]);
+ transformM(c,p[2]);
+ transformM(d,p[3]);
+ clipDraw<4,WriteOCL>(p,face,btScalar(0.f));
+ }
+ // query occluder for a box (c=center, e=extend) in world coordinate
+ inline bool queryOccluderW( const btVector3& c,
+ const btVector3& e)
+ {
+ if (!m_occlusion)
+ // no occlusion yet, no need to check
+ return true;
+ btVector4 x[8];
+ transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2]),x[0]);
+ transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2]),x[1]);
+ transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2]),x[2]);
+ transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2]),x[3]);
+ transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2]),x[4]);
+ transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2]),x[5]);
+ transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2]),x[6]);
+ transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]),x[7]);
+ for(int i=0;i<8;++i)
+ {
+ // the box is clipped, it's probably a large box, don't waste our time to check
+ if((x[i][2]+x[i][3])<=0) return(true);
+ }
+ static const int d[]={ 1,0,3,2,
+ 4,5,6,7,
+ 4,7,3,0,
+ 6,5,1,2,
+ 7,6,2,3,
+ 5,4,0,1};
+ for(int i=0;i<(sizeof(d)/sizeof(d[0]));)
+ {
+ const btVector4 p[]={ x[d[i++]],
+ x[d[i++]],
+ x[d[i++]],
+ x[d[i++]]};
+ if(clipDraw<4,QueryOCL>(p,1.f,0.f))
+ return(true);
+ }
+ return(false);
+ }
+};
+
+
struct DbvtCullingCallback : btDbvt::ICollide
{
PHY_CullingCallback m_clientCallback;
void* m_userData;
+ OcclusionBuffer *m_ocb;
DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData)
{
m_clientCallback = clientCallback;
m_userData = userData;
+ m_ocb = NULL;
+ }
+ bool Descent(const btDbvtNode* node)
+ {
+ return(m_ocb->queryOccluderW(node->volume.Center(),node->volume.Extents()));
}
-
void Process(const btDbvtNode* node,btScalar depth)
{
Process(node);
@@ -1210,31 +1691,83 @@ struct DbvtCullingCallback : btDbvt::ICollide
// the client object is a graphic controller
CcdGraphicController* ctrl = static_cast<CcdGraphicController*>(proxy->m_clientObject);
KX_ClientObjectInfo* info = (KX_ClientObjectInfo*)ctrl->getNewClientInfo();
+ if (m_ocb)
+ {
+ // means we are doing occlusion culling. Check if this object is an occluders
+ KX_GameObject* gameobj = KX_GameObject::GetClientObject(info);
+ if (gameobj && gameobj->GetOccluder())
+ {
+ double* fl = gameobj->GetOpenGLMatrixPtr()->getPointer();
+ // this will create the occlusion buffer if not already done
+ // and compute the transformation from model local space to clip space
+ m_ocb->SetModelMatrix(fl);
+ float face = (gameobj->IsNegativeScaling()) ? -1.0f : 1.0f;
+ // walk through the meshes and for each add to buffer
+ for (int i=0; i<gameobj->GetMeshCount(); i++)
+ {
+ RAS_MeshObject* meshobj = gameobj->GetMesh(i);
+ const float *v1, *v2, *v3, *v4;
+
+ int polycount = meshobj->NumPolygons();
+ for (int j=0; j<polycount; j++)
+ {
+ RAS_Polygon* poly = meshobj->GetPolygon(j);
+ switch (poly->VertexCount())
+ {
+ case 3:
+ v1 = poly->GetVertex(0)->getXYZ();
+ v2 = poly->GetVertex(1)->getXYZ();
+ v3 = poly->GetVertex(2)->getXYZ();
+ m_ocb->appendOccluderM(v1,v2,v3,((poly->IsTwoside())?0.f:face));
+ break;
+ case 4:
+ v1 = poly->GetVertex(0)->getXYZ();
+ v2 = poly->GetVertex(1)->getXYZ();
+ v3 = poly->GetVertex(2)->getXYZ();
+ v4 = poly->GetVertex(3)->getXYZ();
+ m_ocb->appendOccluderM(v1,v2,v3,v4,((poly->IsTwoside())?0.f:face));
+ break;
+ }
+ }
+ }
+ }
+ }
if (info)
(*m_clientCallback)(info, m_userData);
}
};
-bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes)
+static OcclusionBuffer gOcb;
+bool CcdPhysicsEnvironment::cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes)
{
if (!m_cullingTree)
return false;
DbvtCullingCallback dispatcher(callback, userData);
- btVector3 planes_n[5];
- btScalar planes_o[5];
- if (nplanes > 5)
- nplanes = 5;
+ btVector3 planes_n[6];
+ btScalar planes_o[6];
+ if (nplanes > 6)
+ nplanes = 6;
for (int i=0; i<nplanes; i++)
{
planes_n[i].setValue(planes[i][0], planes[i][1], planes[i][2]);
planes_o[i] = planes[i][3];
}
- btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
- btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);
+ // if occlusionRes != 0 => occlusion culling
+ if (occlusionRes)
+ {
+ gOcb.setup(occlusionRes);
+ dispatcher.m_ocb = &gOcb;
+ // occlusion culling, the direction of the view is taken from the first plan which MUST be the near plane
+ btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);
+ btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher);
+ }else
+ {
+ btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher);
+ btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher);
+ }
return true;
}
-
int CcdPhysicsEnvironment::getNumContactPoints()
{
return 0;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
index ddbcbe6b4d6..f861621ae37 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
@@ -172,7 +172,7 @@ protected:
btTypedConstraint* getConstraintById(int constraintId);
virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes);
+ virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes);
//Methods for gamelogic collision/physics callbacks
diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile
index bf3573138f7..48e537bb6a3 100644
--- a/source/gameengine/Physics/Bullet/Makefile
+++ b/source/gameengine/Physics/Bullet/Makefile
@@ -39,9 +39,16 @@ CPPFLAGS += -I$(NAN_BULLET2)/include
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
CPPFLAGS += -I$(NAN_STRING)/include
CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_GLEW)/include
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include
CPPFLAGS += -I../../../kernel/gen_system
CPPFLAGS += -I../../Physics/common
CPPFLAGS += -I../../Physics/Dummy
CPPFLAGS += -I../../Rasterizer
+CPPFLAGS += -I../../Ketsji
+CPPFLAGS += -I../../Expressions
+CPPFLAGS += -I../../GameLogic
+CPPFLAGS += -I../../SceneGraph
CPPFLAGS += -I../../../../source/blender/makesdna
diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript
index f3b6549089d..115ab8bf730 100644
--- a/source/gameengine/Physics/Bullet/SConscript
+++ b/source/gameengine/Physics/Bullet/SConscript
@@ -3,9 +3,21 @@ Import ('env')
sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp'
-incs = '. ../common #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer #source/blender/makesdna'
+incs = '. ../common'
+incs += ' #source/kernel/gen_system'
+incs += ' #intern/string'
+incs += ' #intern/moto/include'
+incs += ' #extern/glew/include'
+incs += ' #source/gameengine/Rasterizer'
+incs += ' #source/gameengine/Ketsji'
+incs += ' #source/gameengine/Expressions'
+incs += ' #source/gameengine/GameLogic'
+incs += ' #source/gameengine/SceneGraph'
+incs += ' #source/blender/makesdna'
+incs += ' #intern/SoundSystem'
incs += ' ' + env['BF_BULLET_INC']
+incs += ' ' + env['BF_PYTHON_INC']
cxxflags = []
if env['OURPLATFORM']=='win32-vc':
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
index fae1844d505..4e15e6ec130 100644
--- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
@@ -70,7 +70,7 @@ public:
}
virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes) { return false; }
+ virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4* planes, int nplanes, int occlusionRes) { return false; }
//gamelogic callbacks
diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
index 9942a367451..418a361a065 100644
--- a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h
@@ -76,7 +76,7 @@ public:
}
virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes) { return false; }
+ virtual bool cullingTest(PHY_CullingCallback callback, void* userData, PHY__Vector4 *planes, int nplanes, int occlusionRes) { return false; }
//gamelogic callbacks
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index 5edafe6b51e..9a4500c3214 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -143,7 +143,9 @@ class PHY_IPhysicsEnvironment
virtual PHY_IPhysicsController* rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0;
//culling based on physical broad phase
- virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber) = 0;
+ // the plane number must be set as follow: near, far, left, right, top, botton
+ // the near plane must be the first one and must always be present, it is used to get the direction of the view
+ virtual bool cullingTest(PHY_CullingCallback callback, void *userData, PHY__Vector4* planeNormals, int planeNumber, int occlusionRes) = 0;
//Methods for gamelogic collision/physics callbacks
//todo: