ð#Syntax10.Scn.Fntû/û/MODULE RayTrace; (* Berechnung eines True-Color-Raytrace-Bildes *) (* Klaus Mittmannsgruber 9155126 *) (* System: Oberon-2 *) IMPORT MathL,MoreMathL,Display,Input,Oberon,Viewers,Pictures; CONST maxRed=1.0; maxGreen=1.0; maxBlue=1.0; epsilon=1.0E-3; COLOR*=0; TEXTURE*=1; TYPE Color*=RECORD r*,g*,b*:LONGREAL; END; Vector*=RECORD x*,y*,z*:LONGREAL; END; Texture=RECORD pict*:Pictures.Picture; skale*:LONGREAL; END; Surface*=POINTER TO SurfaceDesc; SurfaceDesc*=RECORD material*,mirror*,trans*,difConst*, specConst*,highConst*,velocity*:LONGREAL; colorType*:INTEGER; color*:Color; texture*:Texture; END; Object*=POINTER TO ObjectDesc; ObjectDesc*=RECORD surface*:Surface; next*:Object; END; Lamp*=POINTER TO LampDesc; LampDesc*=RECORD vector*:Vector; color*:Color; intens*:LONGREAL; next*:Lamp; END; World*=POINTER TO WorldDesc; WorldDesc*=RECORD lamp*:Lamp; object*:Object; observer*:Vector; lookAt*:Vector; viewUp*:Vector; eye*:LONGREAL; background*,ambient*:Color; pWidth*,pHeight*:INTEGER; showFastPixel*:INTEGER; calcInTask*:BOOLEAN; END; Task=POINTER TO TaskDesc; TaskDesc=RECORD(Oberon.TaskDesc) world:World; scrnx,scrny,firstray:Vector; x,y:INTEGER; pict:Pictures.Picture; circleTime:LONGINT; runs:INTEGER; END; VAR black-:Color; PROCEDURE Min(a,b:LONGREAL):LONGREAL; BEGIN IF(ab)THEN RETURN(a) ELSE RETURN(b); END; END Max; PROCEDURE Pow(w,ex:LONGREAL):LONGREAL; CONST maxExp=87; VAR temp:LONGREAL; BEGIN IF(wmaxExp)THEN temp:=maxExp; END; RETURN(MathL.exp(temp)); END; END Pow; PROCEDURE VectDot*(a,b:Vector):LONGREAL; BEGIN RETURN(a.x*b.x+a.y*b.y+a.z*b.z); END VectDot; PROCEDURE VectMul*(a:Vector; t:LONGREAL; VAR res:Vector); BEGIN res.x:=a.x*t; res.y:=a.y*t; res.z:=a.z*t; END VectMul; PROCEDURE VectProd*(a,b:Vector; VAR res:Vector); BEGIN res.x:=a.y*b.z-a.z*b.y; res.y:=a.z*b.x-a.x*b.z; res.z:=a.x*b.y-a.y*b.x; END VectProd; PROCEDURE VectAdd*(a,b:Vector; VAR res:Vector); BEGIN res.x:=a.x+b.x; res.y:=a.y+b.y; res.z:=a.z+b.z; END VectAdd; PROCEDURE VectSub*(a,b:Vector; VAR res:Vector); BEGIN res.x:=a.x-b.x; res.y:=a.y-b.y; res.z:=a.z-b.z; END VectSub; PROCEDURE VectDist*(a,b:Vector):LONGREAL; VAR v:Vector; BEGIN VectSub(a,b,v); RETURN(MathL.sqrt(VectDot(v,v))); END VectDist; PROCEDURE VectNorm*(v:Vector; VAR n:Vector); BEGIN VectMul(v,1/MathL.sqrt(VectDot(v,v)),n); END VectNorm; PROCEDURE(object:Object)Intersection*(point,dir:Vector; VAR hitPoint,normal:Vector):BOOLEAN; BEGIN HALT(99) END Intersection; PROCEDURE(object:Object)TexturePoint*(hitPoint:Vector;VAR x,y:LONGREAL); BEGIN HALT(99) END TexturePoint; PROCEDURE LineTrace(VAR point,dir:Vector; world:World; VAR hitPoint,normal:Vector; VAR ret:Object); VAR obj:Object; first:BOOLEAN; r,n:Vector; BEGIN obj:=world.object; first:=TRUE; ret:=NIL; WHILE(obj#NIL)DO IF(obj.Intersection(point,dir,r,n))THEN IF(first)THEN ret:=obj; hitPoint:=r; normal:=n; first:=FALSE; ELSIF(VectDist(r,point)0)THEN VectSub(L,dir,V); VectMul(V,0.5,V); VectNorm(V,V); licht:=licht+object.surface.specConst* Pow(VectDot(V,normal),object.surface.highConst); ELSE licht:=0; END; IntensCol(col,licht,lamp.color); IF(licht>0)THEN IntensCol(col,MathL.exp(log/ lamp.intens*VectDist(hitPoint,lamp.vector)),col); END; AddColor(localCol,localCol,col); END; lamp:=lamp.next; END; AddColor(localCol,localCol,world.ambient); END LocalColor; PROCEDURE SurfaceColor(object:Object; hitPoint:Vector; VAR color:Color); VAR px,py:LONGREAL; x,y,red,green,blue:INTEGER; pict:Pictures.Picture; skale:LONGREAL; BEGIN IF(object.surface.colorType=TEXTURE)THEN pict:=object.surface.texture.pict; skale:=object.surface.texture.skale; object.TexturePoint(hitPoint,px,py); x:=SHORT(ENTIER(px/skale))MOD pict.width; y:=SHORT(ENTIER(py/skale))MOD pict.height; pict.GetPixelRGB(x,y,red,green,blue); color.r:=(red/255)*color.r; color.g:=(green/255)*color.g; color.b:=(blue/255)*color.b; ELSE color.r:=object.surface.color.r*color.r; color.g:=object.surface.color.g*color.g; color.b:=object.surface.color.b*color.b; END; END SurfaceColor; PROCEDURE Raytrace(point,dir:Vector; depth:INTEGER; world:World; VAR color:Color); CONST maxdepth=10; VAR localCol,refCol,transCol:Color; refDir,transDir,hitPoint,normal:Vector; object:Object; BEGIN LineTrace(point,dir,world,hitPoint,normal,object); IF(object=NIL)THEN color:=world.background; ELSE LocalColor(object,dir,normal,hitPoint,world,localCol); IF(depth=maxdepth)THEN refCol:=black; transCol:=black; ELSE IF(object.surface.mirror>0)THEN RefVector(normal,dir,refDir); Raytrace(hitPoint,refDir,depth+1,world,refCol); ELSE refCol:=black; END; IF(object.surface.trans>0)THEN TransVector(object,normal,dir,transDir); Raytrace(hitPoint,transDir,depth+1,world,transCol); ELSE transCol:=black; END; END; Combine(color,localCol,object.surface.material, refCol,object.surface.mirror, transCol,object.surface.trans); SurfaceColor(object,hitPoint,color); END; END Raytrace; PROCEDURE TransColor(color:Color;VAR red,green,blue:INTEGER); BEGIN IF((color.r<0)OR(color.b<0)OR(color.g<0))THEN color.r:=0; color.b:=0; color.g:=0; ELSE IF(color.r>1.0)THEN color.r:=1.0; END; IF(color.g>1.0)THEN color.g:=1.0; END; IF(color.b>1.0)THEN color.b:=1.0; END; red:=SHORT(ENTIER(color.r*255)); green:=SHORT(ENTIER(color.g*255)); blue:=SHORT(ENTIER(color.b*255)); END; END TransColor; PROCEDURE Viewing(world:World; VAR scrnx,scrny,firstray:Vector); VAR magnitude:LONGREAL; BEGIN VectSub(world.lookAt,world.observer,firstray); VectNorm(firstray,firstray); VectNorm(world.viewUp,world.viewUp); VectProd(firstray,world.viewUp,scrnx); VectProd(scrnx,firstray,scrny); magnitude:=SHORT(MoreMathL.tan(world.eye*MathL.pi/360))/world.pWidth*2; VectMul(scrnx,magnitude,scrnx); magnitude:=SHORT(MoreMathL.tan(world.eye*MathL.pi/360))/world.pHeight*2; VectMul(scrny,magnitude,scrny); END Viewing; PROCEDURE ^TaskProc; PROCEDURE CalcWorld*(world:World; pict:Pictures.Picture); VAR x,y,dx,dy:INTEGER; ch:CHAR; color:Color; red,green,blue,i:INTEGER; ray,scrnx,scrny,firstray:Vector; task:Task; BEGIN pict.SetColorRGB(0,0,0); pict.ReplConst(0,0,pict.width,pict.height,Display.replace); pict.Update(0,0,pict.width,pict.height); IF(world.showFastPixel>world.pWidth DIV 10)THEN world.showFastPixel:=world.pWidth DIV 10 END; IF(world.showFastPixel>world.pHeight DIV 10)THEN world.showFastPixel:=world.pHeight DIV 10 END; IF(world.showFastPixel<=0)THEN world.showFastPixel:=1 END; IF(world.calcInTask)THEN NEW(task); task.safe:=FALSE; task.handle:=TaskProc; task.time:=0; task.runs:=1; task.world:=world; task.x:=0; task.y:=0; task.pict:=pict; Viewing(task.world,task.scrnx,task.scrny,task.firstray); Oberon.Install(task); ELSE Viewing(world,scrnx,scrny,firstray); y:=0; WHILE((y1)THEN y:=0; WHILE((y=world.pHeight DIV world.showFastPixel*world.showFastPixel)OR (x>=world.pWidth DIV world.showFastPixel*world.showFastPixel))THEN dx:=x-world.pWidth DIV 2; ray.x:=firstray.x+dx*scrnx.x+dy*scrny.x; ray.y:=firstray.y+dx*scrnx.y+dy*scrny.y; ray.z:=firstray.z+dx*scrnx.z+dy*scrny.z; Raytrace(world.observer,ray,0,world,color); TransColor(color,red,green,blue); pict.SetColorRGB(red,green,blue); pict.ReplConst(x,y,1,1,Display.replace); END; INC(x); END; pict.Update(0,y,world.pWidth,1); INC(y); END; END; WHILE(Input.Available()#0)DO Input.Read(ch); END; END; END CalcWorld; PROCEDURE TaskProc; VAR dx,dy:INTEGER; color:Color; red,green,blue,i:INTEGER; ray:Vector; task:Oberon.Task; BEGIN task:=Oberon.CurTask; WITH task:Task DO IF(Input.Time()-task.circleTime1)THEN DEC(task.runs) END; task.circleTime:=Input.Time(); FOR i:=1 TO task.runs DO dy:=task.y-task.world.pHeight DIV 2; dx:=task.x-task.world.pWidth DIV 2; ray.x:=task.firstray.x+dx*task.scrnx.x+dy*task.scrny.x; ray.y:=task.firstray.y+dx*task.scrnx.y+dy*task.scrny.y; ray.z:=task.firstray.z+dx*task.scrnx.z+dy*task.scrny.z; Raytrace(task.world.observer,ray,0,task.world,color); TransColor(color,red,green,blue); task.pict.SetColorRGB(red,green,blue); task.pict.ReplConst(task.x,task.y,1,1,Display.replace); INC(task.x); IF(task.x=task.world.pWidth)THEN task.pict.Update(0,task.y,task.world.pWidth,1); task.x:=0; INC(task.y); IF(task.y=task.world.pHeight)THEN Oberon.Remove(task) END; END; END; END; END TaskProc; END RayTrace.