9.游戏引擎 三维几何体数据类

        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 &centerPos);
	//
	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 &center);
	int Cull(GLPlane *pPlanes, int nNumPlanes);//判断点是不是在平面里
	GLPoint() {}
	~GLPoint() {}
};



//球类
class GLSphere
{

public:
	Vector3D m_center;
	float m_radius;

public:
	GLSphere(Vector3D &center,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 &centerPos)
{
	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 &center)
{
	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 &center, 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;
}

猜你喜欢

转载自blog.csdn.net/qq_33531923/article/details/126913025
今日推荐