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); 
}