又一种随机赛道生成算法

之前在赛车游戏中介绍过一种利用迷宫拼接随机赛道的方法,之前介绍的波函数坍缩算法也很适合用来拼接随机赛道。今天介绍另外一种随机赛道生成方法。

路径变形算法pathdeform,熟悉3dsmax建模的应该很熟悉,有点类似loft放样。

比如将一个圆沿着一条直线路径拉伸变成圆柱的过程就是放样,但是放样法产生赛道每个路段都是一样的缺乏美观。路径变形则是将一段预先制作好的直线路段扭曲贴合到赛道路径上。预先制作好的路段可以做的很复杂可以包含建筑、树木、坑洞等所有想要的东西。

不同于直接拼接,预制路段将可以适用到曲线上。

路径变形算法比较固定,所以代码主要集中在路径曲线的生成上,关于曲线生成有以下几个尝试方案,还不够完善需要的可以改改。

第一种方案:可能想到的是利用数学函数来生成路径曲线,效果都不是很好,不可控。比如

    //WANDER曲线
    //float t = ang*0.2;// + z; 
    //x += 5 * sin(3.12 * t) * cos(1.24 * t);
    //y += 5 * sin(2.97 * t) * cos(0.81 * t);
    //z += 5 * sin(1.23 * t) * cos(t);

    //周期回归的WANDER曲线
    //float t = ang*0.2;// + z; 
    //x += 5 * sin(1.23 * t) * cos(1.24 * t);
    //y += 5 * sin(1.23 * t) * cos(0.81 * t);
    //z += 5 * sin(1.23 * t) * cos(t);

第二种方案:先生成路点,然后用tsp算法连接,再用b曲线来平滑,这种方法生成的赛道可以方便的避免交叉,但是赛道太直,效果也不是太好。后来想到的改进方法是每两个路点之间直接使用相切的圆弧来连接,这样生成的赛道有点像铅笔刀铰出的木屑,大约还需要再配合平滑算法。

第三种方案:每次只生成一个路点,通过随机偏转欧拉角和随机弧度、随机弧长等来生成下一段曲线。这种方案生成过山车赛道效果是最好的,缺点是生成的路面可能会交叉,另外首尾衔接不太好处理。

 通过控制欧拉角的旋转也可以生成特定风格的路面

还有一些待改进的地方:比如路径分岔的处理。 

 源码:


#define  ZFacing 1 //-1  面向z正半轴为前进方向
class RollerWay
{
public:
	class WayPoint_
	{
	public:
		vec3 pos;
		vec3 dir;
		//欧式路程
		float roadDist;
		//变换矩阵
		mat4 matAll;
		//旋转矩阵
		mat3 matRot;
		//桥墩式变换矩阵
		mat4 matPier;
		int  lmr; //1左路 0中路 2右路
	};
	class Vertex
	{
	public:
		float x;
		float y;
		float z;
		float u;
		float v;
		float w;
	};
	struct Trigon
	{
		IndexInt vIndex[3];
	};
	RollerWay();
	~RollerWay();
	void Init(int roadType);
	//过山车式轨道
	void RandRoller();
	void RandRollerTsp();
	//赛车式轨道 
	void RandRacing();
	void CalWayPoints();
	void GenBuffer();

	void LoadFromFile();
	void Update();
	void Render();
	vec3 GetPos(float wayPos);
	//根据欧式路程[几何距离]获得路径路程[0~m_wayPointNum]
	float GetWayPos(float euclidDist);

	TexturePtr m_texRoad;
	MovieClip* m_roadsMovie ;
	MC_Frame*  m_pierMovie  ;
	MC_Frame*  m_roadMovieL ;
	MC_Frame*  m_roadMovieM ;
	MC_Frame*  m_roadMovieR ;
	MC_Frame*  m_doorMovieL ;
	MC_Frame*  m_doorMovieR ;

#define MAX 2048
	Curve* m_spline;
	WayPoint_ m_wayPoints[MAX];
	int  m_wayPointNum;

	int  m_trigonNum;
	int  m_vVertexNum;

	Trigon*   m_trigons;
	Vertex*   m_vVertexs;

	float StepDist;
	float MaxDist;

	vec3  WorldMin;
	vec3  WorldMax;

	//记录到文件
	int   m_stageNum;
	class Stage
	{
	public:
		int   step;
		//mat4 matStep;
		float pitch,head,roll;
		vec3  stepOffset;
	};
};



#include "General/Pch.h"
#include "Render/RendDriver.h"
#include "Math/MathLib.h"
#include <stdlib.h>
#include "stdio.h"


RollerWay* G_RollerWay;

RollerWay::RollerWay()
:m_spline(NULL)
{
	G_RollerWay = this;
	m_wayPointNum = 0;
	m_roadsMovie = NULL;
	m_pierMovie = NULL;
	m_roadMovieL = NULL;
	m_roadMovieM = NULL;
	m_roadMovieR = NULL;
	m_doorMovieL = NULL;
	m_doorMovieR = NULL;
}

RollerWay::~RollerWay()
{
	SafeDelete(m_spline);
}

void RollerWay::Init(int roadType)
{
	if (m_roadsMovie==NULL)
	{
		m_roadsMovie = new RendSys::MovieClip;
		m_roadsMovie->LoadFromFile("data/environment/wall/roads.movie");
		m_roadsMovie->SetFrustumSkipEnable(false,Recursive);
		m_roadsMovie->Advance();

		m_pierMovie = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("pier"); 
		if(m_pierMovie)m_pierMovie->ZeroFrames();


		m_roadMovieL = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("roadl"); 
		if(m_roadMovieL)m_roadMovieL->ZeroFrames();


		m_roadMovieM = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("roadm"); 
		if(m_roadMovieM)m_roadMovieM->ZeroFrames();


		m_roadMovieR = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("roadr"); 
		if(m_roadMovieR)m_roadMovieR->ZeroFrames();


		m_doorMovieL = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("doorleft"); 
		m_doorMovieR = (RendSys::MC_Frame*)m_roadsMovie->GetMovieClip("doorright"); 

	}

	//G_TextureMgr->AddTexture(m_texRoad,"data/environment/wall/doodads1.png");
	m_texRoad = m_roadMovieM->GetTexture();

	WorldMin = vec3(-1000,10,-1000)*0.5f;
	WorldMax = vec3(1000,1000,1000)*0.5f;

	switch(roadType)
	{
	case 0:
		RandRoller();
		break;
	case 1:
		RandRollerTsp();
		break;
	case 2:
		RandRacing();
		break;
	}
}

//过山车式轨道
void RollerWay::RandRoller()
{
	WorldMin = vec3(-1000,10,-1000)*0.5f;
	WorldMax = vec3(1000,400,1000)*0.5f;

	File file;
	file.Fopen("data/environment/wall/RollerWay.txt","wt");

	mat3  matStepRot;

	int   stepNum = 0;
	vec3  stepOffset;
	float stepPitch = 0;
	float stepRota = 0;
	StepDist = 10.2f;

	float AngPitch = 0;
	float AngRota  = 0;

	m_wayPointNum = 0;

	float StepAng = 10;
	int   nextPoint = 1;//+RandRange(0,5);
	int   MaxWayPoint = 512;//128;//512;
	while (m_wayPointNum<MaxWayPoint)
	{
		WayPoint_* curWayPoint = &m_wayPoints[m_wayPointNum];
		WayPoint_* preWayPoint = m_wayPointNum>=1?&m_wayPoints[m_wayPointNum-1]:NULL;

		//闭合结束
		if (preWayPoint
			&&m_wayPointNum>10
			&&(preWayPoint->pos-m_wayPoints[0].pos).LengthSq()<StepDist*StepDist*0.01f
			)
		{
			break;
		}

		m_wayPointNum ++;

		if (m_wayPointNum>=nextPoint)
		{
			//改变旋转方向
			如果出了包围盒 趋向回头
			//if(preWayPoint&&preWayPoint->pos.x<WorldMin.x)
			//{

			//}
			bool BigCircle = 0;//(Rand()%6==0);
			if (BigCircle)
			{
				StepAng = 10;
				//todo 大回旋的轴也可以不竖直或水平 只不过变换矩阵是基于回旋起点而不是prev点
				//	//不是增量旋转矩阵  matStepRot.FromEulerAngRadZXY(vec3(stepPitch*i,stepRota*i,0)* DEG2RAD);
				// 没有offset时在一个平面内
				if(Rand()%2)
				{
					//pitch大回旋
					//todo pitch 大回旋圈只能是向上,向下时必须roll180度保证车体在圈内运行?
					AngPitch = RandRange(360,780);
					stepNum  = AngPitch / StepAng * RandRange(0.5f,1.5f);
					stepPitch = AngPitch / stepNum * RandSign();
					stepRota  = 0;

					stepOffset = vec3(StepDist/stepNum*4*RandSign(),0,0);
					if(preWayPoint)
						stepOffset = preWayPoint->matRot*stepOffset;
				}
				else //rotate大回旋
				{
					AngRota = RandRange(360,780);
					stepNum  = AngRota / StepAng * RandRange(0.5f,1.5f);
					stepPitch = 0;
					stepRota  = AngRota / stepNum * RandSign();

					stepOffset = vec3(0,StepDist/stepNum*4*RandSign(),0);
					if(preWayPoint)
						stepOffset = preWayPoint->matRot*stepOffset;
				}
			}
			else
			{
				// 没有offset时也不在一个平面内
				StepAng = 10;
				vec3 front = vec3(0,0,-1);
				vec3 up    = vec3(0,1,0);
				vec3 right = vec3(1,0,0);
				if(preWayPoint)
				{
					front = preWayPoint->matRot*front;
					up    = preWayPoint->matRot*up;
					right = preWayPoint->matRot*right;
				}
 
				if(preWayPoint==NULL || preWayPoint->pos.y < WorldMin.y)
				{
					if ( up.y>0.0f)    //位置过低=》上升
					{
						AngPitch = RandRange(20.0f,40.0f)*-1;
					}
					else //if ( up.y<-0.0f)
					{
						AngPitch = RandRange(20.0f,40.0f)*1;
					}
					AngRota  = 0;
				}
				else if(preWayPoint->pos.y > WorldMax.y)
				{
					if ( up.y>0)     //位置过高=》下降
					{
						AngPitch = RandRange(20.0f,40.0f)*1;
					}
					else
					{
						AngPitch = RandRange(20.0f,40.0f)*-1;
					}
					AngRota  = 0;
				}
				else
				{
					//垂直方向坡度不允许变化太大
					AngPitch = 0.1f*RandRange(20.0f,40.0f)*RandSign();
					AngRota  = RandRange(80.0f,160.0f)*RandSign();	
				}
				//else
				//{
				//	if (   (front.y> 0.707f && up.y>0)   //抬头过高=》下凹
				//		|| (front.y<-0.707f && up.y<0)   //倒置抬头过高=》下凹
				//		)
				//	{
				//		AngPitch = RandRange(20.0f,40.0f)*-1;
				//	}
				//	else if ( (front.y>0.707 && up.y<0)
				//		||(front.y<-0.707 && up.y>0)
				//		)
				//	{
				//		AngPitch = RandRange(20.0f,40.0f)*1;
				//	}
				//	else
				//	{
				//		//垂直方向坡度不允许变化太大
				//		AngPitch = 0.1f*RandRange(20.0f,40.0f)*RandSign();
				//	}

				//	AngRota  = RandRange(80.0f,160.0f)*RandSign();	
				//}
			
				stepNum  = max(fabs(AngRota),fabs(AngPitch))/StepAng*RandRange(1.0f,3.0f);
				stepPitch = AngPitch / stepNum;
				stepRota  = AngRota  / stepNum;
				stepOffset = vec3();

			}

			//趋向闭合
			if (m_wayPointNum>MaxWayPoint*0.7f)
			{
				stepOffset = m_wayPoints[0].pos-preWayPoint->pos;
				stepOffset.Normalize();
				stepOffset*= (StepDist/stepNum*RandRange(3.0f,6.0f));
			}

			//增量旋转矩阵
			matStepRot.FromEulerAngRadZXY(vec3(stepPitch,stepRota,0)* DEG2RAD);

			file.Fprintf("point%d,  stepNum%d, angPitch%f, angHead%f, offset%f %f %f\n",m_wayPointNum,stepNum,AngPitch,AngRota,stepOffset.x,stepOffset.y,stepOffset.z);
			nextPoint = m_wayPointNum+stepNum;
		}


		//趋向闭合
		if (m_wayPointNum>MaxWayPoint*0.9f)
		{
			stepOffset = m_wayPoints[0].pos-preWayPoint->pos;
			stepOffset.Normalize();
			stepOffset*= (StepDist/*/stepNum*/*RandRange(1.0f,2.0f));
		}

		if (preWayPoint==NULL)
		{
			curWayPoint->matRot = matStepRot;
			curWayPoint->pos    = vec3(0,WorldMin.y,0);
		}
		else
		{
			if (m_wayPointNum==MaxWayPoint)
			{
				//闭合最后一个点
				//计算路点的旋转矩阵
				curWayPoint->matRot =  m_wayPoints[0].matRot;	
				curWayPoint->pos    = m_wayPoints[0].pos;
				stepRota = 0;
			}
			else
			{
				//计算路点的旋转矩阵
				//curWayPoint->matRot = matStepRot*preWayPoint->matRot;	//????
				curWayPoint->matRot = preWayPoint->matRot*matStepRot;	

				vec3  debug = curWayPoint->matRot * vec3(0,0,StepDist*ZFacing);
				curWayPoint->pos    = preWayPoint->pos + curWayPoint->matRot * vec3(0,0,StepDist*ZFacing);//-StepDist
				curWayPoint->pos    += stepOffset;
			}
		}

		调整,带偏移的大回旋圈处 matRot不正确 阶梯状
		//if (preWayPoint)
		//{
		//	mat4 adj;
		//	mat4 inverse = curWayPoint->matRot;
		//	inverse.Inverse();
		//	adj.FromToDir(vec3(0,0,-1*ZFacing),inverse*(preWayPoint->pos-curWayPoint->pos));//[-1 StepDist] 或 [1 -StepDist]
		//	curWayPoint->matRot = curWayPoint->matRot*adj;
		//}
	}

	CalWayPoints();
	GenBuffer();
}

class Ball
{
public:
	vec3  cen;
	float radius;
	vec3  start;
	int   stepNum;
	mat4  stepMat;
};
//过山车式轨道
void RollerWay::RandRollerTsp()
{
	File file;
	file.Fopen("data/environment/wall/RollerWay.txt","wt");

	//构造tsp路径
	const int CityNum = 32;//64;//30;//0;//32;
	Tsp tsp;
	tsp.CityNum = CityNum;
	for(int i = 0; i < CityNum; i++)
	{
		tsp.citys[i].index = i;
		tsp.citys[i].pos = vec3(RandRange(WorldMin.x,WorldMax.x),RandRange(WorldMin.y,WorldMax.y),RandRange(WorldMin.z,WorldMax.z));
	}
	tsp.SolveGreedy();

	//每段路径间使用若干圆柱过渡
	Ball balls[CityNum*3];
	int  ballNum = 0;
	Tsp::Path&  path = tsp.pathLess;
	vec3 localStart;
	vec3 localEnd;
	vec3 axis;
	int  stepNum;
	for(int i = 0; i < CityNum; i++)
	{
		vec3& curPoint  = path.citys[i]->pos;
		vec3& prevPoint = path.citys[(i-1+CityNum)%CityNum]->pos; 
		vec3& nextPoint = path.citys[(i+1)%CityNum]->pos;
		vec3& nextnextPoint = path.citys[(i+2)%CityNum]->pos;

		float disPrev = (curPoint-prevPoint).Length();
		float disNext = (curPoint-nextPoint).Length();
		float disNextNext = (nextPoint-nextnextPoint).Length();
		float curRadius = Min(disPrev,disNext)*0.5f;
		balls[ballNum].cen     = curPoint;
		balls[ballNum].radius  = curRadius;
		localStart = (prevPoint-curPoint);
		localEnd   = (nextPoint-curPoint);
		localStart.Normalize();
		localEnd.Normalize();
		balls[ballNum].start  = /*balls[ballNum].cen + */localStart*curRadius;
		float ang = SafeAcos(localStart.Dot(localEnd));
		axis = localStart.Cross(localEnd);
		if (ballNum%2)
		{
			stepNum = (curRadius*ang)/10.0f;
			if (stepNum<3)
			{
				stepNum = 3;
			}
			balls[ballNum].stepNum = stepNum;
			balls[ballNum].stepMat.FromAxisAngle(axis,ang/stepNum);
		}
		else
		{
			stepNum = (curRadius*(TWOPI-ang))/10.0f;
			if (stepNum<3)
			{
				stepNum = 3;
			}
			balls[ballNum].stepNum = stepNum;
			balls[ballNum].stepMat.FromAxisAngle(-axis,(TWOPI-ang)/stepNum);
		}
		ballNum++;

		//如果需要 在两点之间的边中部添加一个过渡球
		float nextRadius = Min(disNext,disNextNext)*0.5f;
		float cenRadius = (disNext - curRadius - nextRadius)*0.5f;
		if (cenRadius > 5)
		{
			localStart = (curPoint-nextPoint);
			localEnd   = (nextnextPoint-nextPoint);
			localStart.Normalize();
			localEnd.Normalize();
			axis = (axis+localStart.Cross(localEnd))*0.5f;

			//
			localStart = (curPoint-nextPoint);
			localStart.Normalize();
			localEnd   = -localStart;
			balls[ballNum].cen    = curPoint - localStart*(curRadius+cenRadius);
			balls[ballNum].radius = cenRadius;
			balls[ballNum].start  = /*balls[ballNum].cen + */localStart*cenRadius;
			float ang = _PI;
			if (ballNum%2)
			{
				stepNum = (curRadius*ang)/10.0f;
				if (stepNum<3)
				{
					stepNum = 3;
				}
				balls[ballNum].stepNum = stepNum;
				balls[ballNum].stepMat.FromAxisAngle(axis,ang/stepNum);
			}
			else
			{
				stepNum = (curRadius*(TWOPI-ang))/10.0f;
				if (stepNum<3)
				{
					stepNum = 3;
				}
				balls[ballNum].stepNum = stepNum;
				balls[ballNum].stepMat.FromAxisAngle(-axis,(TWOPI-ang)/stepNum);
			}
			ballNum++;
		}
	}

	//细分圆弧
	m_wayPointNum = 0;
	for(int i = 0; i < ballNum; i++)
	{
		localStart = balls[i].start;
		for(int j = 0; j < balls[i].stepNum; j++)
		{
			//if (j!=0)
			{
				m_wayPoints[m_wayPointNum].pos = balls[i].cen + localStart;
				m_wayPointNum++;
			}
			localStart = balls[i].stepMat*localStart;
		}
	}

	//平滑点

	CalWayPoints();
	GenBuffer();
}

//赛车式轨道: 禁止俯仰角 2d赛道 高度右地形提供
void RollerWay::RandRacing()
{
	File file;
	file.Fopen("data/environment/wall/RollerWay.txt","wt");

	//构造tsp路径
	int CityNum = 64;//30;//0;//32;
	Tsp tsp;
	tsp.CityNum = CityNum;
	for(int i = 0; i < CityNum; i++)
	{
		tsp.citys[i].index = i;
		tsp.citys[i].pos = vec3(RandRange(WorldMin.x,WorldMax.x),RandRange(WorldMin.y,WorldMax.y),RandRange(WorldMin.z,WorldMax.z));
	}
	tsp.SolveGreedy();

	//平滑路径
	HSpline* spline = new HSpline;
	spline->SetClosed(true);
	for(int i = 0; i < CityNum; i++)
	{
		spline->AddKnot(tsp.pathLess.citys[i]->pos);
	}
	spline->GenSmoothPoints(30);
	m_spline = spline;

	//拷贝点
	m_wayPointNum = m_spline->GetPointNum();
	for(int i = 0; i < m_wayPointNum; i++)
	{
		m_wayPoints[i].pos = m_spline->GetPoint(i)->pos;
	}

	CalWayPoints();

	//terrain可能在外部生成  或者内部生成 路面下架设柱子
	//。。。
	GenBuffer();
}

void RollerWay::CalWayPoints()
{
	//计算路点数据
	vec3 x_,z_;
	vec3 y_(0,1,0);

	mat4 matPos;
	mat3 matRot;
	for(int i = 0; i < m_wayPointNum; i++)
	{
		WayPoint_* curWayPoint  = &m_wayPoints[i];
		WayPoint_* preWayPoint  = &m_wayPoints[(i-1+m_wayPointNum)%m_wayPointNum];
		WayPoint_* nextWayPoint = &m_wayPoints[(i+1)%m_wayPointNum];

		//欧式路程
		if (i==0)
			curWayPoint->roadDist = 0;
		else
			curWayPoint->roadDist = preWayPoint->roadDist + (curWayPoint->pos-preWayPoint->pos).Length();

		//dir
		curWayPoint->dir = curWayPoint->pos-preWayPoint->pos;
		curWayPoint->dir.Normalize();

		//计算路点的变换矩阵

		//位移
		matPos.FromTranslate(curWayPoint->pos);

		//旋转
		1拧麻花
		//curWayPoint->matRot.FromToDir(vec3(0,0,-1*ZFacing),curWayPoint->dir);


		//2不拧麻花 路面可能朝下
		if (i==0)
		{
			curWayPoint->matRot.FromToDir(vec3(0,0,-1*ZFacing),vec3(0,1,0),curWayPoint->dir,vec3(0,1,0));
		}
		else
		{
			matRot.FromToDir(preWayPoint->dir,curWayPoint->dir);
			curWayPoint->matRot = matRot*preWayPoint->matRot;
		}
		//缓慢修正朝上 前面已经细分
		vec3 head = curWayPoint->matRot*vec3(0,0,-1*ZFacing);
		vec3 up = curWayPoint->matRot*vec3(0,1,0);
		vec3 tarUp = head.Cross(vec3(0,1,0)).Cross(head);
		float dot = up.Dot(tarUp);
		if ( dot< 0.8f)
		{
			float ang = SafeAcos(dot);
			if (ang>0.02f)
			{
				ang = 0.02f;
			}
			vec3 axis = up.Cross(tarUp);
			matRot.FromAxisAngle(axis.x,axis.y,axis.z,ang);
			curWayPoint->matRot = matRot*curWayPoint->matRot;
		}


		3路面始终朝上
		//curWayPoint->matRot.FromToDir(vec3(0,0,-1*ZFacing),vec3(0,1,0),curWayPoint->dir,vec3(0,1,0));

		//全部
		curWayPoint->matAll = matPos*curWayPoint->matRot;

		计算路点的桥墩式变换矩阵
		x_ = curWayPoint->matRot*vec3(1,0,0); 
		if (x_.Dot(y_) > 0.9f)
		{
			x_ = vec3(1,0,0);
		}
		z_ = x_.Cross(y_);
		z_.Normalize();
		curWayPoint->matPier.FromToDir(vec3(0,0,1*ZFacing),vec3(0,1,0),z_,vec3(0,1,0));
	}

	MaxDist = m_wayPoints[m_wayPointNum-1].roadDist;
	StepDist = MaxDist/m_wayPointNum;
}

void RollerWay::GenBuffer()
{
	随机左中右
	int lmr = 0;
	//nextPoint = RandRange(20,30);
	//for (int i=0;i<m_wayPointNum;i++)
	//{
	//	m_wayPoints[i].lmr = lmr;
	//	m_wayPoints[i].pos += m_wayPoints[i].matRot*vec3(20,0,StepDist*-3*ZFacing)*lmr;
	//	if (i==nextPoint)
	//	{
	//		lmr = RandRange(-1,1);
	//		nextPoint = i+RandRange(20,30);
	//	}
	//}

	//创建模型
	//段数
	int roadNum = MaxDist /100;
	//每段的欧式距离
	float roadDist = MaxDist /roadNum;//略大于100

	RendSys::Mesh* meshs[3] = 
	{
		m_roadMovieM->GetMesh(),
		m_roadMovieL->GetMesh(),
		m_roadMovieR->GetMesh(),
	};

	int MaxTrigonNum = 0;
	int MaxVertexNum = 0;
	for (int i=0;i<3;i++)
	{
		if (meshs[i]->m_trigonNum>MaxTrigonNum)
		{
			MaxTrigonNum = meshs[i]->m_trigonNum;
		}
		if (meshs[i]->m_vVertexNum>MaxVertexNum)
		{
			MaxVertexNum = meshs[i]->m_vVertexNum;
		}
	}
	MaxTrigonNum *= roadNum;
	MaxVertexNum *= roadNum;
	m_trigons = new Trigon[MaxTrigonNum];
	m_vVertexs = new Vertex[MaxVertexNum];

	m_trigonNum = 0;
	m_vVertexNum = 0;
	vec3 pos;
	float startDist = 0;
	for (int i=0;i<roadNum;i++,startDist+=roadDist)
	{
		lmr = RandRange(0,6);
		if (lmr>2)
		{
			lmr = 0;
		}
		RendSys::Mesh* mesh = meshs[lmr];

		int   startVertex = m_vVertexNum;
		//赋值索引
		RendSys::Mesh::Trigon* srcTrigon = mesh->m_trigons;
		Trigon* dstTrigon = &m_trigons[m_trigonNum];
		for (int j = 0; j < mesh->m_trigonNum; j++,srcTrigon++,dstTrigon++)
		{
			dstTrigon->vIndex[0] = startVertex + srcTrigon->vIndex[0];
			dstTrigon->vIndex[1] = startVertex + srcTrigon->vIndex[1];
			dstTrigon->vIndex[2] = startVertex + srcTrigon->vIndex[2];
		}

		//赋值点
		RendSys::Mesh::Vertex* srcVertex = mesh->m_vVertexs;
		Vertex* dstVertex = &m_vVertexs[startVertex];
		for (int j = 0; j < mesh->m_vVertexNum; j++,srcVertex++,dstVertex++)
		{
			pos.x = srcVertex->x;
			pos.y = srcVertex->y;
			pos.z = 0;//srcVertex->z;

			//float way = m_spline->Length2Path(startDist+srcVertex->z);
			float way = GetWayPos(startDist+srcVertex->z);
			int   iWay = way;

			//无缝衔接
			//pos = m_wayPoints[iWay].matAll* pos; //最后一段跨度太长有问题

			//插值位置
			pos = m_wayPoints[iWay].matRot*pos + GetPos(way);

			//插值矩阵 
			//slerp matrix Slerp(m_wayPoints[iWay].matAll,m_wayPoints[iWay+1].matAll)

			dstVertex->x = pos.x;
			dstVertex->y = pos.y;
			dstVertex->z = pos.z;


			dstVertex->u = mesh->m_tVertexs[j].u;
			dstVertex->v = mesh->m_tVertexs[j].v;
			dstVertex->w = mesh->m_tVertexs[j].w;

		}
		m_trigonNum += mesh->m_trigonNum;
		m_vVertexNum += mesh->m_vVertexNum;

		//标记路段的lmr
		float start = GetWayPos(startDist);
		float end = GetWayPos(startDist+roadDist);
		for (int i=start;i<end;i++)
		{
			m_wayPoints[i].lmr = lmr;
		}
	}
}


void RollerWay::LoadFromFile()
{

}

void RollerWay::Render()
{
	G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,true);
	//路径
	//m_spline->Render();

	G_RendDriver->EnableRendState(RS_BLEND);
	G_RendDriver->EnableRendState(RS_TEXTURE_2D);
	G_RendDriver->EnableRendState(RS_LIGHTING);
	G_RendDriver->Color4f(1.0f, 1.0f, 1.0f, 1.0f);

	//
	m_texRoad->Bind();
	if (G_ShaderMgr&& G_ShaderMgr->m_curEffect)
	{
		G_ShaderMgr->MapChangeParm();
	}

	Vertex* v;	
	int begin = 0;
	while(1)
	{
		G_RendDriver->RendBegin(RS_TRIANGLES);
		//一次最多10000
		int trigonNum = min(10000,m_trigonNum-begin);
		int end = begin + trigonNum;
		for (int i = begin; i < end; i++)
		{
			Vertex*  vertexs = m_vVertexs;
			v = &vertexs[m_trigons[i].vIndex[0]];
			//G_RendDriver->Normal3f(v->nx,v->ny,v->nz);
			G_RendDriver->TexCoord3f(v->u,v->v,v->w);
			G_RendDriver->Vertex3f(v->x,v->y,v->z);

			v = &vertexs[m_trigons[i].vIndex[1]];
			//G_RendDriver->Normal3f(v->nx,v->ny,v->nz);
			G_RendDriver->TexCoord3f(v->u,v->v,v->w);
			G_RendDriver->Vertex3f(v->x,v->y,v->z);	

			v = &vertexs[m_trigons[i].vIndex[2]];
			//G_RendDriver->Normal3f(v->nx,v->ny,v->nz);
			G_RendDriver->TexCoord3f(v->u,v->v,v->w);
			G_RendDriver->Vertex3f(v->x,v->y,v->z);	
		}
		G_RendDriver->RendEnd();

		begin+= trigonNum;
		if (begin>=m_trigonNum)
		{
			break;
		}
	}


	//路墩子
	if (StepDist>0)
	{
		int num = 700.0f/StepDist + 10;
		//if ()
		//{
		//	//第三人称
		//	for (int i=0; i<m_wayPointNum; i+=num)
		//	{
		//		for (; i<m_wayPointNum;i++)
		//		{
		//			if (fabs(m_wayPoints[i].dir.y)<0.7)
		//			{
		//				G_RendDriver->PushMatrix();
		//				G_RendDriver->MultMatrix(m_wayPoints[i].matPier);
		//				m_pierMovie->RendClip();
		//				G_RendDriver->PopMatrix();
		//				break;
		//			}
		//		}
		//	}
		//}
		//else
		{
			//第一人称
			//桥墩子机关 上下左右关门 蜗牛
			for (int i=0; i<m_wayPointNum; i+=num)
			{
				for (; i<m_wayPointNum;i++)
				{
					if (fabs(m_wayPoints[i].dir.y)<0.7)
					{
						//G_RendDriver->PushMatrix();
						//G_RendDriver->MultMatrix(m_wayPoints[i].matAll);
						//m_pierMovie->RendClip();
						//G_RendDriver->PopMatrix();

						RendSys::Frame frame;
						frame.m_matrix = m_wayPoints[i].matAll;
						m_pierMovie->SetProgramFrame(&frame);
						m_pierMovie->Advance(-1.0f);
						m_pierMovie->RendClip();

						if ((i/num)%2==0)
						{
							m_doorMovieL->SetProgramFrame(&frame);
							m_doorMovieL->Advance(-1.0f);
							m_doorMovieL->RendClip();
						}
						else if ((i/num)%2==1)
						{
							m_doorMovieR->SetProgramFrame(&frame);
							m_doorMovieR->Advance(-1.0f);
							m_doorMovieR->RendClip();
						}

						break;
					}
				}
			}
		}
	}
}

void RollerWay::Update()
{
}


vec3 RollerWay::GetPos(float way)
{
	int iWay = way;
	return m_wayPoints[iWay].pos *(1-(way-iWay))
		+m_wayPoints[(iWay+1)%m_wayPointNum].pos*(way-iWay); 
}

float RollerWay::GetWayPos(float dist)
{
	if (dist<0)
	{
		dist += MaxDist;
	}
	else if (dist > MaxDist)
	{
		dist -= MaxDist;
	}

	int iWay = dist/StepDist; //猜测大致路点加速
	if (iWay>m_wayPointNum-1)
	{
		iWay = m_wayPointNum-1;
	}

	//while(m_wayPoints[iWay+1].roadDist<dist && iWay<m_wayPointNum-1)
	//{
	//	//前进查找 渐进猜测
	//	int m = (dist-m_wayPoints[iWay].roadDist)/StepDist;
	//	iWay+=max(1,m);
	//}
	//if(m_wayPoints[iWay].roadDist>dist && iWay>0)
	//{
	//	//回退查找
	//	while(1)
	//	{
	//		iWay--;
	//		if(m_wayPoints[iWay].roadDist<=dist || iWay<=0)
	//			break;
	//	}
	//}

	if(m_wayPoints[iWay+1].roadDist<dist && iWay<m_wayPointNum-1)
	{
		//前进查找
		while(1)
		{
			iWay++;
			if(iWay>=m_wayPointNum-1)
			{
				break;
			}
			if(m_wayPoints[iWay].roadDist>=dist)
			{
				if(iWay>0)
					iWay--;
				break;
			}
		}
	}
	else if(m_wayPoints[iWay].roadDist>dist && iWay>0)
	{
		//回退查找
		while(1)
		{
			iWay--;
			if(m_wayPoints[iWay].roadDist<=dist || iWay<=0)
				break;
		}
	}

	if (iWay>=m_wayPointNum-1)
	{
		return iWay;
	}

	float edgeDist = m_wayPoints[iWay+1].roadDist - m_wayPoints[iWay].roadDist;
	if (edgeDist<_EPSILON&&edgeDist>-_EPSILON)
	{
		return iWay;
	}
	float way = iWay + (dist - m_wayPoints[iWay].roadDist)/edgeDist;
	return way;
}

完 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值