java光线跟踪_用 Javascript 实现光线跟踪算法

光线跟踪算法的介绍

光线跟踪是一种真实地显示物体的方法,该方法由Appe在1968年提出。光线跟踪方法沿着到达视点的光线的反方向跟踪,经过屏幕上每一个象素,找出与视线相交的物体表面点P0,并继续跟踪,找出影响P0点光强的所有光源,从而算出P0点上精确的光线强度,在材质编辑中经常用来表现镜面效果。光线跟踪或称光迹追踪是计算机图形学的核心算法之一。在算法中,光线从光源被抛射出来,当他们经过物体表面的时候,对他们应用种种符合物理光学定律的变换。最终,光线进入虚拟的摄像机底片中,图片被生成出来。

效果图

f10e43708c14d62408e4c4338a2d12eb.png

基本思想

筒型照明器的传输方程有一个cos

可以写出球形等各种照明器

场景中每个表面都有自己的辐射率,从照明器随机位置发射随机方向粒子,检测碰撞

如果击中则增加击中表面的辐射率l,p控制粒子最终是否被表面吸收,并随机决定是否反射

把数据存储在对象的纹理文件中

进行路径跟踪,类似光线跟踪。

至此,我们来实现一个光线跟踪的效果,背景使用棋盘格,场景中放置几个物体,为了简化就只是三个不同颜色的球体。

首先完成摄影机的视距模型,然后根据光线跟踪方程,遍历每一个像素点,计算颜色。

最后添加设定为右上方的灯光。

代码如下

document.body.style.background="#000";

var C=document.getElementById("CANVAS").getContext("2d")

document.onkeydown = function(event){

if(event.keyCode==38){//up

cinemaZ+=10;

}

else if(event.keyCode==40){//down

cinemaZ-=10;

}

else if(event.keyCode==37){//left

q+=-.005

}

else if(event.keyCode==39){//right

q-=-.005

}

}

function sphere_hit(x,y,z,r,ex,ey,ez,sx,sy,sz){

m=Math

a=(sx-ex)*(sx-ex)+(sy-ey)*(sy-ey)+(sz-ez)*(sz-ez)

b=2*(sx-ex)*(ex-x)+2*(sy-ey)*(ey-y)+2*(sz-ez)*(ez-z)

c=ex*ex-2*x*ex+x*x + ey*ey-2*y*ey+y*y + ez*ez-2*z*ez+z*z -r*r

theta=b*b-4*a*c

if(theta<0)return null;

else {

x1=(-b+m.sqrt(theta))/(2*a)

x2=(-b-m.sqrt(theta))/(2*a)

//alert("a:"+a+".b:"+b+".c:"+c+".x1="+x1+" x2="+x2)

tt=(x1

return {

t:tt,

nx:ex+sx*tt-x,

ny:ey+sy*tt-y,

nz:ez+sz*tt-z

};

}

}

function unitization(vector)

{

if(vector[0]==null || vector[1]==null || vector[2]==null) return alert("In Function unitization:Not Acceptable Parameters")

m=Math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2])

return new Array(vector[0]/m,vector[1]/m,vector[2]/m)

}

function transvection(v1,v2){

if(v1[0]==null || v1[1]==null || v[2]==null) return alert("In Function transvection:Not Acceptable Parameters in 1")

if(v2[0]==null || v2[1]==null || v2[2]==null) return alert("In Function transvection:Not Acceptable Parameters in 2")

return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]

}

/*

************obj List***********

1.Sphere

2.Sphere

3.Sphere

4.Plate

************obj List***********

*/

plateN = [0,-1,0]

var obj = new Array(

new Array(new Array(-500,-300,250),300,[255,0,0]),

new Array(new Array(-300,-300,700),300,[255,200,0]),

new Array(new Array(300,-300,15),300,[0,0,255])

)

e=[0,-300,-800]

screenZ=-500

dem=[700,1000]

directal_light=unitization([1/1.732,1/1.732,-1/1.732])

envir_col=[0.6,0.6,0.6]

function detection(e,s){

if(e[0]==null || e[1]==null || e[2]==null)return alert("In Function detection:Not Acceptable Parameters in 1")

if(s[0]==null || s[1]==null || s[2]==null)return alert("In Function detection:Not Acceptable Parameters in 2")

var nearest={}

nearest.t=9999

nearest.n=null

for(io=0;io

sinfor=sphere_hit(obj[io][0][0],obj[io][0][1],obj[io][0][2],obj[io][1],e[0],e[1],e[2],s[0],s[1],s[2])

if(sinfor!=null)if(sinfor.t

}

if(nearest.t==9999) {

/* the farthest locatial ,this value mean the ratio between screen-e and object position

not hit all object,we have to test y=0 plate ,otherwise fill backgroundcolor

*/

if(s[1]!=e[1] && (pt= (-e[1]/(s[1]-e[1])) ) >0 ) {return null;} //nothing having been hited,meanwhile,out of the y=0 plate boundary

else //y=0 plate had been hited,calculate corresponding coordinates

{

return new Array(e[0]+pt*(s[0]-e[0]),0,e[2]+pt*(s[2]-e[2]))

}}

else return nearest;

}

for(i=0;i<=1;i+=.001)

for(j=-.5;j<=.5;j+=.001)

{

s=[dem[1]*j,-dem[0]*i,screenZ]

point=detection(e,s)

if(point==null) {C.fillStyle="rgb(0,128,255)";}

else{

if(point[2]!=null){ //is plate

aaa=Math.floor(Math.sin(point[0]*6.28/100)+1 )

bbb=Math.floor(Math.sin(point[2]*6.28/100)+1 )

if(aaa==bbb)

C.fillStyle="rgb(0,0,0)";

else

C.fillStyle="rgb(255,255,255)";

}else{//is object

rgb=obj[point.n][2]

//phong color model

p0=obj[point.n][0]

p1=[e[0]+point.t*(s[0]-e[0]),e[1]+point.t*(s[1]-e[1]),e[2]+point.t*(s[2]-e[2])]

nvec=unitization([p1[0]-p0[0],p1[1]-p0[1],p1[2]-p0[2]])

co=nvec[0]*directal_light[0]+nvec[1]*directal_light[1]+nvec[2]*directal_light[2]

co=Math.pow(co,31)

//sur_col=[Math.round(co*rgb[0]),Math.round(co*rgb[1]),Math.round(co*rgb[2])]

sur_col=[Math.min(255,Math.round((1-envir_col[0])*co*rgb[0])+envir_col[0]*rgb[0]),

Math.min(255,Math.round((1-envir_col[1])*co*rgb[1])+envir_col[1]*rgb[1]),

Math.min(255,Math.round((1-envir_col[2])*co*rgb[2])+envir_col[2]*rgb[2])]

C.fillStyle="rgb("+sur_col[0]+","+sur_col[1]+","+sur_col[2]+")";

}

}

C.fillRect(s[0]+dem[1]/2,-s[1],1,1);

}

转载请署名,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值