Shape类只是单纯的形状数据,并不能用具真正的绘制,真正的绘制工作是Gizmo类去做的。该类只是作为Gizmo的一个成员去使用的。Shape的函数只是提供了加工数据的,然后把加工后的数据存下来。不多哔哔了,直接贴代码。原理有空了再详细写。
Shape.h
#pragma once #define VSFRONT 0 //面前 #define VSBACK 1 //面后 #define VSPLANAR 2 //面上 #define VSCLIPPED 0 //剪裁 #define VSCULLED 1 //刨除 #define VSCONTAIN 2 //包含 #define EPSILON_E3 0.00001 //线段类 class GLLine { private: public: Vector2 m_vcOrig; //源点|起点 Vector2 m_vcDir; //单位方向长度 float m_len; //向量长度|模 //通过起点和终点获取线段 void Set(Vector2 &vcOrig, Vector2 &vcEnd); //通过点和方向获取线段 void Set(Vector2 &vcOrig, Vector2 &vcDir, float len); GLLine(Vector2 &vcOrig, Vector2 &vcEnd); Vector2 getEnd()const; GLLine() {}; ~GLLine() {}; }; //圆 class GLCircle { private: public: float radius; Vector2 center; void Set(Vector2 pos, float r); GLCircle(Vector2 pos, float r); GLCircle() {} ~GLCircle() {} }; //多边形类 class GLPolygon { private: public: GLLine *m_line; int m_lineNum; GLPolygon(GLLine the_lines[], int the_lineNum); GLPolygon(Vector2 the_points[], int the_pointNum); void Set(GLLine lines[], int lineNum); void Set(Vector2 points[], int pointNum); Vector2 m_vcMin; Vector2 m_vcMax; GLPolygon() { m_line = nullptr; } ~GLPolygon() {} }; class GLAABB { public: Vector2 m_vcMin; //最小边界 Vector2 m_vcMax; //最大边界 Vector2 m_vcCenter; // 中心 //通过最大点,最小点获取Aabb void Set(Vector2 &vcMin, Vector2 &vcMax); //通过长宽高和位置获取Aabb void Set(float width, float height, Vector2 ¢erPos); // void Set(Vector2 aabb[]); GLAABB(float wid, float hei, Vector2 center); GLAABB() {} ~GLAABB() {} }; class GLRay { public: Vector2 m_vcOrig; //源点 Vector2 m_vcDir; //单位方向 //通过点和方向获取射线 void Set(Vector2 &vcOrig, Vector2 &vcDir); GLRay() {} ~GLRay() {} }; class GLPlane { public: Vector3D m_vcN; //平面法向量 Vector3D m_vcPoint; // 平面上的点 float m_fD; // 到原点的距离(ax+by+cz+d=0,-d) void Set(Vector3D &vcN, float fD);//通过法线和常量d获取平面 void Set(Vector3D &vcN, Vector3D &vcP);//通过法线,点获取平面 void Set(Vector3D &v0, Vector3D &v1, Vector3D &v2);//通过三个点获取平面 /*点和平面的位置关系(VSFRONT VSBACK VSPLANAR) 算法描述 用平面上点和vcPoint组成向量和平面向量做点积,根据值的符号判断位置*/ int Classify(Vector3D &vcPoint);//判断点是不是在平面上 GLPlane(){} ~GLPlane(){} }; class GLPoint { public: Vector3D m_center; void setCenter(Vector3D ¢er); int Cull(GLPlane *pPlanes, int nNumPlanes);//判断点是不是在平面里 GLPoint() {} ~GLPoint() {} }; //球类 class GLSphere { public: Vector3D m_center; float m_radius; public: GLSphere(Vector3D ¢er,float radius); void Set(Vector3D center, float radius);//通过中心点和半径获取球 int Cull(GLPlane *pPlanes, int nNumPlanes);//判断多面体和球位置关系(VSCULLED,VSCLIPPED,VSVISIBLE) bool IsPointIn(Vector3D &point);//判断点在球内 bool Intersects(Vector3D &v1, Vector3D &v2);//是否与线段相交 GLSphere() {} ~GLSphere() {} }; class GLAABB3D { public: Vector3D m_vcMin; //最小边界 Vector3D m_vcMax; //最大边界 Vector3D m_vcCenter; // 中心 Vector3D CORNERPOINT[8];//八个顶点 float length; float width; float height; GLAABB3D(Vector3D &vcMin, Vector3D &vcMax); GLAABB3D(float length, float width, float height, Vector3D &position); void Set(Vector3D &vcMin, Vector3D &vcMax);//通过最大点,最小点获取Aabb void Set(float length, float width, float height, Vector3D &position);//通过长宽高和位置获取Aabb void Set(Vector3D everyPoint[]); bool IsPointIn(Vector3D &point);//判断点在AABB内 int Cull(GLPlane *pPlanes, int nNumPlanes);//判断多面体和AABB位置关系(VSCULLED,VSCLIPPED,VSVISIBLE) GLAABB3D() {} ~GLAABB3D() {} }; class GLLine3D { private: public: Vector3D m_vcOrig; //源点|起点 Vector3D m_vcDir; //单位方向长度 float m_len; //向量长度|模 void Set(Vector3D &vcOrig, Vector3D &vcEnd); //通过起点和终点获取线段 //通过点和方向获取线段 void Set(Vector3D &vcOrig, Vector3D &vcDir, float len); GLLine3D(Vector3D &vcOrig, Vector3D &vcEnd); Vector3D getEnd()const; GLLine3D() {}; ~GLLine3D() {}; }; class GLRay3D { public: Vector3D m_vcOrig; //源点 Vector3D m_vcDir; //单位方向 void Set(Vector3D &vcOrig, Vector3D &vcDir);//通过点和方向获取射线 bool Intersects(GLSphere &sphere_a, Vector3D &hitPoint); bool Intersects(GLLine3D &line_a, Vector3D &hitPoint); bool Intersects(GLPlane & plane_a, int size, Vector3D & hitPoint); GLRay3D() {} ~GLRay3D() {} }; class GLTrianglePlane:public GLPlane { public: Vector3D m_v0, m_v1, m_v2; Vector3D m_vertex[3]; void set(Vector3D v0, Vector3D v1, Vector3D v2); bool IsPointIn(Vector3D & point); };
Shape.cpp
#include "Engine.h" //线段 GLLine::GLLine(Vector2 &vcOrig, Vector2 &vcEnd) { m_vcOrig = vcOrig; m_vcDir = (vcEnd - vcOrig).Normalize(); m_len = (vcEnd - vcOrig).length(); } void GLLine::Set(Vector2 &vcOrig, Vector2 &vcEnd) { m_vcOrig = vcOrig; m_vcDir =(vcEnd - vcOrig).Normalize(); m_len = (vcEnd - vcOrig).length(); } void GLLine::Set(Vector2 &vcOrig, Vector2 &vcDir, float len) { m_vcOrig = vcOrig; m_vcDir = vcDir; m_len = len; } Vector2 GLLine::getEnd() const { return Vector2(m_vcOrig.x + m_len*m_vcDir.x, m_vcOrig.y + m_len*m_vcDir.y); } //3D空间中的线 GLLine3D::GLLine3D(Vector3D &vcOrig, Vector3D &vcEnd) { m_vcOrig = vcOrig; m_vcDir = (vcEnd - vcOrig).Normalize(); m_len = (vcEnd - vcOrig).length(); } void GLLine3D::Set(Vector3D &vcOrig, Vector3D &vcEnd) { m_vcOrig = vcOrig; m_vcDir = (vcEnd - vcOrig).Normalize(); m_len = (vcEnd - vcOrig).length(); } void GLLine3D::Set(Vector3D &vcOrig, Vector3D &vcDir, float len) { m_vcOrig = vcOrig; m_vcDir = vcDir; m_len = len; } Vector3D GLLine3D::getEnd()const { return Vector3D(m_vcOrig.x + m_len*m_vcDir.x, m_vcOrig.y + m_len*m_vcDir.y,m_vcOrig.z+m_len*m_vcDir.z); } //圆形 GLCircle::GLCircle(Vector2 pos, float r) { this->center = pos; this->radius = r; } void GLCircle::Set(Vector2 pos, float r) { this->center = pos; this->radius = r; } //多边形 GLPolygon::GLPolygon(GLLine lines[], int lineNum) { m_line = new GLLine[lineNum]; memcpy(m_line, lines, sizeof(GLLine)*lineNum); this->m_lineNum = lineNum; } GLPolygon::GLPolygon(Vector2 points[], int pointNum) { m_lineNum = pointNum; m_line = new GLLine[pointNum]; for (int i = 0;i < pointNum;i++) { m_line[i].Set(points[i], points[(i + 1) % pointNum]); } m_vcMin.x = points[0].x; m_vcMin.y = points[0].y; m_vcMax.x = points[0].x; m_vcMax.y = points[0].y; for (int i = 1; i<pointNum; ++i) { if (m_vcMin.x > points[i].x) swap(m_vcMin.x, points[i].x); if (m_vcMin.y > points[i].y) swap(m_vcMin.y, points[i].y); if (m_vcMax.x < points[i].x) swap(m_vcMax.x, points[i].x); if (m_vcMax.y < points[i].y) swap(m_vcMax.y, points[i].y); } } void GLPolygon::Set(GLLine lines[], int lineNum) { delete[]m_line; m_line = new GLLine[lineNum]; memcpy(m_line,lines,sizeof(GLLine)*lineNum); this->m_lineNum = lineNum; } void GLPolygon::Set(Vector2 points[], int pointNum) { delete[]m_line; m_lineNum = pointNum; m_line = new GLLine[pointNum]; for (int i = 0;i < pointNum;i++) { m_line[i].Set(points[i], points[(i+1)% pointNum]); } } GLAABB::GLAABB(float wid, float hei, Vector2 center) { Set(wid, hei, center); } void GLAABB::Set(Vector2 &vcMin, Vector2 &vcMax) { this->m_vcMin = vcMin; this->m_vcMax = vcMax; this->m_vcCenter = m_vcMin+(vcMax - vcMin) / 2; } void GLAABB::Set(float width, float height, Vector2 ¢erPos) { this->m_vcCenter = centerPos; //算最小点 this->m_vcMin.x= centerPos.x-width*0.5; this->m_vcMin.y = centerPos.y-height*0.5; //算最大点 this->m_vcMax.x = centerPos.x+width*0.5; this->m_vcMax.y = centerPos.y+height*0.5; } void GLAABB::Set(Vector2 vec[]) { m_vcMin =Vector2(9999,9999); m_vcMax= Vector2(-9999,-9999); for (int i = 0; i < 4; i++) { if (m_vcMin.x > vec[i].x){m_vcMin.x=vec[i].x;} if (m_vcMin.y > vec[i].y){m_vcMin.y=vec[i].y;} if (m_vcMax.x < vec[i].x){m_vcMax.x=vec[i].x;} if (m_vcMax.y < vec[i].y){m_vcMax.y=vec[i].y;} } } void GLRay::Set(Vector2 &vcOrig, Vector2 &vcDir) { this->m_vcOrig = vcOrig; this->m_vcDir = vcDir.Normalize(); } void GLPlane::Set(Vector3D &vcN, float fD) { float len=vcN.length(); m_vcN.x= vcN.x /= len; m_vcN.y= vcN.y/= len; m_vcN.z= vcN.z/= len; m_fD=fD/= len; } void GLPlane::Set(Vector3D &vcN,Vector3D &vcP)//法向量和一个点 { m_vcN = vcN.Normalize(); m_fD = -m_vcN.dot(vcP);//面上的法向量点乘一个点 m_vcPoint = vcP; } void GLPlane::Set(Vector3D &v0,Vector3D &v1,Vector3D &v2) { Vector3D vcEdge1 = v1 - v0; Vector3D vcEdge2 = v2 - v0; m_vcN = vcEdge1.cross(vcEdge2); m_vcN.normalize(); m_fD = -m_vcN.dot(v0); m_vcPoint = v0; } int GLPlane::Classify(Vector3D &vcPoint) { float len = m_vcN.dot(m_vcPoint) + m_fD; if (len > 0) { return VSPLANAR; } if (len < 0) { return VSBACK; } return VSPLANAR; } void GLPoint::setCenter(Vector3D ¢er) { m_center = center; } int GLPoint::Cull(GLPlane *pPlanes, int nNumPlanes) { for (int i = 0;i < nNumPlanes;++i) { float f = m_center.dot(pPlanes[i].m_vcN)+pPlanes[i].m_fD; /*if (f >0) return VSFRONT;*/ if (f <0) return VSCULLED; if (f == 0) { return VSCLIPPED; } } return VSCONTAIN; } GLSphere::GLSphere(Vector3D ¢er, float radius) { Set(center, radius); } void GLSphere::Set(Vector3D center, float radius) { m_center = center; m_radius = radius; } int GLSphere::Cull(GLPlane *pPlanes, int nNumPlanes) { for (int i = 0; i < nNumPlanes; i++) { if (pPlanes[i].m_vcN.x * m_center.x + pPlanes[i].m_vcN.y * m_center.y + pPlanes[i].m_vcN.z * m_center.z + pPlanes[i].m_fD <= -m_radius) { return VSCULLED; } } return VSCONTAIN; } bool GLSphere::IsPointIn(Vector3D &point) { if ((m_center - point).length2q() <= m_radius*m_radius) { return true; } return false; } bool GLSphere::Intersects(Vector3D &v1, Vector3D &v2) { Vector3D d1 = this->m_center - v1; if (d1.length2q() <= this->m_radius*this->m_radius) return true; Vector3D b_dir = (v2 - v1).Normalize(); float s = d1.dot(b_dir); if (s < 0.000001f) return false; Vector3D d2 = this->m_center - v2; if (d2.length2q() <= this->m_radius*this->m_radius) return true; //延长线 float l = (v2 - v1).length2q(); float m = d1.length2q() - s*s; if (m <= this->m_radius*this->m_radius&&l > s*s) return true; return false; } GLAABB3D::GLAABB3D(Vector3D &vcMin, Vector3D &vcMax) { Set(vcMin, vcMax); } GLAABB3D::GLAABB3D(float length, float width, float height, Vector3D &position) { Set(length, width, height, position); } void GLAABB3D::Set(Vector3D &vcMin, Vector3D &vcMax) { m_vcMin = vcMin; m_vcMax = vcMax; this->length = fabs(vcMax.x - vcMin.x); this->height = fabs( vcMax.y - vcMin.y); this->width = fabs(vcMax.z - vcMin.z); CORNERPOINT[0] = Vector3D(vcMin.x, vcMin.y, vcMin.z); CORNERPOINT[1] = Vector3D(vcMin.x, vcMin.y, vcMax.z); CORNERPOINT[2] = Vector3D(vcMin.x, vcMax.y, vcMin.z); CORNERPOINT[3] = Vector3D(vcMax.x, vcMin.y, vcMin.z); CORNERPOINT[4] = Vector3D(vcMax.x, vcMax.y, vcMin.z); CORNERPOINT[5] = Vector3D(vcMax.x, vcMin.y, vcMax.z); CORNERPOINT[6] = Vector3D(vcMin.x, vcMax.y, vcMax.z); CORNERPOINT[7] = Vector3D(vcMax.x, vcMax.y, vcMax.z); m_vcCenter = (vcMax + vcMin) / 2; } void GLAABB3D::Set(float length, float width, float height, Vector3D &position) { //长:X - 宽:Z - 高:Y; //以中心点画AABB m_vcCenter = position; m_vcMin.x = position.x - width; m_vcMin.y = position.y /*- height*/; m_vcMin.z = position.z - width; m_vcMax.x = position.x +width; m_vcMax.y = position.y + height; m_vcMax.z = position.z + width; this->length = length; this->width = width; this->height = height; CORNERPOINT[0] = Vector3D(-length*0.5, -height*0.5, -width*0.5); CORNERPOINT[1] = Vector3D(-length*0.5, -height*0.5, +width*0.5); CORNERPOINT[2] = Vector3D(-length*0.5, +height*0.5, -width*0.5); CORNERPOINT[3] = Vector3D(+length*0.5, -height*0.5, -width*0.5); CORNERPOINT[4] = Vector3D(-length*0.5, +height*0.5, +width*0.5); CORNERPOINT[5] = Vector3D(+length*0.5, +height*0.5, -width*0.5); CORNERPOINT[6] = Vector3D(+length*0.5, -height*0.5, +width*0.5); CORNERPOINT[7] = Vector3D(+length*0.5, +height*0.5, +width*0.5); m_vcCenter = (m_vcMax + m_vcMin) / 2; } void GLAABB3D::Set(Vector3D vec[]) { m_vcMin = Vector3D(99999, 99999,99999); m_vcMax = Vector3D(-99999, -99999,-99999); for (int i = 0; i <8;++i) { if (m_vcMin.x > vec[i].x) m_vcMin.x = vec[i].x; if (m_vcMin.y > vec[i].y) m_vcMin.y = vec[i].y; if( m_vcMin.z>=vec[i].z) m_vcMin.z = vec[i].z; if (m_vcMax.x < vec[i].x) m_vcMax.x = vec[i].x; if (m_vcMax.y < vec[i].y) m_vcMax.y = vec[i].y; if (m_vcMax.z < vec[i].z) m_vcMax.z = vec[i].z; } this->length = fabs(m_vcMax.x - m_vcMin.x); this->height = fabs(m_vcMax.y - m_vcMin.y); this->width = fabs(m_vcMax.z - m_vcMin.z); m_vcCenter = (m_vcMax + m_vcMin) / 2; } bool GLAABB3D::IsPointIn(Vector3D &point) { if (point.x>m_vcMin.x&&point.x<m_vcMax.x&& point.y>m_vcMin.y&&point.y<m_vcMax.y&& point.z>m_vcMin.z&&point.z<m_vcMax.z) { return true; } return false; } int GLAABB3D::Cull(GLPlane *pPlanes, int nNumPlanes) { Vector3D vcMin, vcMax; bool bIntersects = false; for (int i = 0; i < nNumPlanes; i++) { // x if (pPlanes[i].m_vcN.x >= 0.0f) { vcMin.x = m_vcMin.x; vcMax.x = m_vcMax.x; } else { vcMin.x = m_vcMax.x; vcMax.x = m_vcMin.x; } // y if (pPlanes[i].m_vcN.y >= 0.0f) { vcMin.y = m_vcMin.y; vcMax.y = m_vcMax.y; } else { vcMin.y = m_vcMax.y; vcMax.y = m_vcMin.y; } // z if (pPlanes[i].m_vcN.z >= 0.0f) { vcMin.z = m_vcMin.z; vcMax.z = m_vcMax.z; } else { vcMin.z = m_vcMax.z; vcMax.z = m_vcMin.z; } //刨除 if ((pPlanes[i].m_vcN.dot(vcMin) + pPlanes[i].m_fD) > 0.0f) return VSCULLED; if ((pPlanes[i].m_vcN.dot(vcMax) + pPlanes[i].m_fD) >= 0.0f) bIntersects = true; } //剪裁 if (bIntersects) return VSCLIPPED; //包含 return VSCONTAIN; } void GLRay3D::Set(Vector3D&vcOrig,Vector3D &vcDir) { m_vcOrig = vcOrig; m_vcDir = vcDir.Normalize(); } //射线与线段碰撞 bool GLRay3D::Intersects(GLLine3D &line_a, Vector3D &hitPoint) { Vector3D n = m_vcDir.cross(line_a.m_vcDir); if (fabs(n.length()) < EPSILON_E3) return false; float s = ((line_a.m_vcOrig - this->m_vcOrig).cross(line_a.m_vcDir)).dot(n); s /= n.length()*n.length(); float t = ((this->m_vcOrig - line_a.m_vcOrig).cross(m_vcDir)).dot(-n); t /= n.length()*n.length(); if (s >= 0 && t >= 0 && t <= line_a.m_len) { Vector3D hit_a = m_vcOrig + m_vcDir*s; Vector3D hit_b = line_a.m_vcOrig + line_a.m_vcDir*t; if ((hit_a - hit_b).length() < 2) { hitPoint = hit_a; return true; } } return false; } //射线与面碰撞 bool GLRay3D::Intersects(GLPlane &plane_a, int size, Vector3D &hitPoint) { float Vd = plane_a.m_vcN.dot(m_vcDir); if (fabs(Vd) < EPSILON_E3) return false; /*if (Vd > 0.0f) return false;*/ float Vo = -(plane_a.m_vcN.dot(m_vcOrig) + plane_a.m_fD); float f = Vo / Vd; if (f >= 0.0f) { hitPoint = m_vcOrig + (m_vcDir * f); Vector3D d = hitPoint - plane_a.m_vcPoint; if (fabs(d.x) <= size && fabs(d.y) <= size && fabs(d.z) <= size) { return true; } } return false; } //射线与球碰撞 bool GLRay3D::Intersects(GLSphere &sphere_a, Vector3D &hitPoint) { Vector3D d = m_vcOrig - sphere_a.m_center; if (d.length2q() <= sphere_a.m_radius*sphere_a.m_radius) return false; float b = m_vcDir.dot(d); float c = d.dot(d) - sphere_a.m_radius*sphere_a.m_radius; float dt = b*b - c; if (dt<0) return false; //有一个或两个交点 float t1 = -b + sqrt(dt); float t2 = -b - sqrt(dt); if (t1 >= 0 && t2 >= 0) { float f = fmin(t1, t2); hitPoint = m_vcOrig + (m_vcDir * f); return true; } return false; } void GLTrianglePlane::set(Vector3D v0, Vector3D v1, Vector3D v2) { this->m_v0 = v0; this->m_v1 = v1; this->m_v2 = v2; m_vertex[0] = v0; m_vertex[1] = v1; m_vertex[2] = v2; //GLPlane::Set(v0, v1, v2); Set(v0, v1, v2); } bool GLTrianglePlane::IsPointIn(Vector3D & point) { Vector3D p0 = m_vertex[1] - m_vertex[0]; Vector3D p1 = m_vertex[2] - m_vertex[0]; Vector3D p2 = point - m_vertex[0]; float dot00 = p0.dot(p0); float dot01 = p0.dot(p1); float dot02 = p0.dot(p2); float dot11 = p1.dot(p1); float dot12 = p1.dot(p2); float inverDeno = 1.0f / (dot00*dot11 - dot01*dot01); float u = (dot02*dot11 - dot01*dot12)*inverDeno; if (u < 0 || u > 1) { return false; } float v = (dot00*dot12 - dot02*dot01)*inverDeno; if (v < 0 || v > 1) { return false; } return u + v <= 1; }