本人学的OpenGL ES 都是从http://edu.csdn.net/lecturer/440 地方学的!喜欢的支持一下
{拾取 1:给碰撞的物体整个盒子-->包围盒AxisAlignedBox(别名aabb) 2:用射线与盒子相交 ray.intersects(盒子) 3:加过程 }
1:给碰撞的物体整个盒子-->包围盒AxisAlignedBox(别名aabb)
//轴向包围盒 template<typename T> class AxisAlignedBox { public: enum Extent { EXTENT_NULL,//是否被初始化 EXTENT_FINITE,//有限大 EXTENT_INFINITE//无限大 }; public: tvec3<T> _minimum;//最小值 tvec3<T> _maximum;//最大值 Extent _extent;//扩展变量 public: /* 1-----2 /| /| / | / | 5-----4 | | 0--|--3 | / | / |/ |/ 6-----7 */ typedef enum { FAR_LEFT_BOTTOM = 0, FAR_LEFT_TOP = 1, FAR_RIGHT_TOP = 2, FAR_RIGHT_BOTTOM = 3, NEAR_RIGHT_BOTTOM = 7, NEAR_LEFT_BOTTOM = 6, NEAR_LEFT_TOP = 5, NEAR_RIGHT_TOP = 4 } CornerEnum; AxisAlignedBox() { _minimum = tvec3<T>( T(-0.5), T(-0.5), T(-0.5) ); _maximum = tvec3<T>( T(0.5), T(0.5), T(0.5) ); _extent = EXTENT_NULL; } AxisAlignedBox(const AxisAlignedBox & rkBox) { setExtents( rkBox._minimum, rkBox._maximum ); _extent = rkBox._extent; } AxisAlignedBox( const tvec3<T>& min, const tvec3<T>& max ) { setExtents( min, max ); } AxisAlignedBox(T mx, T my, T mz, T Mx, T My, T Mz ) { setExtents( mx, my, mz, Mx, My, Mz ); } AxisAlignedBox<T>& operator=(const AxisAlignedBox<T>& right) { setExtents(right._minimum, right._maximum); return *this; } ~AxisAlignedBox(){} //设置/获取最小值 void setMinimum(const tvec3<T>& mins) { _minimum = mins; } void setMinimum(T x,T y, T z){ _minimum = tvec3<T>(x,y,z); } const tvec3<T>& getMinimum(void) const { return _minimum; } tvec3<T>& getMinimum(void) { return _minimum; } //设置/获取最大值 const tvec3<T>& getMaximum(void) const{ return _maximum; } tvec3<T>& getMaximum(void) { return _maximum; } void setMaximum( const tvec3<T>& vec ){ _maximum = vec; } void setMaximum( T x, T y, T z ){ _maximum.x = x; _maximum.y = y; _maximum.z = z; } void setMaximumX( T x ){_maximum.x = x;} void setMaximumY( T y ){_maximum.y = y;} void setMaximumZ( T z ){_maximum.z = z;} /** 设置包围盒大小 * @param min 最小值 * @param max 最大值 */ void setExtents( const tvec3<T>& min, const tvec3<T>& max ) { _minimum = min; _maximum = max; _extent = EXTENT_FINITE; } /** 设置包围盒大小 * @param mx my mz 最小值xyz * @param Mx My Mz 最大值xyz */ void setExtents(T mx, T my, T mz, T Mx, T My, T Mz ){ _minimum.x = mx; _minimum.y = my; _minimum.z = mz; _maximum.x = Mx; _maximum.y = My; _maximum.z = Mz; _extent = EXTENT_FINITE; } /** 获取包围盒8个顶点的坐标 Returns a pointer to an array of 8 corner points, useful for collision vs. non-aligned objects. @remarks If the order of these corners is important, they are as follows: The 4 points of the minimum Z face (note that because Ogre uses right-handed coordinates, the minimum Z is at the 'back' of the box) starting with the minimum point of all, then anticlockwise around this face (if you are looking onto the face from outside the box). Then the 4 points of the maximum Z face, starting with maximum point of all, then anticlockwise around this face (looking onto the face from outside the box). Like this: <pre> 1-----2 /| /| / | / | 5-----4 | | 0--|--3 | / | / |/ |/ 6-----7 </pre> @remarks as this implementation uses a static member, make sure to use your own copy ! */ void getAllCorners(tvec3<T> mpCorners[8] ) const { mpCorners[0] = _minimum; mpCorners[1].x = _minimum.x; mpCorners[1].y = _maximum.y; mpCorners[1].z = _minimum.z; mpCorners[2].x = _maximum.x; mpCorners[2].y = _maximum.y; mpCorners[2].z = _minimum.z; mpCorners[3].x = _maximum.x; mpCorners[3].y = _minimum.y; mpCorners[3].z = _minimum.z; mpCorners[4] = _maximum; mpCorners[5].x = _minimum.x; mpCorners[5].y = _maximum.y; mpCorners[5].z = _maximum.z; mpCorners[6].x = _minimum.x; mpCorners[6].y = _minimum.y; mpCorners[6].z = _maximum.z; mpCorners[7].x = _maximum.x; mpCorners[7].y = _minimum.y; mpCorners[7].z = _maximum.z; } /** 获取局部顶点 * @param cornerToGet 方向枚举值 * gets the position of one of the corners */ tvec3<T> getCorner(CornerEnum cornerToGet) const { switch(cornerToGet) { case FAR_LEFT_BOTTOM: return _minimum; case FAR_LEFT_TOP: return tvec3<T>(_minimum.x, _maximum.y, _minimum.z); case FAR_RIGHT_TOP: return tvec3<T>(_maximum.x, _maximum.y, _minimum.z); case FAR_RIGHT_BOTTOM: return tvec3<T>(_maximum.x, _minimum.y, _minimum.z); case NEAR_RIGHT_BOTTOM: return tvec3<T>(_maximum.x, _minimum.y, _maximum.z); case NEAR_LEFT_BOTTOM: return tvec3<T>(_minimum.x, _minimum.y, _maximum.z); case NEAR_LEFT_TOP: return tvec3<T>(_minimum.x, _maximum.y, _maximum.z); case NEAR_RIGHT_TOP: return _maximum; default: return tvec3<T>(); } } /** 合并包围盒 * 两个包围盒合到一起,就是取并集 * Merges the passed in box into the current box. The result is the * box which encompasses both. */ void merge( const AxisAlignedBox<T>& right ) { if ((right._extent == EXTENT_NULL) || (_extent == EXTENT_INFINITE)){ return; }else if (right._extent == EXTENT_INFINITE){ _extent = EXTENT_INFINITE; }else if (_extent == EXTENT_NULL){ setExtents(right._minimum, right._maximum); }else{ //! merge tvec3<T> min = _minimum; tvec3<T> max = _maximum; max.makeCeil(right._maximum);//取最大值 min.makeFloor(right._minimum);//取最小值 setExtents(min, max); } } /** * Extends the box to encompass the specified point (if needed). */ void merge( const tvec3<T>& point ) { switch (_extent) { case EXTENT_NULL: // if null, use this point setExtents(point, point); return; case EXTENT_FINITE: _maximum.makeCeil(point); _minimum.makeFloor(point); return; case EXTENT_INFINITE: return; } } /*** 模型变换了,从新计算最大值/最小值 * 正方形6个面一共36顶点,在算出最大值和最小值,在和模型相乘 * 原理:8个顶点和矩阵相乘,得到新的8个顶点,在求最大值和最小值 * @param matrix 模型矩阵 */ void transform( const tmat4x4<T>& matrix ) { tvec3<T> oldMin; tvec3<T> oldMax; tvec3<T> currentCorner; oldMin = _minimum; oldMax = _maximum; // We sequentially compute the corners in the following order : // 0, 6, 5, 1, 2, 4 ,7 , 3 // This sequence allows us to only change one member at a time to get at all corners. // For each one, we transform it using the matrix // Which gives the resulting point and merge the resulting point. currentCorner = oldMin; tvec3<T> vVert = currentCorner * matrix; setExtents(vVert,vVert); // First corner // min min min currentCorner = oldMin; merge( currentCorner * matrix ); // min,min,max currentCorner.z = oldMax.z; merge( currentCorner * matrix ); // min max max currentCorner.y = oldMax.y; merge( currentCorner * matrix ); // min max min currentCorner.z = oldMin.z; merge( currentCorner * matrix ); // max max min currentCorner.x = oldMax.x; merge( currentCorner * matrix ); // max max max currentCorner.z = oldMax.z; merge( currentCorner * matrix ); // max min max currentCorner.y = oldMin.y; merge( currentCorner * matrix); // max min min currentCorner.z = oldMin.z; merge( currentCorner * matrix); } /** 和盒子相交(两个盒子相交) * Returns whether or not this box intersects another. * @param b2 第二个盒子 * @return true 相交,false 不相交 */ bool intersects(const AxisAlignedBox& b2) const { if (_maximum.x < b2._minimum.x) return false; if (_maximum.y < b2._minimum.y) return false; if (_maximum.z < b2._minimum.z) return false; if (_minimum.x > b2._maximum.x) return false; if (_minimum.y > b2._maximum.y) return false; if (_minimum.z > b2._maximum.z) return false; return true; } /** 和盒子相交(两个盒子相交),不考虑z轴 * Returns whether or not this box intersects another. * @param b2 第二个盒子 * @return true 相交,false 不相交 */ bool intersectsNoZ(const AxisAlignedBox& b2) const { if (_maximum.x < b2._minimum.x) return false; if (_maximum.y < b2._minimum.y) return false; if (_minimum.x > b2._maximum.x) return false; if (_minimum.y > b2._maximum.y) return false; return true; } /** 和盒子相交(两个盒子相交) * Returns whether or not this box intersects another. * @param b2 第二个盒子 * @return 返回交集 */ AxisAlignedBox<T> intersection(const AxisAlignedBox<T>& b2) const { tvec3<T> intMin = _minimum; tvec3<T> intMax = _maximum; intMin.makeCeil(b2.getMinimum()); intMax.makeFloor(b2.getMaximum()); if (intMin.x < intMax.x && intMin.y < intMax.y &&intMin.z < intMax.z){ return AxisAlignedBox<T>(intMin, intMax); } return AxisAlignedBox<T>(); } //是否被初始化 bool isNull(void) const {return (_extent == EXTENT_NULL); } void setNull() {_extent = EXTENT_NULL; } //是否是有限的 bool isFinite(void) const{ return (_extent == EXTENT_FINITE);} void setInfinite() {_extent = EXTENT_INFINITE; } bool isInfinite(void) const { return (_extent == EXTENT_INFINITE); } //缩放 void scale(const tvec3<T>& s){ tvec3<T> min = _minimum * s; tvec3<T> max = _maximum * s; setExtents(min, max); } /*** 和点相交 * @param v 三维点 */ bool intersects(const tvec3<T>& v) const { return( v.x >= _minimum.x && v.x <= _maximum.x && v.y >= _minimum.y && v.y <= _maximum.y && v.z >= _minimum.z && v.z <= _maximum.z); } /*** 和点相交 * @param v 二维点 */ bool intersects(const tvec2<T>& v) const { return( v.x >= _minimum.x && v.x <= _maximum.x && v.y >= _minimum.y && v.y <= _maximum.y ); } //获取包围盒中心点 tvec3<T> getCenter(void) const { return tvec3<T>( (_maximum.x + _minimum.x) * T(0.5f), (_maximum.y + _minimum.y) * T(0.5f), (_maximum.z + _minimum.z) * T(0.5f) ); } //获取包围盒大小 tvec3<T> getSize(void) const { return _maximum - _minimum; } //获取包围盒一半的大小 tvec3<T> getHalfSize(void) const { return (_maximum - _minimum) * T(0.5); } //是否包含点 bool contains(const tvec3<T>& v) const { return _minimum.x <= v.x && v.x <= _maximum.x && _minimum.y <= v.y && v.y <= _maximum.y && _minimum.z <= v.z && v.z <= _maximum.z; } //是否包含盒子 bool contains(const AxisAlignedBox& other) const { return this->_minimum.x <= other._minimum.x && this->_minimum.y <= other._minimum.y && this->_minimum.z <= other._minimum.z && other._maximum.x <= this->_maximum.x && other._maximum.y <= this->_maximum.y && other._maximum.z <= this->_maximum.z; } bool operator== (const AxisAlignedBox& right) const { return this->_minimum == right._minimum && this->_maximum == right._maximum; } bool operator!= (const AxisAlignedBox& right) const { return !(*this == right); } };
2:用射线与盒子相交 ray.intersects(盒子)
//射线 template<typename T> class tray { typedef T value_type; typedef tray<T> type; protected: tvec3<T> _origin;//起始点 tvec3<T> _direction;//方向 public: tray(): _origin(value_type(0),value_type(0),value_type(0)), _direction(value_type(0),value_type(0),value_type(1)) {} tray(const tvec3<T>& origin, const tvec3<T>& direction): _origin(origin), _direction(direction) {} //设置射线的起点 void setOrigin(const tvec3<T>& origin) { _origin = origin; } // 返回射线的起点 const tvec3<T>& getOrigin(void) const{ return _origin; } //设置射线的方向 void setDirection(const tvec3<T>& dir) { _direction = dir; } //返回射线的方向 const tvec3<T>& getDirection(void) const { return _direction; } /** * Gets the position of a point t units along the ray. */ tvec3<T> getPoint(T time) const { return tvec3<T>(_origin + (_direction * time));} /** 射线与box相交 * 如果相交,返回值中的first == true.否则false * second为射线到点的距离 * 调用getPoint方法,则返回交点 * @param box 盒子 * @return std::pair<bool, T>.first 是否碰上,true碰上,false没有碰上 * @return std::pair<bool, T>.second 射线到点的距离(这是个时间), getPoint(pair.second)得到交点 */ std::pair<bool, T> intersects(const AxisAlignedBox<T>& box) const { T lowt = 0.0f; T t; bool hit = false; tvec3<T> hitpoint; tvec3<T> min = box.getMinimum(); tvec3<T> max = box.getMaximum(); // 点在包围盒里面 if ( _origin > min && _origin < max ) { return std::pair<bool, T>(true, 0); } // Check each face in turn, only check closest 3 // Min x if (_origin.x <= min.x && _direction.x > 0) { t = (min.x - _origin.x) / _direction.x; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.y >= min.y && hitpoint.y <= max.y && hitpoint.z >= min.z && hitpoint.z <= max.z && (!hit || t < lowt)) { hit = true; lowt = t; } } } // Max x if (_origin.x >= max.x && _direction.x < 0) { t = (max.x - _origin.x) / _direction.x; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.y >= min.y && hitpoint.y <= max.y && hitpoint.z >= min.z && hitpoint.z <= max.z && (!hit || t < lowt)) { hit = true; lowt = t; } } } // Min y if (_origin.y <= min.y && _direction.y > 0) { t = (min.y - _origin.y) / _direction.y; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.x >= min.x && hitpoint.x <= max.x && hitpoint.z >= min.z && hitpoint.z <= max.z && (!hit || t < lowt)) { hit = true; lowt = t; } } } // Max y if (_origin.y >= max.y && _direction.y < 0) { t = (max.y - _origin.y) / _direction.y; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.x >= min.x && hitpoint.x <= max.x && hitpoint.z >= min.z && hitpoint.z <= max.z && (!hit || t < lowt)) { hit = true; lowt = t; } } } // Min z if (_origin.z <= min.z && _direction.z > 0) { t = (min.z - _origin.z) / _direction.z; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.x >= min.x && hitpoint.x <= max.x && hitpoint.y >= min.y && hitpoint.y <= max.y && (!hit || t < lowt)) { hit = true; lowt = t; } } } // Max z if (_origin.z >= max.z && _direction.z < 0) { t = (max.z - _origin.z) / _direction.z; if (t >= 0) { // Substitute t back into ray and check bounds and dist hitpoint = _origin + _direction * t; if (hitpoint.x >= min.x && hitpoint.x <= max.x && hitpoint.y >= min.y && hitpoint.y <= max.y && (!hit || t < lowt)) { hit = true; lowt = t; } } } return std::pair<bool, T>(hit, lowt); } }; template<typename T> /*** 射线与三角形相交 * @param orig 射线原点 * @param dir 射线方向 * @param v0, v1, v2 三角形三个点 * @param t 返回的时间 * @param u,v 返回各个方向的一个分量 */ bool intersectTriangle( const tvec3<T>& orig,const tvec3<T>& dir,tvec3<T>& v0, tvec3<T>& v1,tvec3<T>& v2, T* t, T* u, T* v ) { // Find vectors for two edges sharing vert0 tvec3<T> edge1 = v1 - v0; tvec3<T> edge2 = v2 - v0; // Begin calculating determinant - also used to calculate U parameter tvec3<T> pvec; pvec = cross(dir, edge2 ); // If determinant is near zero, ray lies in plane of triangle T det = dot( edge1,pvec ); tvec3<T> tvec; if( det > 0 ) { tvec = orig - v0; } else { tvec = v0 - orig; det = -det; } if( det < 0.0001f ) return false; // Calculate U parameter and test bounds *u = dot( tvec, pvec ); if( *u < 0.0f || *u > det ) return false; // Prepare to test V parameter tvec3<T> qvec; qvec = cross(tvec, edge1 ); // Calculate V parameter and test bounds *v = dot( dir, qvec ); if( *v < T(0.0f) || *u + *v > det ) return false; *t = dot( edge2,qvec ); T fInvDet = T(1.0) / det; *t *= fInvDet; *u *= fInvDet; *v *= fInvDet; return true; }
3:加过程
typedef AxisAlignedBox<float> aabb3d; typedef tray<float> Ray;
{初始化变量 AABBVertex ptLine[2];//射线的两个点(画射线用) CELL::aabb3d aabbBox;//包围盒 CELL::aabb3d aabbTran;//记录aabbBox包围盒(包围盒改变后的大小,也是更新的大小) CELL::float3 vMin=(FLT_MAX,FLT_MAX,FLT_MAX); CELL::float3 vMax=(-FLT_MAX,-FLT_MAX,-FLT_MAX); //aabbBoxVertex 要添加盒子的模型数据 size_t count=sizeof(aabbBoxVertex)/sizeof(aabbBoxVertex[0]);//正方形6个面,每个面6个顶点(两个三角形组成一个面)一共36顶点 for (size_t i=0;i<count;i++){ vMin.x=min(aabbBoxVertex[i].x,vMin.x); vMin.y=min(aabbBoxVertex[i].y,vMin.y); vMin.z=min(aabbBoxVertex[i].z,vMin.z); vMax.x=max(aabbBoxVertex[i].x,vMax.x); vMax.y=max(aabbBoxVertex[i].y,vMax.y); vMax.z=max(aabbBoxVertex[i].z,vMax.z); } aabbBox.setExtents(vMin,vMax); } {鼠标交互 virtual void onMousePress(int absx, int absy, MouseKeyCode id) { if(id==MouseKeyCode::Left) { CELL::Ray ray=camera.createRayFromScreen(absx,absy);//得到射线 CELL::float3 post=ray.getOrigin();//射线起始点的位置 float tm=(post.y)/ray.getDirection().y; //得到地面的焦点位置 //CELL::float3 target= dd.getPoint(abs(tm)); CELL::float3 target= ray.getOrigin()+ray.getDirection()*abs(tm); target=CELL::float3(target.x,0,target.z); //设置物体移动到什么位置 role.setTarget(target); {//画射线(获取点) ptLine[0].x=post.x;//起始点 ptLine[0].y=post.y; ptLine[0].z=post.z; ptLine[1].x=target.x;//终点(目标点) ptLine[1].y=target.y; ptLine[1].z=target.z; } std::pair<bool, float> parl=ray.intersects(aabbTran);//射线与box相交 //intersectTriangle();射线与三角形相交 static int index=0; if(parl.first){ CELL::float3 jd=ray.getPoint(parl.second); printf("碰撞上了 %d --> 焦点(%f,%f,%f)\n",++index,jd.x,jd.y,jd.z); } }else if(id==MouseKeyCode::Right){ mousePos=CELL::float2(absx,absy); isRight=true; } } } {画 {//画射线 glLineWidth(5); glVertexAttribPointer(shader._positionAttr, 3, GL_FLOAT,false,sizeof(AABBVertex),&ptLine[0].x); glVertexAttribPointer(shader._uvAttr, 2, GL_FLOAT,false,sizeof(AABBVertex),&ptLine[0].u); glVertexAttribPointer(shader._colorAttr, 4, GL_FLOAT,false,sizeof(AABBVertex),&ptLine[0].r); glDrawArrays(GL_LINES,0,2); } {//移动的立方盒 glBindTexture(GL_TEXTURE_2D,textureRole); CELL::matrix4 matRot(1); CELL::matrix4 matModel; static float agle = 0.0f; agle += 1.0f; matRot.rotateYXZ(agle,agle,agle); matModel.translate(role._pos); aabbTran = aabbBox; aabbTran.transform(matModel * matRot); CELL::matrix4 ddz= matModel * matRot; MVP = matProj * matView * ddz; glUniformMatrix4fv(shader._MVP,1,false,MVP.data()); glVertexAttribPointer(shader._positionAttr, 3, GL_FLOAT,false,sizeof(AABBVertex),&aabbBoxVertex[0].x); glVertexAttribPointer(shader._uvAttr, 2, GL_FLOAT,false,sizeof(AABBVertex),&aabbBoxVertex[0].u); glVertexAttribPointer(shader._colorAttr, 4, GL_FLOAT,false,sizeof(AABBVertex),&aabbBoxVertex[0].r); glDrawArrays(GL_TRIANGLES,0,sizeof(aabbBoxVertex)/sizeof(aabbBoxVertex[0])); } {//画包围盒 CELL::float3 arBox[8]; AABBVertex vertexBox[8]; aabbTran.getAllCorners(arBox); for (size_t i = 0 ; i < 8 ;++ i ){//顶点位置 vertexBox[i].x = arBox[i].x; vertexBox[i].y = arBox[i].y; vertexBox[i].z = arBox[i].z; } short boxIndex[24] = {//索引--必须按照返回的vertexBox数组设置,具体看这个函数getAllCorners 0,1,2,3,//后 2,3,7,4,//右 4,5,6,7,//前 1,0,6,5,//左 2,4,5,1,//上 0,3,7,6//下 }; MVP = matProj * matView; glUniformMatrix4fv(shader._MVP,1,false,MVP.data()); glVertexAttribPointer(shader._positionAttr, 3, GL_FLOAT,false,sizeof(AABBVertex),&vertexBox[0].x); size_t count=sizeof(boxIndex)/sizeof(boxIndex[0]); for (size_t i=0;i<count;i+=4){ glDrawElements(GL_LINE_STRIP,4,GL_UNSIGNED_SHORT, &boxIndex[i]); } } } {Shader const char vs[]={ "uniform mat4 _MVP;" "attribute vec3 _positionAttr;" "attribute vec4 _colorAttr;" "attribute vec2 _uvAttr;" "varying vec4 _outColor;" "varying vec2 _outUV;" "void main(){" " vec4 pos = vec4(_positionAttr.x,_positionAttr.y,_positionAttr.z,1);" " gl_Position = _MVP * pos;" " _outColor = _colorAttr;" " _outUV = _uvAttr;" "}" }; const char fs[]={ "precision lowp float; " "uniform sampler2D _texture;" "varying vec4 _outColor;" "varying vec2 _outUV;" "void main()" "{" " vec4 color = texture2D(_texture,_outUV);" " gl_FragColor = color * _outColor;" "}" }; pValue=creteShaderProgram(vs,fs);//编译Shader程序 _MVP=glGetUniformLocation(pValue.pID,"_MVP"); _texture=glGetUniformLocation(pValue.pID,"_texture"); _positionAttr=glGetAttribLocation(pValue.pID,"_positionAttr"); _uvAttr=glGetAttribLocation(pValue.pID,"_uvAttr"); _colorAttr=glGetAttribLocation(pValue.pID,"_colorAttr"); }
效果图
文字有点模糊
蓝色的线是--射线
黄色的线是--模型
橙色的线是--包围盒
源码地址 http://pan.baidu.com/s/1geVargZ 拾取.zip
推荐博客
http://www.cnblogs.com/seebro/p/3801597.html
时间: 2024-10-07 10:05:33