Un petit RayTracing

Partagez votre expérience de PureBasic avec les autres utilisateurs.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Un petit RayTracing

Message par comtois »

Code : Tout sélectionner

;Traduction de ce code
;https://www.scratchapixel.com/code.php?id=3&origin=/lessons/3d-basic-rendering/introduction-To-ray-tracing

#INFINITY = 1e8
#MAX_RAY_DEPTH = 5 

Structure vector3
  x.f
  y.f
  z.f
EndStructure

Structure sphere
  center.vector3 
  radius.f 
  radius2.f
  surfaceColor.vector3 
  reflection.f 
  transparency.f
  emissionColor.vector3
EndStructure

Macro AddSphere(n,cx,cy,cz,r,sx,sy,sz,f,t,ex,ey,ez)
  spheres(n)\center\x = cx 
  spheres(n)\center\y = cy
  spheres(n)\center\z = cz
  spheres(n)\radius =  r
  spheres(n)\radius2 = spheres(n)\radius*spheres(n)\radius
  spheres(n)\surfaceColor\x = sx
  spheres(n)\surfaceColor\y = sy
  spheres(n)\surfaceColor\z = sz
  spheres(n)\reflection = f
  spheres(n)\transparency = t
  spheres(n)\emissionColor\x = ex
  spheres(n)\emissionColor\y = ey
  spheres(n)\emissionColor\z = ez
EndMacro

Procedure.f length2(*v.vector3) 
  ProcedureReturn *v\x * *v\x + *v\y * *v\y + *v\z * *v\z
EndProcedure

Procedure length(*v.vector3)
  ProcedureReturn Sqr(length2(*v))
EndProcedure  

Procedure normalize(*v.vector3) 
  nor2.f = length2(*v) 
  If (nor2 > 0)  
    invNor.f = 1.0 / Sqr(nor2) 
    *v\x * invNor
    *v\y * invNor
    *v\z * invNor 
  EndIf 
EndProcedure


Procedure.f min(a.f, b.f)
  If b<a
    ProcedureReturn b
  Else
    ProcedureReturn a
  EndIf
EndProcedure

Procedure.f max(a.f, b.f)
  If b>a
    ProcedureReturn b
  Else
    ProcedureReturn a
  EndIf
EndProcedure

Procedure.f dot(*v1.vector3, *v2.vector3)
  ProcedureReturn *v1\x**v2\x + *v1\y**v2\y + *v1\z**v2\z  
EndProcedure

;Compute a ray-sphere intersection using the geometric solution

Procedure intersect(*s.sphere, *rayorig.vector3, *raydir.vector3, *t0.Float, *t1.Float)  
  l.vector3
  l\x = *s\center\x - *rayorig\x
  l\y = *s\center\y - *rayorig\y
  l\z = *s\center\z - *rayorig\z
  tca.f = dot(@l, *raydir)
  
  If tca < 0 
    ProcedureReturn #False
    Debug "la"
  EndIf  
  d2.f = dot(@l, @l) - tca * tca 
  If d2 > *s\radius2 
    ProcedureReturn #False
  EndIf  
  thc.f = Sqr(*s\radius2 - d2) 
  *t0\f = tca - thc 
  *t1\f = tca + thc
  
  ProcedureReturn #True 
EndProcedure 

;This variable controls the maximum recursion depth



Procedure.f mix(a.f, b.f, mix.f) 
  ProcedureReturn b * mix + a * (1 - mix)
EndProcedure 

;This is the main trace function. It takes a ray As argument (defined by its origin And direction). 
;We test If this ray intersects any of the geometry in the scene. If the ray intersects an object, 
;we compute the intersection point, the normal at the intersection point, And shade this point using this information. 
;Shading depends on the surface property (is it transparent, reflective, diffuse). 
;The function returns a color For the ray. If the ray intersects an object that is the color of the object at the intersection point, 
;otherwise it returns the background color.

Procedure trace(*Result.vector3, *rayorig.vector3, *raydir.vector3, Array spheres.sphere(1), depth) 
  
  ;If (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
  tnear.f = #INFINITY 
  Protected *sphere.sphere 
  ; find intersection of this ray With the sphere in the scene
  For i = 0 To ArraySize(spheres()) 
    t0.f = #INFINITY
    t1.f = #INFINITY
    If intersect(@spheres(i), *rayorig, *raydir, @t0, @t1) 
      If (t0 < 0) 
        t0 = t1
      EndIf  
      If t0 < tnear 
        tnear = t0 
        *sphere = @spheres(i)
      EndIf 
    EndIf 
  Next 
  ; If there's no intersection return black or background color
  If *sphere=0 
    *Result\x = 2
    *Result\y = 2
    *Result\z = 2
    ProcedureReturn
  EndIf  
  surfaceColor.vector3; // color of the ray/surfaceof the object intersected by the ray 
  
  phit.vector3        ; // point of intersection 
  phit\x = *rayorig\x + *raydir\x * tnear
  phit\y = *rayorig\y + *raydir\y * tnear
  phit\z = *rayorig\z + *raydir\z * tnear
  
  nhit.vector3 ; // normal at the intersection point 
  nhit\x = phit\x - *sphere\center\x
  nhit\y = phit\y - *sphere\center\y
  nhit\z = phit\z - *sphere\center\z
  normalize(@nhit); // normalize normal direction 
                  ; If the normal And the view direction are Not opposite To each other
                  ; reverse the normal direction. That also means we are inside the sphere so set
                  ; the inside bool To true. Finally reverse the sign of IdotN which we want
                  ; positive.
  bias.f = 1e-4   ; // add some bias to the point from which we will be tracing 
  
  inside = #False
  If dot(*raydir, @nhit) > 0
    nhit\x = -nhit\x
    nhit\y = -nhit\y
    nhit\z = -nhit\z
    inside = #True
  EndIf  
  
  If (*sphere\transparency > 0 Or *sphere\reflection > 0) And depth < #MAX_RAY_DEPTH  
    facingratio.f = -dot(*raydir,@nhit)
    ; change the mix value To tweak the effect
    fresneleffect.f = mix(Pow(1 - facingratio, 3), 1, 0.1)
    ; compute reflection direction (Not need To normalize because all vectors
    ; are already normalized)
    refldir.vector3
    refldir\x = *raydir\x - nhit\x * 2 * dot(*raydir, @nhit)
    refldir\y = *raydir\y - nhit\y * 2 * dot(*raydir, @nhit)
    refldir\z = *raydir\z - nhit\z * 2 * dot(*raydir, @nhit)
    normalize(@refldir) 
    reflection.vector3 
    prov.vector3
    prov\x = phit\x + nhit\x * bias
    prov\y = phit\y + nhit\y * bias
    prov\z = phit\z + nhit\z * bias
    trace(@reflection, @prov, @refldir, spheres(), depth + 1)
    refraction.vector3
    ; If the sphere is also transparent compute refraction ray (transmission)
    If *sphere\transparency  
      ior.f = 1.1
      If inside; are we inside or outside the surface? 
        eta = ior
      Else  
        eta = 1.0 / ior
      EndIf  
      cosi.f = -dot(@nhit,*raydir)
      k.f = 1 - eta * eta * (1 - cosi * cosi)
      refrdir.vector3 
      refrdir\x = *raydir\x * eta + nhit\x * (eta *  cosi - Sqr(k))
      refrdir\y = *raydir\y * eta + nhit\y * (eta *  cosi - Sqr(k))
      refrdir\z = *raydir\z * eta + nhit\z * (eta *  cosi - Sqr(k))
      normalize(@refrdir) 
      prov\x = phit\x - nhit\x * bias
      prov\y = phit\y - nhit\y * bias
      prov\z = phit\z - nhit\z * bias
      trace(@refraction, prov, refrdir, spheres(), depth + 1)
    EndIf 
    ; the result is a mix of reflection And refraction (If the sphere is transparent)
    surfaceColor\x = ( reflection\x * fresneleffect +   refraction\x * (1 - fresneleffect) * *sphere\transparency) * *sphere\surfaceColor\x 
    surfaceColor\y = ( reflection\y * fresneleffect +   refraction\y * (1 - fresneleffect) * *sphere\transparency) * *sphere\surfaceColor\y 
    surfaceColor\z = ( reflection\z * fresneleffect +   refraction\z * (1 - fresneleffect) * *sphere\transparency) * *sphere\surfaceColor\z 
    
  Else  
    ; it's a diffuse object, no need to raytrace any further
    For i = 0 To ArraySize(spheres()) 
      If (spheres(i)\emissionColor\x > 0)  
        ; this is a light
        transmission.vector3
        transmission\x = 1
        transmission\y = 1
        transmission\z = 1
        
        lightDirection.vector3
        lightDirection\x  = spheres(i)\center\x - phit\x 
        lightDirection\y  = spheres(i)\center\y - phit\y 
        lightDirection\z  = spheres(i)\center\z - phit\z 
        normalize(lightDirection)
        For j = 0 To ArraySize(spheres()) 
          If i <> j  
            t0.f
            t1.f
            prov\x = phit\x + nhit\x * bias
            prov\y = phit\y + nhit\y * bias
            prov\z = phit\z + nhit\z * bias
            If intersect(@spheres(j), @prov, @lightDirection, @t0, @t1)  
              transmission\x = 0
              transmission\y = 0
              transmission\z = 0
              Break 
            EndIf 
          EndIf 
        Next 
        surfaceColor\x + *sphere\surfaceColor\x * transmission\x * max(0, dot(@nhit, @lightDirection)) * spheres(i)\emissionColor\x 
        surfaceColor\y + *sphere\surfaceColor\y * transmission\y * max(0, dot(@nhit, @lightDirection)) * spheres(i)\emissionColor\y 
        surfaceColor\z + *sphere\surfaceColor\z * transmission\z * max(0, dot(@nhit, @lightDirection)) * spheres(i)\emissionColor\z 
      EndIf 
    Next 
  EndIf 
  
  *Result\x =  surfaceColor\x + *sphere\emissionColor\x 
  *Result\y =  surfaceColor\y + *sphere\emissionColor\y 
  *Result\z =  surfaceColor\z + *sphere\emissionColor\z 
EndProcedure 

;Main rendering function. We compute a camera ray For each pixel of the image trace it And Return a color. 
;If the ray hits a sphere, we Return the color of the sphere at the intersection point, Else we Return the background color.

Procedure render(Array spheres.sphere(1)) 
  
  width = 640
  height = 480
  Dim image.vector3(width * height)
  *pixel.vector3 = image() 
  invWidth.f = 1.0 / width
  invHeight.f = 1.0 / height 
  fov.f = 30.0
  aspectratio.f = width / height 
  angle.f = Tan(#PI * 0.5 * fov / 180.0); 
                                        ; Trace rays
  For y = 0 To height-1 
    For x = 0 To width-1 
      *pixel+SizeOf(vector3) 
      xx.f = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio
      yy.f = (1 - 2 * ((y + 0.5) * invHeight)) * angle 
      raydir.vector3
      raydir\x = xx
      raydir\y = yy
      raydir\z = -1
      normalize(@raydir)
      prov.vector3
      prov\x = 0
      prov\y = 0
      prov\z = 0
      trace(*pixel,@prov, @raydir, spheres(), 0)
    Next 
  Next 
  
  StartDrawing(SpriteOutput(0))
  k=0
  For j = 0 To height-1 
    For i=0 To width-1
      Plot(i,j, RGB(min(1, image(k)\x) * 255, min(1, image(k)\y) * 255,min(1, image(k)\z) * 255)) 
      k+1
    Next
  Next      
  StopDrawing()
  
EndProcedure 

;In the main function, we will create the scene which is composed of 5 spheres And 1 light (which is also a sphere). 
;Then, once the scene description is complete we render that scene, by calling the render() function.

Procedure main() 
  
  Dim spheres.sphere(5)
  
  ; position, radius, surface color, reflectivity, transparency, emission color
  AddSphere(0,  0.0, -10004, -20, 10000, 0.20, 0.20, 0.20, 0, 0.0, 0, 0, 0) 
  AddSphere(1,  0.0,      0, -20,     4, 1.00, 0.32, 0.36, 1, 0.5, 0, 0, 0) 
  AddSphere(2,  5.0,     -1, -15,     2, 0.90, 0.76, 0.46, 1, 0.0, 0, 0, 0) 
  AddSphere(3,  5.0,      0, -25,     3, 0.65, 0.77, 0.97, 1, 0.0, 0, 0, 0) 
  AddSphere(4, -5.5,      0, -15,     3, 0.90, 0.90, 0.90, 1, 0.0, 0, 0, 0) 
  
  ; light
  AddSphere(5,  0.0,     20, -30,     3,  0.0, 0.00, 0.00, 0, 0.0, 3, 3, 3)
  
  render(spheres()) 
  
EndProcedure



If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 640, 480, "Gadget and sprites!", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  
  If OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0)
    
    CreateSprite(0,640, 480)
    
    main()
    ReleaseMouse(1)
    Repeat
      Repeat
        ; Always process all the events to flush the queue at every frame
        Event = WindowEvent()
        
        Select Event
          Case #PB_Event_CloseWindow
            Quit = 1
            
            
        EndSelect
        
      Until Event = 0 ; Quit the event loop only when no more events are available
      
      ExamineKeyboard()
            
      ExamineMouse()
      
      ; Clear the screen and draw our sprites
      ClearScreen(RGB(0,0,0))
      
      DisplaySprite(0,0, 0)
      
      FlipBuffers()       ; Inverse the buffers (the back become the front (visible)... and we can do the rendering on the back
      
    Until  Quit Or KeyboardPushed(#PB_Key_Escape)
  Else
    MessageRequester("Error", "Can't open windowed screen!", 0)
  EndIf
EndIf
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Un petit RayTracing

Message par comtois »

Et maintenant qui se lance pour traduire celui-ci en PB ?

Code : Tout sélectionner

#include <stdlib.h>   // card > aek.ppm
#include <stdio.h>
#include <math.h>
typedef int i;typedef float f;struct v{f x,y,z;v operator+(v r){return v(x+r.x,y+r.y,z+r.z);}v operator*(f r){return v(x*r,y*r,z*r);}f operator%(v r){return x*r.x+y*r.y+z*r.z;}v(){}v operator^(v r){return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.y-y*r.x);}v(f a,f b,f c){x=a;y=b;z=c;}v operator!(){return*this*(1/sqrt(*this%*this));}};i G[]={247570,280596,280600,249748,18578,18577,231184,16,16};f R(){return(f)rand()/RAND_MAX;}i T(v o,v d,f&t,v&n){t=1e9;i m=0;f p=-o.z/d.z;if(.01<p)t=p,n=v(0,0,1),m=1;for(i k=19;k--;)for(i j=9;j--;)if(G[j]&1<<k){v p=o+v(-k,0,-j-4);f b=p%d,c=p%p-1,q=b*b-c;if(q>0){f s=-b-sqrt(q);if(s<t&&s>.01)t=s,n=!(p+d*t),m=2;}}return m;}v S(v o,v d){f t;v n;i m=T(o,d,t,n);if(!m)return v(.7,.6,1)*pow(1-d.z,4);v h=o+d*t,l=!(v(9+R(),9+R(),16)+h*-1),r=d+n*(n%d*-2);f b=l%n;if(b<0||T(h,l,t,n))b=0;f p=pow(l%r*(b>0),99);if(m&1){h=h*.2;return((i)(ceil(h.x)+ceil(h.y))&1?v(3,1,1):v(3,3,3))*(b*.2+.1);}return v(p,p,p)+S(h,r)*.5;}i main(){printf("P6 512 512 255 ");v g=!v(-6,-16,0),a=!(v(0,0,1)^g)*.002,b=!(g^a)*.002,c=(a+b)*-256+g;for(i y=512;y--;)for(i x=512;x--;){v p(13,13,13);for(i r=64;r--;){v t=a*(R()-.5)*99+b*(R()-.5)*99;p=S(v(17,16,8)+t,!(t*-1+(a*(R()+x)+b*(y+R())+c)*16))*3.5+p;}printf("%c%c%c",(i)p.x,(i)p.y,(i)p.z);}}
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Un petit RayTracing

Message par djes »

Pour ceux qui sont passés à côté, hades est en train de nous faire un tutorial sur le raytracing http://www.purebasic.fr/english/viewtop ... 36&t=70251
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Un petit RayTracing

Message par falsam »

Joli rendu Comtois. Par contre très très long si vous avez un Intel i3 :wink:
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Un petit RayTracing

Message par Ar-S »

super chouette.
Ajouter DisableDebugger en debut de code pour un rendu casi instantané (i5)
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Un petit RayTracing

Message par comtois »

falsam a écrit :Par contre très très long si vous avez un Intel i3 :wink:
Combien de temps ça met ??

Chez moi 470 ms

Pour ceux qui veulent relever le temps de calcul, il suffit de remplacer l'appel de main() par les lignes suivantes :

Code : Tout sélectionner

    time1 = ElapsedMilliseconds()
    main()
    MessageRequester("temps de calcul", Str(ElapsedMilliseconds()-time1) + " ms" ,0)
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
Guillot
Messages : 522
Inscription : jeu. 25/juin/2015 16:18

Re: Un petit RayTracing

Message par Guillot »

ça jette !
si t'es interressé par le ray tracing met toi en contact avec Hades (le grand spécialiste du sujet (forum anglais))
il cherche du monde pour travailler dessus
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Un petit RayTracing

Message par G-Rom »

@Comtois
j'ai mis ton code au propre , toujours en C : https://pastebin.com/jd3NgmPP
la structure "v" , est un Vector3 avec surcharge d'opérateur pour les opérations basique sur les vecteurs

Pour un raytracer plus complet, tu pourrais utilisé ce genre de code :

Code : Tout sélectionner

Enumeration 
  #TYPE_PLANE
  #TYPE_SPHERE
  #TYPE_CUBE
  #TYPE_MESH
EndEnumeration

Structure vector3
  x.f
  y.f
  z.f
EndStructure

Structure AABB
  min.vector3
  max.vector3
EndStructure

Structure Geometry
  Position.vector3
  BoundingBox.AABB
  type.w
  *intersect_func
EndStructure

Macro intersect(obj,a,b,c,d,e)
  CallCFunctionFast(obj\intersect_func,a,b,c,d,e)
EndMacro


Structure Sphere Extends Geometry
  ;...
  radius.f
EndStructure

Structure Cube Extends Geometry
  ;...
  width.l
  height.l
  lenght.l
EndStructure

Structure Plane Extends Geometry
  width.l
  height.l
  ;...
EndStructure


ProcedureC ray_plane_intersect(*p.Plane, *rayorig.vector3, *raydir.vector3, *t0.Float, *t1.Float)
  Debug #PB_Compiler_Procedure
  ;...  
EndProcedure

ProcedureC ray_sphere_intersect(*s.Sphere, *rayorig.vector3, *raydir.vector3, *t0.Float, *t1.Float)
  Debug #PB_Compiler_Procedure
  ;...  
EndProcedure


ProcedureC ray_cube_intersect(*c.Cube, *rayorig.vector3, *raydir.vector3, *t0.Float, *t1.Float)
  Debug #PB_Compiler_Procedure
  ;...
EndProcedure


MaSphere.Sphere
MonCube.Cube
MyPlane.Plane


MaSphere\intersect_func = @ray_sphere_intersect()
MonCube\intersect_func = @ray_cube_intersect()
MyPlane\intersect_func = @ray_plane_intersect()


intersect(MyPlane,0,0,0,0,0)
intersect(MonCube,0,0,0,0,0)
intersect(MaSphere,0,0,0,0,0)

Chaque type de geometrie ( sphere, cube, plan, mesh ( triangle ), etc... ) utilise une fonction d'intersection propre, avec une bonne macro et un peu de slicing, tu peu géré n'importe quel type d'objet a tracer. Bon boulot sinon ! :)
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Un petit RayTracing

Message par djes »

Guillot a écrit :ça jette !
si t'es interressé par le ray tracing met toi en contact avec Hades (le grand spécialiste du sujet (forum anglais))
il cherche du monde pour travailler dessus
Tu m'as bloqué (je parle d'hades juste au-dessus) ? :mrgreen:
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Un petit RayTracing

Message par Ar-S »

comtois a écrit : Chez moi 470 ms
433 ms
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Un petit RayTracing

Message par Kwai chang caine »

Sans debugger = 861 ms
Avec debugger = 30302 ms

C'est super beau ces boules transparentes 8O
Merci 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Un petit RayTracing

Message par comtois »

G-Rom a écrit :@Comtois
j'ai mis ton code au propre , toujours en C : https://pastebin.com/jd3NgmPP
la structure "v" , est un Vector3 avec surcharge d'opérateur pour les opérations basique sur les vecteurs
Merci pour l'effort. Je viens de trouver un site qui explique le code.

http://fabiensanglard.net/rayTracing_ba ... ness_card/

Et voici où j'en suis pour l'instant (en utilisant le site ci-dessus) , ça ne marche pas encore, mais je n'ai jamais été aussi proche :)

Il faut une trentaine de secondes sur mon PC pour afficher un truc qui ne ressemble à rien, alors que je devrais obtenir ça :
Image

Code : Tout sélectionner

Structure vector3
  x.f
  y.f
  z.f
EndStructure
; 
; struct v
; {
; f x,y,z;
; v operator+(v r){Return v(x+r.x,y+r.y,z+r.z);}
; v operator*(f r){Return v(x*r,y*r,z*r)      ;}
; f operator%(v r){Return x*r.x+y*r.y+z*r.z   ;}
; v(){}
; v operator^(v r){Return v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.y-y*r.x);}
; v(f a,f b,f c){x=a;y=b;z=c;}
; v operator!(){Return*this*(1/sqrt(*this%*this))               ;}
; } 

;
Global Dim G(8)
G(0) = 247570
G(1) = 280596
G(2) = 280600
G(3) = 249748
G(4) = 18578
G(5) = 18577
G(6) = 231184
G(7) = 16
G(8) = 16
; 

Procedure.f length2(*v.vector3) 
  ProcedureReturn *v\x * *v\x + *v\y * *v\y + *v\z * *v\z
EndProcedure

Procedure.f Mul(*v.vector3, *t.vector3) 
  ProcedureReturn *v\x * *t\x + *v\y * *t\y + *v\z * *t\z
EndProcedure

Procedure normalize(*v.vector3) 
  nor2.f = length2(*v) 
  If (nor2 > 0)  
    invNor.f = 1.0 / Sqr(nor2) 
    *v\x * invNor
    *v\y * invNor
    *v\z * invNor 
  EndIf 
EndProcedure

Procedure.f R()
  ProcedureReturn Random(1000)/1000
EndProcedure  

Procedure cross(*w.vector3, *v.vector3, *r.vector3)
  *w\x = *v\y * *r\z - *v\z * *r\y
  *w\y = *v\z * *r\x - *v\x * *r\z
  *w\z = *v\x * *r\y - *v\y * *r\x
EndProcedure


;The intersection test For line [o,v].
; Return 2 If a hit was found (And also Return distance t And bouncing ray n).
; Return 0 If no hit was found but ray goes upward
; Return 1 If no hit was found but ray goes downward
Procedure T(*o.vector3,*d.vector3,*t.Float,*n.vector3) 
  *t\f=1e9
  m=0
  p1.f=-*o\z/*d\z
  If 0.01<p1
    *t\f=p1
    *n\x=0
    *n\y=0
    *n\z=1
    m=1
  EndIf
  
  ;The world is encoded in G, With 9 lines And 19 columns
  For k=18 To 0 Step -1 ;For each columns of objects
    For j=8 To 0 Step -1;For each line on that columns
      
      If(G(j)&(1<<k)) ;//For this line j, is there a sphere at column i ?
        
        ; There is a sphere but does the ray hits it ?
        
        p.vector3
        p\x=*o\x -k
        p\y=*o\y 
        p\z=*o\z-j-4
        
        
        b.f=Mul(@p,*d)
        c.f=Mul(@p,@p)-1
        q.f=b*b-c
        
        ;Does the ray hit the sphere ?
        If q>0
          ;It does, compute the distance camera-sphere
          s.f=-b-Sqr(q)
          
          If s<*t\f And s>0.01
            ; So far this is the minimum distance, save it. And also
            ; compute the bouncing ray vector into 'n'  
            *t\f=s
            *n\x=p\x+*d\x*s
            *n\y=p\y+*d\y*s
            *n\z=p\z+*d\z*s
            
            normalize(*n)
            m=2
          EndIf  
        EndIf
      EndIf
    Next
  Next
  ProcedureReturn m
EndProcedure

; (S)ample the world And Return the pixel color For
; a ray passing by point o (Origin) And d (Direction)
Procedure S(*w.vector3, *o.vector3, *d.vector3)
  t.f
  n.vector3
  
  ;Search For an intersection ray Vs World.
  m=T(*o,*d,@t,@n)
  
  If m=0
    ;No sphere found And the ray goes upward: Generate a sky color  
    *w\x = 0.7 * Pow(1-*d\z,4)
    *w\y = 0.6 * Pow(1-*d\z,4)
    *w\z =   1 * Pow(1-*d\z,4)
    
    ProcedureReturn  
  EndIf
  
  ; sphere was maybe hit.
  h.vector3  ; h = intersection coordinate
  l.vector3  ; 'l' = direction To light (random delta For shadows).
  r.vector3  ; r = The half-vector
  
  h\x=*o\x+*d\x*t                    
  h\y=*o\y+*d\y*t  
  h\z=*o\z+*d\z*t  
  
  l\x=9+R()+h\x*-1
  l\y=9+R()+h\y*-1
  l\z=16+h\z*-1  
  normalize(@l)
  r\x=*d\x+n\x*(mul(@n,*d)*-2)               
  r\y=*d\y+n\y*(mul(@n,*d)*-2) 
  r\z=*d\z+n\z*(mul(@n,*d)*-2) 
  
  ;Calculated the lambertian factor
  b.f=mul(@l,@n)
  
  ;Calculate illumination factor (lambertian coefficient > 0 Or in shadow)?
  If b<0 Or T(@h,@l,@t,@n)
    b=0
  EndIf
  
  ; Calculate the color 'p' With diffuse And specular component 
  p.f=Pow(mul(@l,@r)*Bool(b>0),99)
  
  If m=1   ;m == 1
    h\x=h\x*0.2; //No sphere was hit and the ray was going downward: Generate a floor color
    h\y=h\y*0.2
    h\z=h\z*0.2
    
    ii.i = Int(Round(h\y,#PB_Round_Nearest))&1
    
    If Round(h\x,#PB_Round_Nearest)+ ii
      *w\x = 3
      *w\y = 1
      *w\z = 1
    Else  
      *w\x = 3*(b*0.2+0.1)
      *w\y = 3*(b*0.2+0.1)
      *w\z = 3*(b*0.2+0.1)
    EndIf  
    ProcedureReturn
  EndIf
  
  ;m == 2 A sphere was hit. Cast an ray bouncing from the sphere surface.
  S(*w,@h,@r)
  ww.vector3
  ww\x = p
  ww\y = p
  ww\z = p
  *w\x = ww\x + *w\x*0.5 ; //Attenuate color by 50% since it is bouncing (* .5)
  *w\y = ww\x + *w\y*0.5
  *w\z = ww\z + *w\z*0.5
  ProcedureReturn 
EndProcedure


; The main function. It generates a PPM image To stdout.
; Usage of the program is hence: ./card > erk.ppm
Procedure main()
  
  ; The '!' are For normalizing each vectors With ! operator. 
  Protected.vector3 g,a,b,c,p,pc,t,q
  ;Camera direction
  g\x =-6
  g\y = -16
  g\z = 0 
  normalize(@g)
  ; Camera up vector...Seem Z is pointing up :/ WTF !
  q\x = 0
  q\y = 0
  q\z = 1
  
  cross(@a, @q, @g)
  normalize(@a)
  a\x *0.002 
  a\y *0.002 
  a\z *0.002   
  ; The right vector, obtained via traditional cross-product
  cross(@b,@g,@a)
  normalize(@b)
  b\x *0.002 
  b\y *0.002 
  b\z *0.002 
  ; WTF ? See https://news.ycombinator.com/item?id=6425965.
  c\x=(a\x+b\x)*-256+g\x      
  c\y=(a\y+b\y)*-256+g\y  
  c\z=(a\x+b\z)*-256+g\z  
  
  For y=511 To 0  Step -1 ;For each column
    For x=511 To 0 Step -1;For each pixel in a line
      
      ;Reuse the vector class To store Not XYZ but a RGB pixel color
      ; Default pixel color is almost pitch black
      pc\x = 255    
      pc\y = 255 
      pc\z = 255 
      ;Cast 64 rays per pixel (For blur (stochastic sampling) And soft-shadows. 
      For r=63 To 0 Step -1 
        
        ; The delta To apply To the origin of the view (For Depth of View blur).
        t\x=a\x*(R()-0.5)*99+b\x*(R()-0.5)*99;  A little bit of delta 
        t\y=a\y*(R()-0.5)*99+b\y*(R()-0.5)*99;  A little bit of delta 
        t\z=a\z*(R()-0.5)*99+b\z*(R()-0.5)*99;  A little bit of delta 
        
        ; Set the camera focal point v(17,16,8) And Cast the ray 
        ; Accumulate the color returned in the p variable
        q.vector3 ;Ray Origin
        q\x = 17 + t\x
        q\y = 16 + t\y
        q\z =  8 + t\z
        w.vector3 ; Ray Direction With random deltas, For stochastic sampling
        w\x = t\x*-1+(a\x*(R()+x)+b\x*(y+R())+c\x)*16
        w\y = t\y*-1+(a\y*(R()+x)+b\y*(y+R())+c\y)*16
        w\z = t\z*-1+(a\z*(R()+x)+b\z*(y+R())+c\z)*16
        normalize(@w)
        S(@p,@q,@w)
        p\x=p\x*3.5+pc\x; // +p for color accumulation
        p\y=p\y*3.5+pc\y
        p\z=p\z*3.5+pc\z
      Next
      
      Plot(511-x,511-y, RGB(p\x,p\y,p\z))
      
      
    Next
  Next  
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
  MessageRequester("Error", "Can't open the sprite system", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 512, 512, "Gadget and sprites!", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  
  If OpenWindowedScreen(WindowID(0), 0, 0, 512, 512, 0, 0, 0)
    
    CreateSprite(0,512, 512)
    StartDrawing(SpriteOutput(0))
    main()
    StopDrawing()
    
    ReleaseMouse(1)
    Repeat
      Repeat
        ; Always process all the events to flush the queue at every frame
        Event = WindowEvent()
        
        Select Event
          Case #PB_Event_CloseWindow
            Quit = 1
            
            
        EndSelect
        
      Until Event = 0 ; Quit the event loop only when no more events are available
      
      ExamineKeyboard()
      
      
      ExamineMouse()
      
      ; Clear the screen and draw our sprites
      ClearScreen(RGB(0,0,0))
      
      DisplaySprite(0,0, 0)
      
      FlipBuffers()       ; Inverse the buffers (the back become the front (visible)... and we can do the rendering on the back
      
    Until  Quit Or KeyboardPushed(#PB_Key_Escape)
  Else
    MessageRequester("Error", "Can't open windowed screen!", 0)
  EndIf
EndIf
Dernière modification par comtois le jeu. 05/avr./2018 20:29, modifié 1 fois.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Un petit RayTracing

Message par falsam »

Comtois a écrit :Combien de temps ça met ??
Effectivement je n'ai pas retirer l'option déboguer.

-Avec debug 22107
-Sans debug 955
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
G-Rom
Messages : 3626
Inscription : dim. 10/janv./2010 5:29

Re: Un petit RayTracing

Message par G-Rom »

j'ai pas beaucoup de temps, mais par exemple la fonction S() , ne renvois pas de resultat, alors que le code C oui.
return v(p,p,p)+S(h,r)*.5;
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Un petit RayTracing

Message par comtois »

G-Rom a écrit :j'ai pas beaucoup de temps, mais par exemple la fonction S() , ne renvois pas de resultat, alors que le code C oui.
return v(p,p,p)+S(h,r)*.5;
J'ai ajouté un paramètre à la fonction pour copier le résultat.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Répondre