之前在赛车游戏中介绍过一种利用迷宫拼接随机赛道的方法,之前介绍的波函数坍缩算法也很适合用来拼接随机赛道。今天介绍另外一种随机赛道生成方法。
路径变形算法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;
}
完