📄 flybezier.cpp
字号:
#include "../Fly3D.h"
float bezier_curve::distance(float *p,float *p1,float *p2)
{
// returns distance from point p to line defined by p1,p2
float dot=0,len1=0,len2=0;
int i;
// alloc two vectors
float *v1=new float [nd];
float *v2=new float [nd];
// compute length from (p1,p) and (p1,p2)
for( i=0;i<nd;i++ )
{
v1[i]= p[i]-p1[i];
v2[i]=p2[i]-p1[i];
len1+=v1[i]*v1[i];
len2+=v2[i]*v2[i];
}
len1=(float)sqrt(len1);
len2=(float)sqrt(len2);
// normalize
if (len1>0)
for( i=0;i<nd;i++ )
v1[i]/=len1;
if (len2>0)
for( i=0;i<nd;i++ )
v2[i]/=len2;
// compute dot product
for( i=0;i<nd;i++ )
dot+=v1[i]*v2[i];
// free vectors
delete v1;
delete v2;
// return distance
return (float)sqrt(len1*len1*(1.0f-dot*dot));
}
int bezier_curve::adaptative_subdiv(float maxerror,float *points,int maxpoints)
{
if (maxpoints<2) return 0;
int npoints,i,j;
float tmp;
// start points list with two points (the curve edges)
points[0]=0.0f;
points[1]=1.0f;
npoints=2;
// subdiv curve recursevily
subdiv(0,1,&p[0],&p[nd*(np-1)],points,npoints,maxerror,maxpoints);
// sort points
for( i=1;i<npoints;i++ )
for( j=i+1;j<npoints;j++ )
if (points[j]<points[i])
{
tmp=points[i];
points[i]=points[j];
points[j]=tmp;
}
// sort number of points
return npoints;
}
void bezier_curve::subdiv(float u1,float u2,float *p1,float *p2,float *points,int& npoints,float maxerror,int maxpoints)
{
// if points list is not full
if (npoints<maxpoints)
{
// alloc a new point
float *p=new float[nd];
// compute segment midpoint coordinate
float u=(u1+u2)*0.5f;
// evaluate curve at the segment midpoint
evaluate(u,p);
// if error is bigger then maxerror
if (distance(p,p1,p2)>maxerror)
{
// add point to points list
points[npoints++]=u;
// subdiv each segment recursevily
subdiv(u1,u,p1,p,points,npoints,maxerror,maxpoints);
subdiv(u,u2,p,p2,points,npoints,maxerror,maxpoints);
}
// delete allocated point
delete p;
}
}
void bezier_curve::reset()
{
if (p)
delete p;
p=0;
ns=0;
np=0;
}
void bezier_curve::set_dim(int ndim)
{
reset();
nd=ndim;
}
void bezier_curve::add_point(float *f)
{
// adds a new point to the curve
// f must point to nd floats
if (nd==0) return;
float *t=new float[(np+1)*nd];
if (p!=0)
{
memcpy(t,p,sizeof(float)*np*nd);
delete p;
}
p=t;
memcpy(&p[np*nd],f,sizeof(float)*nd);
np++;
if (((np-4)%3)==0 && np>1)
ns++;
}
void bezier_curve::evaluate_tangent(float u,float *f)
{
// evaluate the curve tangent at position u
// f must point to nd floats
if (p==0) return;
static float B[4];
float u1,u2;
int s,a,b,c;
if (u==1.0f)
s=np-4;
else s=(int)(u*(np-1))/3*3;
u1=(u-(float)s/(np-1))*ns;
u2=u1*u1;
B[0] =-3.0f + 6.0f*u1 - 3.0f*u2;
B[1] = 3.0f - 12.0f*u1 + 9.0f*u2;
B[2] = 6.0f*u1 - 9.0f*u2;
B[3] = 3.0f*u2;
memset(f,0,sizeof(float)*nd);
c=s*nd;
for( a=0;a<4;a++ )
for( b=0;b<nd;b++ )
f[b]+=p[c++]*B[a];
}
void bezier_curve::evaluate(float u,float *f)
{
// evaluate the curve point at position u
// f must point to nd floats
if (p==0) return;
static float B[4];
float u1,u2;
int s,a,b,c;
if (u==1.0f)
s=np-4;
else s=(int)(u*(np-1))/3*3;
u1=(u-(float)s/(np-1))*ns;
u2=1.0f-u1;
B[0]=u2*u2*u2;
B[1]=3.0f*u1*u2*u2;
B[2]=3.0f*u1*u1*u2;
B[3]=u1*u1*u1;
memset(f,0,sizeof(float)*nd);
c=s*nd;
for( a=0;a<4;a++ )
for( b=0;b<nd;b++ )
f[b]+=p[c++]*B[a];
}
int bezier_curve::load_bez(char *file)
{
// loads the curve from a .bez text file
fly_pak fp;
if (!fp.open(file))
return 0;
reset();
int i,j,n,d;
float *f;
pivot.x=fp.get_float();
pivot.y=fp.get_float();
pivot.z=fp.get_float();
d=fp.get_int();
n=fp.get_int();
set_dim(d);
f=new float[d];
for( i=0;i<n;i++ )
{
for( j=0;j<d;j++ )
f[j]=fp.get_float();
add_point(f);
}
delete f;
fp.close();
return 1;
}
float bezier_curve::length()
{
if (ns==0 || nd==0) return 0;
int i,j=ns*8,k,vv=1;
float *v[2],len=0.0f,f;
v[0]=new float[nd];
v[1]=new float[nd];
evaluate(0.0f,v[0]);
for( i=1;i<j;i++ )
{
evaluate((float)i/(j-1),v[vv]);
f=0.0f;
for( k=0;k<nd;k++ )
f+=(v[0][k]-v[1][k])*(v[0][k]-v[1][k]);
len+=(float)sqrt(f);
vv=!vv;
}
delete v[0];
delete v[1];
return len;
}
void bezier_patch::build_loft(bezier_curve *shape,bezier_curve *path,int texture,int lightmap,float tileu,float tilev)
{
reset();
if (shape && path && shape->nd==3 && path->nd==3)
{
mode=4;
texpic=texture;
lm=lightmap;
npu=shape->np;
npv=path->np;
np=npu*npv;
nsu=shape->ns;
nsv=path->ns;
p=new vector[np];
t=new vector[np];
vector v;
local_system ls;
int i,j,k=0;
ls.align_z(vector(0,0,1));
for( j=0;j<npv;j++ )
{
path->evaluate_tangent((float)j/(npv-1),&v.x);
v.normalize();
ls.rotate(ls.Z,v);
v=*((vector *)&path->p[j*3]);
for( i=0;i<npu;i++ )
{
p[k]=v+(*((vector *)&shape->p[i*3])*ls.mat);
t[k].x=(float)i/(npu-1)*tileu;
t[k].y=(float)j/(npv-1)*tilev;
t[k].z=(float)i/(npu-1);
t[k].w=(float)j/(npv-1);
k++;
}
}
}
}
void bezier_patch::evaluate(int evaltype,float u,float v,vector *dest)
{
if (p==0 || t==0)
return;
static float Bu[4],Bv[4],Bdu[4],Bdv[4];
float u1,u2,v1,v2,f;
int i,j,k,su,sv;
vector point(0,0,0);
vector textcoord(0,0,0,0);
vector du(0,0,0),dv(0,0,0);
switch(mode)
{
case 3:
if (FP_BITS(u)==FP_ONE_BITS)
su=npu-3;
else su=(int)(u*(npu-1))/2*2;
u1=(u-(float)su/(npu-1))*nsu;
if (FP_BITS(v)==FP_ONE_BITS)
sv=npv-3;
else sv=(int)(v*(npv-1))/2*2;
v1=(v-(float)sv/(npv-1))*nsv;
u2=1.0f-u1;
Bu[0]=u2*u2;
Bu[1]=2.0f*u1*u2;
Bu[2]=u1*u1;
v2=1.0f-v1;
Bv[0]=v2*v2;
Bv[1]=2.0f*v1*v2;
Bv[2]=v1*v1;
if (evaltype&PATCH_EVAL_NORMAL)
{
Bdu[0]= 2.0f*u1-2.0f;
Bdu[1]= 2.0f-4.0f*u1;
Bdu[2]= 2.0f*u1;
Bdv[0]= 2.0f*v1-2.0f;
Bdv[1]= 2.0f-4.0f*v1;
Bdv[2]= 2.0f*v1;
}
break;
case 4:
if (FP_BITS(u)==FP_ONE_BITS)
su=npu-4;
else su=(int)(u*(npu-1))/3*3;
u1=(u-(float)su/(npu-1))*nsu;
if (FP_BITS(v)==FP_ONE_BITS)
sv=npv-4;
else sv=(int)(v*(npv-1))/3*3;
v1=(v-(float)sv/(npv-1))*nsv;
u2=1.0f-u1;
Bu[0]=u2*u2*u2;
Bu[1]=3.0f*u1*u2*u2;
Bu[2]=3.0f*u1*u1*u2;
Bu[3]=u1*u1*u1;
v2=1.0f-v1;
Bv[0]=v2*v2*v2;
Bv[1]=3.0f*v1*v2*v2;
Bv[2]=3.0f*v1*v1*v2;
Bv[3]=v1*v1*v1;
if (evaltype&PATCH_EVAL_NORMAL)
{
u2=u1*u1;
Bdu[0]=-3.0f + 6.0f*u1 - 3.0f*u2;
Bdu[1]= 3.0f - 12.0f*u1 + 9.0f*u2;
Bdu[2]= 6.0f*u1 - 9.0f*u2;
Bdu[3]= 3.0f*u2;
v2=v1*v1;
Bdv[0]=-3.0f + 6.0f*v1 - 3.0f*v2;
Bdv[1]= 3.0f - 12.0f*v1 + 9.0f*v2;
Bdv[2]= 6.0f*v1 - 9.0f*v2;
Bdv[3]= 3.0f*v2;
}
}
for( i=0;i<mode;i++ )
for( j=0;j<mode;j++ )
{
k=(sv+j)*npu+su+i;
f=Bu[i]*Bv[j];
if (evaltype&PATCH_EVAL_POINT)
{
point.x+=f*p[k].x;
point.y+=f*p[k].y;
point.z+=f*p[k].z;
}
if (evaltype&PATCH_EVAL_TEXTCOORD)
{
textcoord.x+=f*t[k].x;
textcoord.y+=f*t[k].y;
textcoord.z+=f*t[k].z;
textcoord.w+=f*t[k].w;
}
if (evaltype&PATCH_EVAL_NORMAL)
{
du+=p[k]*(Bdu[i]*Bv[j]);
dv+=p[k]*(Bu[i]*Bdv[j]);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -