2017-03-18 54 views
1

我正在使用GLSL計算着色器編寫基於GPU的實時光線跟蹤渲染器。到目前爲止,它的運作非常好,但當涉及到同時進行反射和折射時,我偶然發現了一個看似無法解決的問題。如果沒有遞歸射線追蹤,反射和折射是不可能的?

我的邏輯告訴我,爲了在玻璃等物體上產生反射和折射,光線必須分成兩部分,一部分光線反射離開表面,另一部分折射穿過表面。這些光線的最終顏色將根據某種功能進行組合,最終用作光線起源像素的顏色。我遇到的問題是我無法在着色器代碼中分割光線,因爲我不得不使用遞歸來實現這一點。根據我的理解,着色器中的函數不能遞歸,因爲所有GLSL函數都像C++中的內聯函數,這是由於舊GPU硬件的兼容性問題。

是否有可能在着色器代碼中模擬或僞遞歸,或者甚至可以在不使用遞歸的情況下同時實現反射和折射?沒有遞歸我看不到它會發生什麼,但我可能是錯的。

+2

我想你正在使用蒙特卡洛技術 - 然後隨機選擇反射或折射。 – Plow

+0

我想你可以嘗試迭代。創建一個光線列表進行處理,並添加到列表中...對於像7條光線這樣的有限遞歸層,您可以將其硬編碼爲靜態數組。另一種選擇是使用幾何着色器,並在那裏發射新的光線,但我不知道這是否可行,因爲我不知道如何傳遞數據的架構。 – Spektre

+0

我使用更新的代碼添加了** [edit1] **。所以概念的證明是有效的。然而,使用32位浮點的第4級遞歸較慢,但仍比CPU光線追蹤器快一個數量級。 – Spektre

回答

1

我設法轉換背光線追蹤到適合GLSL與方法迭代過程中我的意見建議。這是遠遠沒有優化,我沒有實施所有的物理材料(沒有斯內爾的法律等),但作爲一個概念證明它已經工作。我做的所有的東西,在片段着色器和CPU端代碼只發送uniforms常數和現場32位非鉗位浮紋GL_LUMINANCE32F_ARB渲染的形式僅僅是單一的QUAD覆蓋整個屏幕。

  1. 經過現場

    我決定到現場存放在質地因此每個射線/片段有整個場景的直接訪問。紋理是2D但它被用作32位浮點的線性列表。我決定這種格式:

    enum _fac_type_enum 
        { 
        _fac_triangles=0, // r,g,b,a, n, triangle count, { x0,y0,z0,x1,y1,z1,x2,y2,z2 } 
        _fac_spheres,  // r,g,b,a, n, sphere count, { x,y,z,r } 
        }; 
    const GLfloat _n_glass=1.561; 
    const GLfloat _n_vacuum=1.0; 
    GLfloat data[]= 
        { 
    // r, g, b, a,  n,   type,count 
        0.2,0.3,0.5,0.5,_n_glass,_fac_triangles, 4,  // tetrahedron 
    //  px, py, pz, r, g, b 
         -0.5,-0.5,+1.0, 
         0.0,+0.5,+1.0, 
         +0.5,-0.5,+1.0, 
    
         0.0, 0.0,+0.5, 
         -0.5,-0.5,+1.0, 
         0.0,+0.5,+1.0, 
    
         0.0, 0.0,+0.5, 
         0.0,+0.5,+1.0, 
         +0.5,-0.5,+1.0, 
    
         0.0, 0.0,+0.5, 
         +0.5,-0.5,+1.0, 
         -0.5,-0.5,+1.0, 
        }; 
    

    您可以添加/更改任何類型的對象。這個例子只有一個半透明的藍色四面體。您還可以添加變換矩陣更加係數的材料特性等...

  2. 架構

    頂點着色器只是初始化視圖的角光線(起始位置和方向)進行插值所以每個片段代表開始回溯射線追蹤過程。

迭代回來的光線追蹤

因此,我創建射線的「靜態」名單,並開始射線初始化它。在列表中從第一

    1. 遍歷所有光線查找最近的交點與現場...

      店:迭代兩個步驟完成第一次背光線追蹤光線的位置,表面法線和材料特性struct

    2. 如果發現相交而不是最後一個「遞歸」層添加反射/折射光線到最後列出。

      也是他們的索引存儲到處理射線struct

    現在你應該光線抱着你需要重建顏色全部交叉信息。爲了做到這一點:對於每個匹配的實際遞歸層的光線的

    1. 遍歷所有遞歸水平向後
    2. 計算射線顏色

      所以使用光照方程你要。如果光線包含兒童根據材料特性(反射和折射係數...)

    現在的第一縷應該包含您要輸出的顏色的顏色添加到結果。

    制服使用:


    tm_eye視攝像機矩陣
    aspect視圖YS/XS長寬比
    n0空的空間折射率(未使用還)
    focal_length相機焦距的
    fac_siz分辨率場景廣場紋理
    fac_num實際上花車的數量SED的場景貼圖
    fac_txr紋理單元的場景貼圖

    前瞻:

    preview

    片段着色器包含我的調試輸出,所以你還需要紋理如果使用看QA :

    TODO:


    添加基質的對象,相機等
    附加材料性能(光澤,反射/折射係數)
    Snell定律現在的新光線的方向是錯誤的。 ..
    可以是單獨的R,G,B至3倍開始的光線,並在端
    SSS表面散射結合基於光線長度
    更好地貫徹落實燈(現在他們是在一個代碼常量)
    實現更多的原語(現在只有三角形支持)

    [EDIT1]代碼調試和升級

    我刪除舊的源代碼以適應30KB的限制。如果你需要它,然後從編輯歷史中挖掘它。有一段時間,更高級的調試,這和這裏的結果:

    preview

    這個版本得到了解決了一些幾何,準確,域名的問題和錯誤。我得到了實現兩者的反射和折射如圖所示在這個調試平局測試線:

    debug view

    在調試視圖只有立方體是透明的,最後一絲不打什麼被忽略。所以,你可以看到光線分裂...由於全反射角度,光線在立方體內部結束。爲了速度的原因,我禁用了物體內部的所有反射。

    用於交叉點檢測的32位floats與距離有點嘈雜,因此您可以使用64位doubles來代替,但在這種情況下速度會明顯下降。另一種選擇是重寫方程以使用在這種情況下更精確的相對座標。

    這裏float着色器源:

    頂點:

    //------------------------------------------------------------------ 
    #version 420 core 
    //------------------------------------------------------------------ 
    uniform float aspect; 
    uniform float focal_length; 
    uniform mat4x4 tm_eye; 
    layout(location=0) in vec2 pos; 
    
    out smooth vec2 txt_pos; // frag position on screen <-1,+1> for debug prints 
    out smooth vec3 ray_pos; // ray start position 
    out smooth vec3 ray_dir; // ray start direction 
    //------------------------------------------------------------------ 
    void main(void) 
        { 
        vec4 p; 
        txt_pos=pos; 
        // perspective projection 
        p=tm_eye*vec4(pos.x/aspect,pos.y,0.0,1.0); 
        ray_pos=p.xyz; 
        p-=tm_eye*vec4(0.0,0.0,-focal_length,1.0); 
        ray_dir=normalize(p.xyz); 
    
        gl_Position=vec4(pos,0.0,1.0); 
        } 
    //------------------------------------------------------------------ 
    

    片段:

    //------------------------------------------------------------------ 
    #version 420 core 
    //------------------------------------------------------------------ 
    // Ray tracer ver: 1.000 
    //------------------------------------------------------------------ 
    in smooth vec3  ray_pos; // ray start position 
    in smooth vec3  ray_dir; // ray start direction 
    uniform float  n0;   // refractive index of camera origin 
    uniform int   fac_siz; // square texture x,y resolution size 
    uniform int   fac_num; // number of valid floats in texture 
    uniform sampler2D fac_txr; // scene mesh data texture 
    out layout(location=0) vec4 frag_col; 
    //--------------------------------------------------------------------------- 
    //#define _debug_print 
    #define _reflect 
    #define _refract 
    //--------------------------------------------------------------------------- 
    #ifdef _debug_print 
    in vec2 txt_pos;    // frag screen position <-1,+1> 
    uniform sampler2D txr_font;  // ASCII 32x8 characters font texture unit 
    uniform float txt_fxs,txt_fys; // font/screen resolution ratio 
    const int _txtsiz=64;   // text buffer size 
    int txt[_txtsiz],txtsiz;  // text buffer and its actual size 
    vec4 txt_col=vec4(0.0,0.0,0.0,1.0); // color interface for txt_print() 
    bool _txt_col=false;   // is txt_col active? 
    void txt_decimal(vec2 v);  // print vec3 into txt 
    void txt_decimal(vec3 v);  // print vec3 into txt 
    void txt_decimal(vec4 v);  // print vec3 into txt 
    void txt_decimal(float x);  // print float x into txt 
    void txt_decimal(int x);  // print int x into txt 
    void txt_print(float x0,float y0); // print txt at x0,y0 [chars] 
    #endif 
    //--------------------------------------------------------------------------- 
    void main(void) 
        { 
        const vec3 light_dir=normalize(vec3(0.1,0.1,1.0)); 
        const float light_iamb=0.1;     // dot offset 
        const float light_idir=0.5;     // directional light amplitude 
        const vec3 back_col=vec3(0.2,0.2,0.2);  // background color 
    
        const float _zero=1e-6;  // to avoid intrsection with start point of ray 
        const int _fac_triangles=0; // r,g,b, refl,refr,n, type, triangle count, { x0,y0,z0,x1,y1,z1,x2,y2,z2 } 
        const int _fac_spheres =1; // r,g,b, refl,refr,n, type, sphere count, { x,y,z,r } 
        // ray scene intersection 
        struct _ray 
         { 
         vec3 pos,dir,nor; 
         vec3 col; 
         float refl,refr;// reflection,refraction intensity coeficients 
         float n0,n1,l; // refaction index (start,end) , ray length 
         int lvl,i0,i1; // recursion level, reflect, refract 
         }; 
        const int _lvls=5; 
        const int _rays=(1<<_lvls)-1; 
        _ray ray[_rays]; int rays; 
    
        vec3 v0,v1,v2,pos; 
        vec3 c,col; 
        float refr,refl; 
        float tt,t,n1,a; 
        int i0,ii,num,id; 
    
        // fac texture access 
        vec2 st; int i,j; float ds=1.0/float(fac_siz-1); 
        #define fac_get texture(fac_txr,st).r; st.s+=ds; i++; j++; if (j==fac_siz) { j=0; st.s=0.0; st.t+=ds; } 
        // enque start ray 
        ray[0].pos=ray_pos; 
        ray[0].dir=normalize(ray_dir); 
        ray[0].nor=vec3(0.0,0.0,0.0); 
        ray[0].refl=0.0; 
        ray[0].refr=0.0; 
        ray[0].n0=n0; 
        ray[0].n1=1.0; 
        ray[0].l =0.0; 
        ray[0].lvl=0; 
        ray[0].i0=-1; 
        ray[0].i1=-1; 
        rays=1; 
    
        // debug print area 
        #ifdef _debug_print 
        bool _dbg=false; 
        float dbg_x0=45.0; 
        float dbg_y0= 1.0; 
        float dbg_xs=12.0; 
        float dbg_ys=_rays+1.0; 
    
        dbg_xs=40.0; 
        dbg_ys=10; 
    
        float x=0.5*(1.0+txt_pos.x)/txt_fxs; x-=dbg_x0; 
        float y=0.5*(1.0-txt_pos.y)/txt_fys; y-=dbg_y0; 
        // inside bbox? 
        if ((x>=0.0)&&(x<=dbg_xs) 
         &&(y>=0.0)&&(y<=dbg_ys)) 
         { 
         // prints on 
         _dbg=true; 
         // preset debug ray 
         ray[0].pos=vec3(0.0,0.0,0.0)*2.5; 
         ray[0].dir=vec3(0.0,0.0,1.0); 
         } 
        #endif 
    
        // loop all enqued rays 
        for (i0=0;i0<rays;i0++) 
         { 
         // loop through all objects 
         // find closest forward intersection between them and ray[i0] 
         // strore it to ray[i0].(nor,col) 
         // strore it to pos,n1 
         t=tt=-1.0; ii=1; ray[i0].l=0.0; 
         ray[i0].col=back_col; 
         pos=ray[i0].pos; n1=n0; 
         for (st=vec2(0.0,0.0),i=j=0;i<fac_num;) 
          { 
          c.r=fac_get;   // RGBA 
          c.g=fac_get; 
          c.b=fac_get; 
          refl=fac_get; 
          refr=fac_get; 
          n1=fac_get;    // refraction index 
          a=fac_get; id=int(a); // object type 
          a=fac_get; num=int(a); // face count 
    
          if (id==_fac_triangles) 
          for (;num>0;num--) 
           { 
           v0.x=fac_get; v0.y=fac_get; v0.z=fac_get; 
           v1.x=fac_get; v1.y=fac_get; v1.z=fac_get; 
           v2.x=fac_get; v2.y=fac_get; v2.z=fac_get; 
           vec3 e1,e2,n,p,q,r; 
           float t,u,v,det,idet; 
           //compute ray triangle intersection 
           e1=v1-v0; 
           e2=v2-v0; 
           // Calculate planes normal vector 
           p=cross(ray[i0].dir,e2); 
           det=dot(e1,p); 
           // Ray is parallel to plane 
           if (abs(det)<1e-8) continue; 
           idet=1.0/det; 
           r=ray[i0].pos-v0; 
           u=dot(r,p)*idet; 
           if ((u<0.0)||(u>1.0)) continue; 
           q=cross(r,e1); 
           v=dot(ray[i0].dir,q)*idet; 
           if ((v<0.0)||(u+v>1.0)) continue; 
           t=dot(e2,q)*idet; 
           if ((t>_zero)&&((t<=tt)||(ii!=0))) 
            { 
            ii=0; tt=t; 
            // store color,n ... 
            ray[i0].col=c; 
            ray[i0].refl=refl; 
            ray[i0].refr=refr; 
            // barycentric interpolate position 
            t=1.0-u-v; 
            pos=(v0*t)+(v1*u)+(v2*v); 
            // compute normal (store as dir for now) 
            e1=v1-v0; 
            e2=v2-v1; 
            ray[i0].nor=cross(e1,e2); 
            } 
           } 
    
          if (id==_fac_spheres) 
          for (;num>0;num--) 
           { 
           float r; 
           v0.x=fac_get; v0.y=fac_get; v0.z=fac_get; r=fac_get; 
           // compute l0 length of ray(p0,dp) to intersection with sphere(v0,r) 
           // where rr= r^-2 
           float aa,bb,cc,dd,l0,l1,rr; 
           vec3 p0,dp; 
           p0=ray[i0].pos-v0; // set sphere center to (0,0,0) 
           dp=ray[i0].dir; 
           rr = 1.0/(r*r); 
           aa=2.0*rr*dot(dp,dp); 
           bb=2.0*rr*dot(p0,dp); 
           cc= rr*dot(p0,p0)-1.0; 
           dd=((bb*bb)-(2.0*aa*cc)); 
           if (dd<0.0) continue; 
           dd=sqrt(dd); 
           l0=(-bb+dd)/aa; 
           l1=(-bb-dd)/aa; 
           if (l0<0.0) l0=l1; 
           if (l1<0.0) l1=l0; 
           t=min(l0,l1); if (t<=_zero) t=max(l0,l1); 
           if ((t>_zero)&&((t<=tt)||(ii!=0))) 
            { 
            ii=0; tt=t; 
            // store color,n ... 
            ray[i0].col=c; 
            ray[i0].refl=refl; 
            ray[i0].refr=refr; 
            // position,normal 
            pos=ray[i0].pos+(ray[i0].dir*t); 
            ray[i0].nor=pos-v0; 
            } 
           } 
          } 
         ray[i0].l=tt; 
         ray[i0].nor=normalize(ray[i0].nor); 
         // split ray from pos and ray[i0].nor 
         if ((ii==0)&&(ray[i0].lvl<_lvls-1)) 
          { 
          t=dot(ray[i0].dir,ray[i0].nor); 
    
          // reflect 
          #ifdef _reflect 
          if ((ray[i0].refl>_zero)&&(t<_zero)) // do not reflect inside objects 
           { 
           ray[i0].i0=rays; 
           ray[rays]=ray[i0]; 
           ray[rays].lvl++; 
           ray[rays].i0=-1; 
           ray[rays].i1=-1; 
           ray[rays].pos=pos; 
           ray[rays].dir=ray[rays].dir-(2.0*t*ray[rays].nor); 
           ray[rays].n0=ray[i0].n0; 
           ray[rays].n1=ray[i0].n0; 
           rays++; 
           } 
          #endif 
    
          // refract 
          #ifdef _refract 
          if (ray[i0].refr>_zero) 
           { 
           ray[i0].i1=rays; 
           ray[rays]=ray[i0]; 
           ray[rays].lvl++; 
           ray[rays].i0=-1; 
           ray[rays].i1=-1; 
           ray[rays].pos=pos; 
    
           t=dot(ray[i0].dir,ray[i0].nor); 
           if (t>0.0) // exit object 
            { 
            ray[rays].n0=ray[i0].n0; 
            ray[rays].n1=n0; 
            v0=-ray[i0].nor; t=-t; 
            } 
           else{  // enter object 
            ray[rays].n0=n1; 
            ray[rays].n1=ray[i0].n0; 
            ray[i0 ].n1=n1; 
            v0=ray[i0].nor; 
            } 
           n1=ray[i0].n0/ray[i0].n1; 
           tt=1.0-(n1*n1*(1.0-t*t)); 
           if (tt>=0.0) 
            { 
            ray[rays].dir=(ray[i0].dir*n1)-(v0*((n1*t)+sqrt(tt))); 
            rays++; 
            } 
           } 
          #endif 
          } 
         else if (i0>0) // ignore last ray if nothing hit 
          { 
          ray[i0]=ray[rays-1]; 
          rays--; i0--; 
          } 
         } 
        // back track ray intersections and compute output color col 
        // lvl is sorted ascending so backtrack from end 
        for (i0=rays-1;i0>=0;i0--) 
         { 
         // directional + ambient light 
         t=abs(dot(ray[i0].nor,light_dir)*light_idir)+light_iamb; 
         t*=1.0-ray[i0].refl-ray[i0].refr; 
         ray[i0].col.rgb*=t; 
         // reflect 
         ii=ray[i0].i0; 
         if (ii>=0) ray[i0].col.rgb+=ray[ii].col.rgb*ray[i0].refl; 
         // refract 
         ii=ray[i0].i1; 
         if (ii>=0) ray[i0].col.rgb+=ray[ii].col.rgb*ray[i0].refr; 
         } 
    
        col=ray[0].col; 
    
        // debug prints 
        #ifdef _debug_print 
    /* 
        if (_dbg) 
         { 
         txtsiz=0; 
         txt_decimal(_lvls); 
         txt[txtsiz]=' '; txtsiz++; 
         txt_decimal(rays); 
         txt[txtsiz]=' '; txtsiz++; 
         txt_decimal(_rays); 
         txt_print(dbg_x0,dbg_y0); 
    
         for (ii=0;ii<rays;ii++) 
          { 
          txtsiz=0; 
          txt_decimal(ray[ii].lvl); 
          txt_print(dbg_x0,dbg_y0+ii+1); 
          } 
    
         for (ii=0,st=vec2(0.0,0.0),i=j=0;i<fac_num;ii++) 
          { 
          c.r=fac_get;   // RGBA 
          txtsiz=0; 
          txt_decimal(c.r); 
          txt_print(dbg_x0,dbg_y0+ii+1); 
          } 
         if (_txt_col) col=txt_col.rgb; 
         } 
    */ 
        if (_dbg) 
         { 
         float x=dbg_x0,y=dbg_y0; 
         vec3 a=vec3(1.0,2.0,3.0); 
         vec3 b=vec3(5.0,6.0,7.0); 
         txtsiz=0; txt_decimal(dot(a,b)); txt_print(x,y); y++; 
         txtsiz=0; txt_decimal(cross(a,b)); txt_print(x,y); y++; 
         if (_txt_col) col=txt_col.rgb; 
         } 
        #endif 
    
        frag_col=vec4(col,1.0); 
        } 
    //--------------------------------------------------------------------------- 
    #ifdef _debug_print 
    //--------------------------------------------------------------------------- 
    void txt_decimal(vec2 v)  // print vec2 into txt 
        { 
             txt[txtsiz]='('; txtsiz++; 
        txt_decimal(v.x); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.y); txt[txtsiz]=')'; txtsiz++; 
        txt[txtsiz]=0; // string terminator 
        } 
    //--------------------------------------------------------------------------- 
    void txt_decimal(vec3 v)  // print vec3 into txt 
        { 
             txt[txtsiz]='('; txtsiz++; 
        txt_decimal(v.x); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.y); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.z); txt[txtsiz]=')'; txtsiz++; 
        txt[txtsiz]=0; // string terminator 
        } 
    //--------------------------------------------------------------------------- 
    void txt_decimal(vec4 v)  // print vec4 into txt 
        { 
             txt[txtsiz]='('; txtsiz++; 
        txt_decimal(v.x); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.y); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.z); txt[txtsiz]=','; txtsiz++; 
        txt_decimal(v.w); txt[txtsiz]=')'; txtsiz++; 
        txt[txtsiz]=0; // string terminator 
        } 
    //--------------------------------------------------------------------------- 
    void txt_decimal(float x)  // print float x into txt 
        { 
        int i,j,c;     // l is size of string 
        float y,a; 
        const float base=10; 
        // handle sign 
        if (x<0.0) { txt[txtsiz]='-'; txtsiz++; x=-x; } 
        else  { txt[txtsiz]='+'; txtsiz++; } 
        // divide to int(x).fract(y) parts of number 
        y=x; x=floor(x); y-=x; 
        // handle integer part 
        i=txtsiz;     // start of integer part 
        for (;txtsiz<_txtsiz;) 
         { 
         a=x; 
         x=floor(x/base); 
         a-=base*x; 
         txt[txtsiz]=int(a)+'0'; txtsiz++; 
         if (x<=0.0) break; 
         } 
        j=txtsiz-1;     // end of integer part 
        for (;i<j;i++,j--)   // reverse integer digits 
         { 
         c=txt[i]; txt[i]=txt[j]; txt[j]=c; 
         } 
        // handle fractional part 
        for (txt[txtsiz]='.',txtsiz++;txtsiz<_txtsiz;) 
         { 
         y*=base; 
         a=floor(y); 
         y-=a; 
         txt[txtsiz]=int(a)+'0'; txtsiz++; 
         if (y<=0.0) break; 
         } 
        txt[txtsiz]=0; // string terminator 
        } 
    //--------------------------------------------------------------------------- 
    void txt_decimal(int x)  // print int x into txt 
        { 
        int a,i,j,c;   // l is size of string 
        const int base=10; 
        // handle sign 
        if (x<0.0) { txt[txtsiz]='-'; txtsiz++; x=-x; } 
        else  { txt[txtsiz]='+'; txtsiz++; } 
        // handle integer part 
        i=txtsiz;    // start of integer part 
        for (;txtsiz<_txtsiz;) 
         { 
         a=x; 
         x/=base; 
         a-=base*x; 
         txt[txtsiz]=int(a)+'0'; txtsiz++; 
         if (x<=0) break; 
         } 
        j=txtsiz-1;    // end of integer part 
        for (;i<j;i++,j--)  // reverse integer digits 
         { 
         c=txt[i]; txt[i]=txt[j]; txt[j]=c; 
         } 
        txt[txtsiz]=0; // string terminator 
        } 
    //--------------------------------------------------------------------------- 
    void txt_print(float x0,float y0) // print txt at x0,y0 [chars] 
        { 
        int i; 
        float x,y; 
        // fragment position [chars] relative to x0,y0 
        x=0.5*(1.0+txt_pos.x)/txt_fxs; x-=x0; 
        y=0.5*(1.0-txt_pos.y)/txt_fys; y-=y0; 
        // inside bbox? 
        if ((x<0.0)||(x>float(txtsiz))||(y<0.0)||(y>1.0)) return; 
        // get font texture position for target ASCII 
        i=int(x);    // char index in txt 
        x-=float(i); 
        i=txt[i]; 
        x+=float(int(i&31)); 
        y+=float(int(i>>5)); 
        x/=32.0; y/=8.0; // offset in char texture 
        txt_col=texture(txr_font,vec2(x,y)); 
        _txt_col=true; 
        } 
    //--------------------------------------------------------------------------- 
    #endif 
    //--------------------------------------------------------------------------- 
    

    的代碼還沒有優化我想有正常工作的物理第一。仍然沒有實施Fresnells,但使用refl,refr材料系數。你

    也可以忽略調試打印的東西(它們被#define封裝)。

    我建立一個小型的類幾何紋理,所以我可以輕鬆設置場景中的對象。這是一幕是如何發起的預覽:

    ray.beg(); 
    //     r g b rfl rfr n 
    ray.add_material(1.0,1.0,1.0,0.3,0.0,_n_glass); ray.add_box (0.0, 0.0, 6.0,9.0,9.0,0.1); 
    ray.add_material(1.0,1.0,1.0,0.1,0.8,_n_glass); ray.add_sphere(0.0, 0.0, 0.5,0.5); 
    ray.add_material(1.0,0.1,0.1,0.3,0.0,_n_glass); ray.add_sphere(+2.0, 0.0, 2.0,0.5); 
    ray.add_material(0.1,1.0,0.1,0.3,0.0,_n_glass); ray.add_box (-2.0, 0.0, 2.0,0.5,0.5,0.5); 
    ray.add_material(0.1,0.1,1.0,0.3,0.0,_n_glass); 
    ray.add_tetrahedron 
        (
        0.0, 0.0, 3.0, 
        -1.0,-1.0, 4.0, 
        +1.0,-1.0, 4.0, 
        0.0,+1.0, 4.0 
        ); 
    ray.end(); 
    

    非常重要,這樣計算法線面臨淘汰的對象,因爲這是用於檢測內部/外部對象口岸。