www.pudn.com > 3DEDITOR.rar > RAYTRACE.CPP
#include "stdafx.h"
#include "3DEditor.h"
#include "RenderView.h"
extern CProgressCtrl *progress;
extern CStatic *status,*status2;
extern time_t t1;
extern CRITICAL_SECTION cs_rv;
extern RenderView *renderview;
float IntPower(float a,unsigned n)
{
float b;
b=1.0;
while( n-- )
b*=a;
return b;
}
void CalcReflectionVector(vector& Rd,vector& N,vector& newRd)
{
newRd=((float)-2.0*VecDot(N,Rd))*N+Rd;
newRd.Normalize();
}
int CalcRefractionVector(vector Rd,vector& N,vector& newRd,float n1,float n2)
{
vector sinT,cosV;
float lsinT,n,NdotV,NdotT;
Rd.Negate();
NdotV=VecDot(N,Rd);
if (NdotV>SMALL)
n=n1/n2;
else n=n2/n1;
cosV=N*NdotV;
sinT=(cosV-Rd)*n;
lsinT=VecDot(sinT,sinT);
if (lsinT>=1.0)
return 0;
NdotT=(float)sqrt(1.0-lsinT);
if (NdotV0&&xsx-1&&y>0&&ysy-1)
{
byteRGB *rgb1;
int r,g,b;
rgb1=(byteRGB *)&p->buf[y][x*3];
r=4*(int)rgb1->r-(int)(rgb1-1)->r-(int)(rgb1+1)->r;
g=4*(int)rgb1->g-(int)(rgb1-1)->g-(int)(rgb1+1)->g;
b=4*(int)rgb1->b-(int)(rgb1-1)->b-(int)(rgb1+1)->b;
rgb1=(byteRGB *)&p->buf[y-1][x*3];
r-=(int)rgb1->r;
g-=(int)rgb1->g;
b-=(int)rgb1->b;
rgb1=(byteRGB *)&p->buf[y+1][x*3];
r-=(int)rgb1->r;
g-=(int)rgb1->g;
b-=(int)rgb1->b;
if (abs(r)>factor || abs(g)>factor || abs(b)>factor)
return 1;
}
return 0;
}
void scene::trace_ray(camera *cam,picture *p,int x,int y,int ray_depth,vector& color)
{
double ipdist,angx,angy;
int i;
ray r;
ipdist=0.5*p->sy/TanD(0.5*cam->theta);
angx=atan((x-p->sx/2.0+0.5)/ipdist);
angy=-atan((y-p->sy/2.0+0.5)/ipdist);
r.rd.Vec((float)(sin(angx)*cos(angy)),(float)(sin(angy)*cos(angx)),-(float)(cos(angx)*cos(angy)));
r.rd=r.rd*cam->mat;
r.rd.Normalize();
r.ro=cam->Vp;
r.at.Vec(1,1,1);
r.depth=ray_depth;
color.Null();
shoot_ray(&r,color);
byteRGB *rgb=(byteRGB *)&p->buf[y][x*3];
i=(int)(color.x*255);
rgb->r=i>255?255:i;
i=(int)(color.y*255);
rgb->g=i>255?255:i;
i=(int)(color.z*255);
rgb->b=i>255?255:i;
}
picture *scene::ray_trace(camera *cam,int& sx,int& sy,int ray_depth,int maxdepth,int minfaces,int antialiase,int antialiase_factor)
{
char str[256];
progress->SetRange(0,sy);
progress->SetPos(0);
progress->SetStep(1);
status2->SetWindowText("00:00:00");
CString s;
s.LoadString(IDS_RAYALLOC);
status->SetWindowText(s);
picture *p=new picture;
p->CreatePicture24(sx,sy);
p->ErasePicture(0);
if (oc==0)
{
s.LoadString(IDS_RAYBUILDOC);
status->SetWindowText(s);
build_octree(minfaces,maxdepth);
}
s.LoadString(IDS_RAYTRACING);
status->SetWindowText(s);
headlightpos=cam->Vp;
int x,y,i,ssx,ssy,px,py;
double angx,angy,ipdist=0.5*p->sy/TanD(0.5*cam->theta);
time_t t2;
byteRGB *rgb;
vector color;
ray r;
unsigned char *use=new unsigned char[sx*sy];
memset(use,0,sx*sy);
if (sysx)
ssx=sx;
ssy=ssx*sy/sx;
for( y=0;ySetPos(ssy);
EnterCriticalSection(&cs_rv);
if (renderview)
renderview->DrawPicture(p,ssx,ssy);
LeaveCriticalSection(&cs_rv);
time(&t2);
t2-=t1;
sprintf(str,"%02i:%02i:%02i",t2/3600,(t2/60)%60,t2%60);
status2->SetWindowText(str);
}
if (progress==0 && (ssxbuf[y1+b][(x1+a)*3];
gg+=p->buf[y1+b][(x1+a)*3+1];
bb+=p->buf[y1+b][(x1+a)*3+2];
}
if (nn>0)
{
p->buf[y1][x1*3]=rr/nn;
p->buf[y1][x1*3+1]=gg/nn;
p->buf[y1][x1*3+2]=bb/nn;
}
}
}
EnterCriticalSection(&cs_rv);
if (renderview)
renderview->DrawPicture(p,ssx,ssy);
LeaveCriticalSection(&cs_rv);
}
delete use;
if (antialiase&&progress)
{
s.LoadString(IDS_RAYANTIALIASE);
status->SetWindowText(s);
if (progress) progress->SetPos(0);
int ix,iy;
float w=(float)1.0/(antialiase*2+1);
vector c;
for( y=0;ybuf[y];
for( x=0;xr/(float)255;
color.y=rgb->g/(float)255;
color.z=rgb->b/(float)255;
for( iy=-antialiase;iy<=antialiase;iy++ )
for( ix=-antialiase;ix<=antialiase;ix++ )
if (ix!=0 || iy!=0)
{
angy=-atan((y-sy/2.0+0.5+w*iy)/ipdist);
angx=atan((x-sx/2.0+0.5+w*ix)/ipdist);
r.rd.Vec((float)(sin(angx)*cos(angy)),(float)(sin(angy)*cos(angx)),-(float)(cos(angx)*cos(angy)));
r.rd=r.rd*cam->mat;
r.rd.Normalize();
r.ro=cam->Vp;
r.at.Vec(1,1,1);
r.depth=ray_depth;
c.Null();
shoot_ray(&r,c);
color+=c;
}
color/=(float)((antialiase*2+1)*(antialiase*2+1));
i=(int)(color.x*255);
rgb->r=i>255?255:i;
i=(int)(color.y*255);
rgb->g=i>255?255:i;
i=(int)(color.z*255);
rgb->b=i>255?255:i;
}
if (progress==0)
break;
else progress->StepIt();
if ((y%4)==0 || y==sy-1)
{
EnterCriticalSection(&cs_rv);
if (renderview)
renderview->DrawPicture(p,ssx,ssy);
LeaveCriticalSection(&cs_rv);
}
time(&t2);
t2-=t1;
sprintf(str,"%02i:%02i:%02i",t2/3600,(t2/60)%60,t2%60);
status2->SetWindowText(str);
}
}
s.LoadString(IDS_RAYFINISHED);
status->SetWindowText(s);
sx=ssx;
sy=ssy;
return p;
}
void scene::shoot_ray(ray *r,vector& color)
{
vector n,ip,c;
float u,v,dist;
ftlist *ft;
if (oc->bbox.ray_intersect(r->ro,r->rd)==-1)
ft=0;
else ft=(ftlist *)oc->ray_intersect(r->ro,r->rd,ip,dist);
if (ft==0)
{
color+=background*r->at;
return;
}
ft->compute_nuv(((object *)(ft->flag))->textcoord,ip,n,u,v);
if (VecDot(r->rd,n)>0)
n.Negate();
compute_color(ft,ip,n,r->rd,u,v,c);
float transp;
material *mat=&matlib[ft->material];
if (mat->map_opacity.piclibindx!=-1)
{
picture *p=&piclib[mat->map_opacity.piclibindx];
byteRGB rgb;
calc_uv(u, v, &(mat->map_opacity));
p->GetPixel(u*p->sx, v*p->sy, &rgb, textinterp);
transp=(float)(255-rgb.Intensity())/(float)255;
}
else transp=mat->transparency;
color+=c*r->at;
if (--r->depth)
{
ray r2;
if (mat->reflection>0)
{
r2=*r;
r2.ro=ip;
r2.at=r->at*mat->reflection;
if (r2.at.x>(float)0.05 || r2.at.y>(float)0.05 || r2.at.z<(float)0.05)
{
CalcReflectionVector(r->rd,n,r2.rd);
shoot_ray(&r2,color);
}
}
if (transp)
{
r2=*r;
r2.ro=ip;
r2.at=r->at*transp;
if (r2.at.x>(float)0.05 || r2.at.y>(float)0.05 || r2.at.z<(float)0.05)
{
if (CalcRefractionVector(r->rd,n,r2.rd,1, mat->refraction))
shoot_ray(&r2,color);
}
}
}
}
void scene::compute_color(ftlist *ft,vector& ip,vector& n,vector& view,float u,float v,vector& color)
{
static vector ro,rd,lc,r,dif,self_illum;
static float dist,d,dot,LdotN,VdotR,us,vs,transp;
static int l,nl;
static ftlist *f;
static byteRGB rgb;
material *mat=&matlib[ft->material];
dif=*((vector *)&mat->diffuse);
static float ru, rv;
if (mat->map_opacity.piclibindx!=-1)
{
picture *p=&piclib[mat->map_opacity.piclibindx];
calc_uv(ru=u, rv=v, &(mat->map_opacity));
p->GetPixel(ru*p->sx, rv*p->sy, &rgb, textinterp);
transp=(float)(255-rgb.Intensity())*mat->map_opacity.amount/(float)25500;
}
else transp=mat->transparency;
if (mat->map_texture1.piclibindx!=-1)
{
picture *p=&piclib[mat->map_texture1.piclibindx];
calc_uv(ru=u, rv=v, &(mat->map_texture1));
p->GetPixel(ru*p->sx, rv*p->sy, &rgb, textinterp);
dif.x*=(float)rgb.r/(float)255;
dif.y*=(float)rgb.g/(float)255;
dif.z*=(float)rgb.b/(float)255;
}
if (mat->map_selfillum.piclibindx!=-1)
{
picture *p=&piclib[mat->map_selfillum.piclibindx];
calc_uv(ru=u, rv=v, &(mat->map_selfillum));
p->GetPixel(ru*p->sx, rv*p->sy, &rgb, textinterp);
self_illum.x=(float)rgb.r/(float)255;
self_illum.y=(float)rgb.g/(float)255;
self_illum.z=(float)rgb.b/(float)255;
self_illum*=mat->map_selfillum.amount/(float)100;
}
else self_illum.Vec(mat->self_illum,mat->self_illum,mat->self_illum);
if (mat->map_bump.piclibindx!=-1)
{
picture *p=&piclib[mat->map_bump.piclibindx];
calc_uv(ru=u, rv=v, &(mat->map_bump));
p->GetPixel(ru*p->sx+1, rv*p->sy, &rgb, textinterp);
int dx=rgb.Intensity();
p->GetPixel(ru*p->sx-1, rv*p->sy, &rgb, textinterp);
dx-=rgb.Intensity();
p->GetPixel(ru*p->sx, rv*p->sy+1, &rgb, textinterp);
int dy=rgb.Intensity();
p->GetPixel(ru*p->sx, rv*p->sy-1, &rgb, textinterp);
dy-=rgb.Intensity();
if(dx || dy)
{
vector du,dv;
ft->compute_dudv(ip,ru,rv,du,dv);
n-=((dx/(float)255)*du+(dy/(float)255)*dv)*mat->map_bump.amount/(float)100;
n.Normalize();
}
}
color.Null();
nl=headlight?1:nlights;
for( l=0;lbbox.ray_intersect(ro,rd)==-1)
break;
f=(ftlist *)oc->ray_intersect(ro,rd,r,d);
if (f==0 || f==ft) break;
f->compute_nuv(((object *)(f->flag))->textcoord,r,ro,us,vs);
ro=r;
if (matlib[f->material].map_opacity.piclibindx!=-1)
{
picture *p=&piclib[matlib[f->material].map_opacity.piclibindx];
byteRGB rgb;
calc_uv(ru=us, rv=vs, &(matlib[f->material].map_opacity));
p->GetPixel(ru*p->sx, rv*p->sy, &rgb, textinterp);
d=(float)(255-rgb.Intensity())/(float)255;
}
else d=matlib[f->material].transparency;
if (d<0.01)
break;
if (matlib[f->material].map_texture1.piclibindx!=-1)
{
picture *p=&piclib[matlib[f->material].map_texture1.piclibindx];
calc_uv(ru=us, rv=vs, &(matlib[f->material].map_texture1));
p->GetPixel(ru*p->sx, rv*p->sy, &rgb, textinterp);
r.x=(float)rgb.r/(float)255;
r.y=(float)rgb.g/(float)255;
r.z=(float)rgb.b/(float)255;
}
else r=*((vector *)(&matlib[f->material].diffuse[0]));
lc=lc*d+lc*d*(1-d)*r;
if (lc.x<0) lc.x=0;
if (lc.y<0) lc.y=0;
if (lc.z<0) lc.z=0;
if (lc.x>1) lc.x=1;
if (lc.y>1) lc.y=1;
if (lc.z>1) lc.z=1;
} while(1);
if (f==ft)
{
if (headlight==-1)
{
VdotR=0;
LdotN=1;
}
else
{
if (headlight==0 && lightlib[l].type==1)
{
dot=VecDot(lightlib[l].dir,rd);
if (dot0)
VdotR=0;
else VdotR=IntPower(-VdotR,(int)(100*mat->shininess))*mat->shininess_strength;
}
color+=lc*( dif*LdotN + *((vector *)&mat->specular)*VdotR );
}
}
color+=*((vector *)&mat->ambient)*amblight+dif*self_illum;
}
void scene::build_octree(int min,int depth)
{
if (oc)
delete oc;
oc=new octree_node;
object *o=obj0;
int f;
while(o)
{
oc->add((tree_elem **)(o->ft),o->nf);
for( f=0;fnf;f++ )
if (o->ft[f])
o->ft[f]->flag=(int)o;
o=o->next;
}
oc->compute_bbox();
oc->split(min,depth);
}