[Tuto] Raytracing , principe de base

Informations pour bien débuter en PureBasic
Anonyme

[Tuto] Raytracing , principe de base

Message par Anonyme »

Je vais tenté via un code d'expliquer la base du raytracing en purebasic.

Tout d'abord, vous devez avoir des notions sur les vecteurs :

- un vecteur est un point dans un repère , en gros une position
représenté sous cette forme x,y,z
en purebasic on le represente sous cette forme :

Code : Tout sélectionner

Structure Vector3D
	x.d
	y.d
	z.d
EndStructure

Code : Tout sélectionner

Structure Vector3F
	x.f
	y.f
	z.f
EndStructure
3D ou 3F , c'est la notation hongroise , 3 pour les dimension , suivi du type
F pour les float , D pour les doubles. on travaillera avec les double.

2 vecteurs dans l'espace représente une droite , ou un segment ,
une demi-droite possède un vecteur , et une direction , la direction est un vecteur unitaire , on verra plus tard comment le calculé.


Le principe du Raytracing est simple , on lance des rayons à partir du point de vue vers le point visé , si il y a une interection avec un objet on calcul la lumière , on ajoute un pixel , etc...

Image
Source de l'image


Dans cette exemple , nous ne verrons pas le calcul de la lumière


Tout d'abord , il faut initialisé notre "camera"
Il lui faut un point d'origine , un point visé , une direction.
L'origine est 0,0,0
le point visé , x,y,distance focale

La distance focale , est importante et il ne faut pas la négligé , si vous mettez une valeur au pif , par exemple 1000 , le rendu ne sera pas pareil selon la résolution.

La distance focale est représenté par "d" sur le schéma plus haut.

Il se calcul de cette façon :

Code : Tout sélectionner

-(ResolutionX / ( 2 * Tan ( FOV / 2 )   )   )
Plus le FOV est grand , plus la distance focale est petite , et inversement , un FOV de 30 est correct.


Commençons par poser nos jalons
avec des structures de bases :

Code : Tout sélectionner

Structure Vector3D
	x.d
	y.d
	z.d
EndStructure

Structure Ray
	O.Vector3D
	D.Vector3D
EndStructure

Structure sphere
 position.Vector3D
 radius.d
EndStructure
Il va nous falloir aussi quelques fonction pour nos vecteurs
on doit pouvoir les soustraires entre eux , obtenir un produit scalaire ( vector_dot ) , etc...

Code : Tout sélectionner

Procedure vector_normalize(*V.Vector3D)
	id.d = 1/Sqr(  (*V\x * *V\x) + (*V\y * *V\y) + (*V\z * *V\z)  )
	*V\x = *V\x * id
	*V\y = *V\y * id
	*V\z = *V\z * id
EndProcedure

Procedure.d vector_dot(*A.vector3d,*B.vector3d)
 ProcedureReturn *A\x * *B\x  + *A\y * *B\y  + *A\z * *B\z  
EndProcedure

Procedure.i vector_copy(*a.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x
	*V\y = *a\y
	*V\z = *a\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_sub(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	- *b\x
	*V\y = *a\y	- *b\y
	*V\z = *a\z	- *b\z
	ProcedureReturn *V
EndProcedure


Revenons à notre point de vue ,

Notre point de vue est le 0,0,0
le point visé Pixel_x , Pixel_y , Distance_Focale

ce qui nous donne :

Code : Tout sélectionner

; Point d'origine :
A.Vector3D
A\x	= 0
A\y	= 0
A\z	= 0

For pixel_y = 0 To 480 -1
	For pixel_x = 0 To 640 -1

		; Point visé
		B.Vector3D
		B\x	= pixel_x - (640/2)
		B\y	= pixel_y	- (480/2)
		B\z	= -(640 / (2*Tan(30/2)))		

		; on le normalize
		vector_normalize(B)

On va donc pouvoir créer notre rayon ,
il nous faut , l'origine ( on l'a déjà 0,0,0 ) est la direction.

La direction est le vecteur directeur entre Origine et le point visé , il se calcule la la manière suivante :
Direction = B - A
Normalize(Direction)
en code :

Code : Tout sélectionner

		;Vecteur direction du rayon
		Ray_Direction.Vector3D
		
		Ray_Direction\x = B\x - A\x
		Ray_Direction\y = B\y - A\y
		Ray_Direction\z = B\z - A\z
		
		vector_normalize(Ray_Direction)

Notre rayon est donc :

Code : Tout sélectionner

		Rayon.Ray
		
		Rayon\O\x = A\x	
		Rayon\O\y = A\y
		Rayon\O\z = A\z
		
		Rayon\D\x = Ray_Direction\x	
		Rayon\D\y = Ray_Direction\y
		Rayon\D\z = Ray_Direction\z

Notre rayon est créer , il nous faut donc savoir si il rentre en collision avec les objets ( ici la sphère )
j'utilise cette fonction , pour testé la collision :


On lui passe en paramètre une sphere , un rayon , un pointeur sur un coefficient que l'on fixe avant avec une grande valeur ( ex:20000 )
si il y a une intersection, le Coef doit être plus petit ( c'est la distance d'impact entre l'objet et la caméra )
Si la sphere est en Z à 100 avec un diamètre de 20 , et si le rayon tape dans le centre , alors le coef doit être de 90...

Code : Tout sélectionner

Procedure intersection_sphere(*sphere.sphere,*ray.ray,*t)

*dist.vector3d = vector_copy(*sphere\position)

vector_sub(*dist,*ray\o)

B.f = vector_dot(*ray\d,*dist)
D.f = B*B - vector_dot(*dist,*dist) + *sphere\radius * *sphere\radius


If D<0
	ProcedureReturn #False
EndIf 

T0.f = B - Sqr(D)
T1.f = B + Sqr(D)
result = #False


If (T0>0.1) And (T0 < PeekD(*t))
	PokeD(*t,T0)
	result = #True
EndIf 

If (T1>0.1) And (T1 < PeekD(*t))
	PokeD(*t,T1)
	result = #True
EndIf 

ProcedureReturn result 
EndProcedure

l'utilisation de la procédure :
Coef.d = 20000
Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
Si intersection <>-1 alors il y a une intersection... simple non ?

voici la boucle principale :

Code : Tout sélectionner

For pixel_y = 0 To 480 -1
	For pixel_x = 0 To 640 -1

		; Point visé du rayon
		B.Vector3D
		B\x	= pixel_x - (640/2)
		B\y	= pixel_y	- (480/2)
		B\z	= -(640 / (2*Tan(30/2)))		; Calcul de la Distance Focale ( Fov = 30 )
		; on le normalize
		vector_normalize(B)
		
		;Vecteur direction du rayon
		Ray_Direction.Vector3D
		
		Ray_Direction\x = B\x - A\x
		Ray_Direction\y = B\y - A\y
		Ray_Direction\z = B\z - A\z
		
		vector_normalize(Ray_Direction)
		
		
		; On a le point de départ
		; le point visé , on en à donc deduis la direction
		; on peut construire notre rayon.
		
		Rayon.Ray
		
		Rayon\O\x = A\x	
		Rayon\O\y = A\y
		Rayon\O\z = A\z
		
		Rayon\D\x = Ray_Direction\x	
		Rayon\D\y = Ray_Direction\y
		Rayon\D\z = Ray_Direction\z
		
		
		Coef.d = 20000
		Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
		
		If Intersection<>-1 And Coef < 20000
			; Affiche un pixel en X,Y ici !!!!!
		EndIf 
		
	
	Next 
Next 
C'est simple non ?


le code complet :

Code : Tout sélectionner

Structure Vector3D
	x.d
	y.d
	z.d
EndStructure

Procedure vector_normalize(*V.Vector3D)
	id.d = 1/Sqr(  (*V\x * *V\x) + (*V\y * *V\y) + (*V\z * *V\z)  )
	*V\x = *V\x * id
	*V\y = *V\y * id
	*V\z = *V\z * id
EndProcedure

Procedure.d vector_dot(*A.vector3d,*B.vector3d)
 ProcedureReturn *A\x * *B\x  + *A\y * *B\y  + *A\z * *B\z  
EndProcedure

Procedure.i vector_copy(*a.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x
	*V\y = *a\y
	*V\z = *a\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_sub(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	- *b\x
	*V\y = *a\y	- *b\y
	*V\z = *a\z	- *b\z
	ProcedureReturn *V
EndProcedure


Structure Ray
	O.Vector3D
	D.Vector3D
EndStructure

Structure sphere
 position.Vector3D
 radius.d
EndStructure


Procedure intersection_sphere(*sphere.sphere,*ray.ray,*t)

*dist.vector3d = vector_copy(*sphere\position)

vector_sub(*dist,*ray\o)

B.f = vector_dot(*ray\d,*dist)
D.f = B*B - vector_dot(*dist,*dist) + *sphere\radius * *sphere\radius


If D<0
	ProcedureReturn #False
EndIf 

T0.f = B - Sqr(D)
T1.f = B + Sqr(D)
result = #False


If (T0>0.1) And (T0 < PeekD(*t))
	PokeD(*t,T0)
	result = #True
EndIf 

If (T1>0.1) And (T1 < PeekD(*t))
	PokeD(*t,T1)
	result = #True
EndIf 

ProcedureReturn result 
EndProcedure





Sphere.sphere
Sphere\position\z = 200
Sphere\radius = 20*2


; Point de départ du rayon
A.Vector3D
A\x	= 0
A\y	= 0
A\z	= -1

CreateImage(0,640,480)
StartDrawing(ImageOutput(0))

For pixel_y = 0 To 480 -1
	For pixel_x = 0 To 640 -1

		; Point visé du rayon
		B.Vector3D
		B\x	= pixel_x - (640/2)
		B\y	= pixel_y	- (480/2)
		B\z	= -(640 / (2*Tan(30/2)))		; Calcul de la Distance Focale ( Fov = 30 )
		; on le normalize
		vector_normalize(B)
		
		;Vecteur direction du rayon
		Ray_Direction.Vector3D
		
		Ray_Direction\x = B\x - A\x
		Ray_Direction\y = B\y - A\y
		Ray_Direction\z = B\z - A\z
		
		vector_normalize(Ray_Direction)
		
		
		; On a le point de départ
		; le point visé , on en à donc deduis la direction
		; on peut construire notre rayon.
		
		Rayon.Ray
		
		Rayon\O\x = A\x	
		Rayon\O\y = A\y
		Rayon\O\z = A\z
		
		Rayon\D\x = Ray_Direction\x	
		Rayon\D\y = Ray_Direction\y
		Rayon\D\z = Ray_Direction\z
		
		
		Coef.d = 20000
		Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
		
		If Intersection<>-1 And Coef < 20000
			Plot(pixel_x,pixel_y,$FF)
		EndIf 
		
	
	Next 
Next 


StopDrawing()
SaveImage(0,"Save.bmp")
l'output du programme , pixar n'a plus qu'a bien se tenir ! :D

Image
Anonyme

Message par Anonyme »

Avec de l'éclairage diffus !


Image

tout ce passe entre

Code : Tout sélectionner

if Norme<>0

endif 

Code : Tout sélectionner

Structure Vector3D
	x.d
	y.d
	z.d
EndStructure

Procedure vector_normalize(*V.Vector3D)
	id.d = 1/Sqr(  (*V\x * *V\x) + (*V\y * *V\y) + (*V\z * *V\z)  )
	*V\x = *V\x * id
	*V\y = *V\y * id
	*V\z = *V\z * id
EndProcedure

Procedure.d vector_dot(*A.vector3d,*B.vector3d)
 ProcedureReturn *A\x * *B\x  + *A\y * *B\y  + *A\z * *B\z  
EndProcedure

Procedure.i vector_copy(*a.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x
	*V\y = *a\y
	*V\z = *a\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_sub(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	- *b\x
	*V\y = *a\y	- *b\y
	*V\z = *a\z	- *b\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_mul(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	* *b\x
	*V\y = *a\y	* *b\y
	*V\z = *a\z	* *b\z
	ProcedureReturn *V
EndProcedure

Structure Ray
	O.Vector3D
	D.Vector3D
EndStructure

Structure sphere
 position.Vector3D
 radius.d
EndStructure


Procedure intersection_sphere(*sphere.sphere,*ray.ray,*t)

*dist.vector3d = vector_copy(*sphere\position)

vector_sub(*dist,*ray\o)

B.f = vector_dot(*ray\d,*dist)
D.f = B*B - vector_dot(*dist,*dist) + *sphere\radius * *sphere\radius


If D<0
	ProcedureReturn #False
EndIf 

T0.f = B - Sqr(D)
T1.f = B + Sqr(D)
result = #False


If (T0>0.1) And (T0 < PeekD(*t))
	PokeD(*t,T0)
	result = #True
EndIf 

If (T1>0.1) And (T1 < PeekD(*t))
	PokeD(*t,T1)
	result = #True
EndIf 

ProcedureReturn result 
EndProcedure





Sphere.sphere
Sphere\position\z = 750
Sphere\radius = 200

Lumiere.Vector3D
Lumiere\x = -500
Lumiere\y = -500
Lumiere\z = -500

LumiereCouleur.Vector3D
LumiereCouleur\x = 0.5
LumiereCouleur\y = 0.5
LumiereCouleur\z = 0.5

; Point de départ du rayon
A.Vector3D
A\x	= 0
A\y	= 0
A\z	= -1

CreateImage(0,640,480)
StartDrawing(ImageOutput(0))
Box(0,0,640,480,$400000)

Ta.d = ElapsedMilliseconds()

For pixel_y = 0 To 480 -1
	For pixel_x = 0 To 640 -1

		; Point visé du rayon
		B.Vector3D
		B\x	= pixel_x - (640/2)
		B\y	= pixel_y	- (480/2)
		B\z	= -(640 / (2*Tan(30/2)))		; Calcul de la Distance Focale ( Fov = 30 )
		; on le normalize
		vector_normalize(B)
		
		;Vecteur direction du rayon
		Ray_Direction.Vector3D
		
		Ray_Direction\x = B\x - A\x
		Ray_Direction\y = B\y - A\y
		Ray_Direction\z = B\z - A\z
		
		vector_normalize(Ray_Direction)
		
		
		; On a le point de départ
		; le point visé , on en à donc deduis la direction
		; on peut construire notre rayon.
		
		Rayon.Ray
		
		Rayon\O\x = A\x	
		Rayon\O\y = A\y
		Rayon\O\z = A\z
		
		Rayon\D\x = Ray_Direction\x	
		Rayon\D\y = Ray_Direction\y
		Rayon\D\z = Ray_Direction\z
		
		
		Coef.d = 20000
		Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
		
		If Intersection<>-1 And Coef < 20000
			
			
			; On calcul le point d'impact
			Impact.Vector3D
			Impact\x = Rayon\O\x + Rayon\D\x * Coef
			Impact\y = Rayon\O\y + Rayon\D\y * Coef
			Impact\z = Rayon\O\z + Rayon\D\z * Coef
			
			
		  ; On calcule la normale sur la sphere     
    
     Direction.vector3d
     Distance.vector3d
     
     Distance\x = Impact\x - Sphere\position\x
		 Distance\y = Impact\y - Sphere\position\y
		 Distance\z = Impact\z - Sphere\position\z
			
		vector_normalize(Distance)
		 ; la norme
		 Norme.d = vector_dot(Distance,Distance)
		 Temp.f = Norme * Norme
		 Temp = 1 / Sqr(Temp)
		 Norme = Temp * Norme
		 
		 		 
		 If Norme<>0
		  
		  ; On calcul la lumière ici ( Modèle de lambert )


		; Distance entre la lumière et l'impact
		RayLightDist.Vector3D
		RayLightDist\x = Lumiere\x - Impact\x
		RayLightDist\y = Lumiere\y - Impact\y
		RayLightDist\z = Lumiere\z - Impact\z
		
		; Produit scalaire
		NormeRayDist.d = vector_dot(RayLightDist,RayLightDist)
		
		RayLightDir.Vector3D
		
		; la norme 
		If NormeRayDist<>0
				RayLightDir\x = RayLightDist\x / Norme
				RayLightDir\y = RayLightDist\y / Norme
				RayLightDir\z = RayLightDist\z / Norme
		EndIf 
		

    
    
    
		*IntensityLight.Vector3D
		*IntensityLight = vector_mul(RayLightDir,Distance)
		

		
    lambert.f = (*IntensityLight\x * Norme)+ (*IntensityLight\y * Norme)+(*IntensityLight\z * Norme)
		  

		    Red.d    = (LumiereCouleur\x * 0.5  * lambert)
        Green.d  = (LumiereCouleur\y * 0.5  * lambert)
        Blue.d   = (LumiereCouleur\z * 0.5  * lambert)
       
                                                                        
        If Red<0    : red   = 0 : EndIf 
        If Green<0  : Green = 0 : EndIf 
        If blue<0   : blue  = 0 : EndIf 
        If Red>255    : red   = 255 : EndIf 
        If Green>255  : Green = 255 : EndIf 
        If blue>255   : blue  = 255 : EndIf 
        
        
        Plot(Pixel_x,Pixel_y,RGB(Red,Green,Blue))
     
		 EndIf 
		
		
		
		
		
			
		EndIf 
		
	
	Next 
Next 
Tb.d = ElapsedMilliseconds()

DrawText(10,10,"TIME RENDERING = "+StrD(Tb-Ta)+" ms")

StopDrawing()
SaveImage(0,"Save.bmp")
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

ouaip , ben je suis vraiment une bille en math :lol:
Anonyme

Message par Anonyme »

Avant de vouloir aller plus loin , je tiens à précisé que les codes du dessus sont "pédagogique"

j'entends par là qu'il ne peut pas y avoir plusieurs sphères , ni plusieurs lumières.

Pour cela l'algorithme est le suivant :

Code : Tout sélectionner

 Pour tout les pixels de la scene
  Trouver l'intersection la plus proche
   Si intersection
    Lancer un rayon vers les sources de lumière
     Si le rayon intersecte un autre objet avant d'atteindre la lumière , le pixel est dans l'ombre
     Si le materiau est reflechissant , récuperer la couleur de l'objet touché
        Calcul de la couleur du pixel
pixel suivant
Anonyme

Message par Anonyme »

Dobro a écrit :ouaip , ben je suis vraiment une bille en math :lol:

je te rassure , moi aussi , j'y vais à taton ^^
tmyke
Messages : 1554
Inscription : lun. 24/juil./2006 6:44
Localisation : vosges (France) 47°54'39.06"N 6°20'06.39"E

Message par tmyke »

Cpl.Bator a écrit :Avant de vouloir aller plus loin , je tiens à précisé que les codes du dessus sont "pédagogique"
niveau pédagogique, c'est très réussi, beau travail, c'est je pense aussi clair que cela puisse l'être.

Il est sûr que les bases mathématiques nécessaires sont en effet minimum pour tout bien suivre,
mais je pense quelles ne sont pas insurmontable.

Belle série sur le sujet en perspective en tous les cas ;)
Force et sagesse...
Anonyme

Message par Anonyme »

Le SuperSampling


Le Supersampling est une technique qui permet d'éviter l'effet escalier entre les pixels , la mise en place est très facile.

Sans supersampling
Image


Avec supersampling 2x
Image

ps : imageshack à l'air de déformé le résultat BMP->PNG :/
a testé chez vous donc :D



Le principe est simple , on veut un rendu dans une image de
640x480 pixel , et bien avec un supersampling de 2
on travaillera dans une image de 1280x960 pixels
Ce qui engendre forcement plus de lancer de rayon ( 4x plus pour une même scène )
une fois notre scene dessiné , on re-dimensionne notre grande image de
1280x960 à 640x480 , grace à la fonction resizeimage() par exemple , pas besoin de se casser plus la tête :D

ReCode :

Code : Tout sélectionner

Structure Vector3D
	x.d
	y.d
	z.d
EndStructure

Procedure vector_normalize(*V.Vector3D)
	id.d = 1/Sqr(  (*V\x * *V\x) + (*V\y * *V\y) + (*V\z * *V\z)  )
	*V\x = *V\x * id
	*V\y = *V\y * id
	*V\z = *V\z * id
EndProcedure

Procedure.d vector_dot(*A.vector3d,*B.vector3d)
 ProcedureReturn *A\x * *B\x  + *A\y * *B\y  + *A\z * *B\z  
EndProcedure

Procedure.i vector_copy(*a.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x
	*V\y = *a\y
	*V\z = *a\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_sub(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	- *b\x
	*V\y = *a\y	- *b\y
	*V\z = *a\z	- *b\z
	ProcedureReturn *V
EndProcedure

Procedure.i vector_mul(*a.vector3d,*b.vector3d)
	*V.vector3d = AllocateMemory(SizeOf(vector3d))
	*V\x = *a\x	* *b\x
	*V\y = *a\y	* *b\y
	*V\z = *a\z	* *b\z
	ProcedureReturn *V
EndProcedure

Structure Ray
	O.Vector3D
	D.Vector3D
EndStructure

Structure sphere
 position.Vector3D
 radius.d
EndStructure


Procedure intersection_sphere(*sphere.sphere,*ray.ray,*t)

*dist.vector3d = vector_copy(*sphere\position)

vector_sub(*dist,*ray\o)

B.f = vector_dot(*ray\d,*dist)
D.f = B*B - vector_dot(*dist,*dist) + *sphere\radius * *sphere\radius


If D<0
	ProcedureReturn #False
EndIf 

T0.f = B - Sqr(D)
T1.f = B + Sqr(D)
result = #False


If (T0>0.1) And (T0 < PeekD(*t))
	PokeD(*t,T0)
	result = #True
EndIf 

If (T1>0.1) And (T1 < PeekD(*t))
	PokeD(*t,T1)
	result = #True
EndIf 

ProcedureReturn result 
EndProcedure





Sphere.sphere
Sphere\position\z = 750
Sphere\radius = 200

Lumiere.Vector3D
Lumiere\x = -500
Lumiere\y = -500
Lumiere\z = -500

LumiereCouleur.Vector3D
LumiereCouleur\x = 0.5
LumiereCouleur\y = 0.5
LumiereCouleur\z = 0.5

; Point de départ du rayon
A.Vector3D
A\x	= 0
A\y	= 0
A\z	= -1


SuperSampling = 2


CreateImage(0,640*SuperSampling,480*SuperSampling)
StartDrawing(ImageOutput(0))
Box(0,0,640*SuperSampling,480*SuperSampling,$400000)

Ta.d = ElapsedMilliseconds()

For pixel_y = 0 To 480*SuperSampling -1
	For pixel_x = 0 To 640*SuperSampling -1

		; Point visé du rayon
		B.Vector3D
		B\x	= pixel_x - ((640*SuperSampling)/2)
		B\y	= pixel_y	- ((480*SuperSampling)/2)
		B\z	= -((640*SuperSampling) / (2*Tan(30/2)))		; Calcul de la Distance Focale ( Fov = 30 )
		; on le normalize
		vector_normalize(B)
		
		;Vecteur direction du rayon
		Ray_Direction.Vector3D
		
		Ray_Direction\x = B\x - A\x
		Ray_Direction\y = B\y - A\y
		Ray_Direction\z = B\z - A\z
		
		vector_normalize(Ray_Direction)
		
		
		; On a le point de départ
		; le point visé , on en à donc deduis la direction
		; on peut construire notre rayon.
		
		Rayon.Ray
		
		Rayon\O\x = A\x	
		Rayon\O\y = A\y
		Rayon\O\z = A\z
		
		Rayon\D\x = Ray_Direction\x	
		Rayon\D\y = Ray_Direction\y
		Rayon\D\z = Ray_Direction\z
		
		
		Coef.d = 20000
		Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
		
		If Intersection<>-1 And Coef < 20000
			
			
			; On calcul le point d'impact
			Impact.Vector3D
			Impact\x = Rayon\O\x + Rayon\D\x * Coef
			Impact\y = Rayon\O\y + Rayon\D\y * Coef
			Impact\z = Rayon\O\z + Rayon\D\z * Coef
			
			
		  ; On calcule la normale sur la sphere     
    
     Direction.vector3d
     Distance.vector3d
     
     Distance\x = Impact\x - Sphere\position\x
		 Distance\y = Impact\y - Sphere\position\y
		 Distance\z = Impact\z - Sphere\position\z
			
		vector_normalize(Distance)
		 ; la norme
		 Norme.d = vector_dot(Distance,Distance)
		 Temp.f = Norme * Norme
		 Temp = 1 / Sqr(Temp)
		 Norme = Temp * Norme
		 
		 		 
		 If Norme<>0
		  
		  ; On calcul la lumière ici ( Modèle de lambert )


		; Distance entre la lumière et l'impact
		RayLightDist.Vector3D
		RayLightDist\x = Lumiere\x - Impact\x
		RayLightDist\y = Lumiere\y - Impact\y
		RayLightDist\z = Lumiere\z - Impact\z
		
		; Produit scalaire
		NormeRayDist.d = vector_dot(RayLightDist,RayLightDist)
		
		RayLightDir.Vector3D
		
		; la norme 
		If NormeRayDist<>0
				RayLightDir\x = RayLightDist\x / Norme
				RayLightDir\y = RayLightDist\y / Norme
				RayLightDir\z = RayLightDist\z / Norme
		EndIf 
		

    
    
    
		*IntensityLight.Vector3D
		*IntensityLight = vector_mul(RayLightDir,Distance)
		

		
    lambert.f = (*IntensityLight\x * Norme)+ (*IntensityLight\y * Norme)+(*IntensityLight\z * Norme)
		  

		    Red.d    = (LumiereCouleur\x * 0.5  * lambert)
        Green.d  = (LumiereCouleur\y * 0.5  * lambert)
        Blue.d   = (LumiereCouleur\z * 0.5  * lambert)
       
                                                                        
        If Red<0    : red   = 0 : EndIf 
        If Green<0  : Green = 0 : EndIf 
        If blue<0   : blue  = 0 : EndIf 
        If Red>255    : red   = 255 : EndIf 
        If Green>255  : Green = 255 : EndIf 
        If blue>255   : blue  = 255 : EndIf 
        
        
        Plot(Pixel_x,Pixel_y,RGB(Red,Green,Blue))
     
		 EndIf 
		
		
		
		
		
			
		EndIf 
		
	
	Next 
Next 
Tb.d = ElapsedMilliseconds()
StopDrawing()

ResizeImage(0,640,480)
StartDrawing(ImageOutput(0))
DrawText(10,10,"TIME RENDERING = "+StrD(Tb-Ta)+" ms")
StopDrawing()
SaveImage(0,"Save.bmp")
tonton
Messages : 315
Inscription : mar. 26/avr./2005 15:19

Message par tonton »

mon boitier Cpl!! tu t' attaque a un sujet dont je n osais apréhender.
je t encourage sur cette voie.
et rassures toi !!moi non plus je ne comprends rien a tes codes....
Si tu pouvais faire voir ce que ca donne en temps réel? 8)
Je suis le sujet avec beaucoup d' attention!!
Anonyme

Message par Anonyme »

Code : Tout sélectionner

Si tu pouvais faire voir ce que ca donne en temps réel? 
Impensable , 200 ms un rendu , ca fait environ 5fps...

je vais voir pour combiné mes connaissances en la matière pour faire cohabité
du polygonale simple et le raytracing en temps réel , avec une technique de subsampling cela devrais le faire pour des petites scenes pas trop complexe.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

S'il y a quelqu'un qui peut optimiser ton code, c'est bien tonton! Figure-toi qu'on arrivait à faire des scènes simples en temps réel sur Amiga (7,14Mhz, je le rappelle); certes, c'était en 160x100 mais quand même (trois sphères de mémoire, avec réflexions)! Bien sûr avant d'optimiser, il vaut mieux avoir quelque chose de plus complet.

PS: Pareil que tonton, c'est génial de se lancer là-dedans! Pfiou moi j'ai jamais eu le courage! Je n'en reviens pas de ce que tu oses :)
Anonyme

Message par Anonyme »

Bah forcement qu'en 160x100 je peut faire un truc fluide sans problèmes
mais adapter cela sur du 640x480 ou 800x600... pas la même histoire , on peut le faire , j'ai pensé utilisé les shaders pour faire les calculs vectoriel , afin de gardé les ressource CPU ( j'avais lu un truc sur le sujet. )
Mais bon... j'vais pas m'embarquer pour du temps réel avec de tel résolutions :D
Je n'en reviens pas de ce que tu oses
C'est pas très compliqué au final , c'est même simple le concept , suffit de s'intéresser :D

D'ailleurs , tant que je t'ai sous la main , j'aurais un truc à te présenté qui va très certainement t'intéresser , chuuuut , j'en dit pas plus pour le moment :D
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

A ton service! Figure-toi que moi aussi j'aurais un truc à te présenter, et il me faudrait une solide équipe de dév 3d :)
garzul
Messages : 683
Inscription : mer. 26/mai/2004 0:33

Message par garzul »

Super tuto! très simple à comprendre :) (il faudrait faire le même pour les voxels, juste une idée :p)
mais adapter cela sur du 640x480 ou 800x600... pas la même histoire , on peut le faire , j'ai pensé utilisé les shaders pour faire les calculs vectoriel , afin de gardé les ressource CPU ( j'avais lu un truc sur le sujet. )
Je me suis faît un petit raytracer temp réel il y à pas longtemps d'ailleurs, si ça t'intéresse les sources (C++ mais facilement portable) sont dispos ici: http://garzul.tonsite.biz/RTR/src.zip

Il utilise pas d'optimisation très agressive mais il tourne plutôt bien (90fps@640x480 sur ma tortue à 3ghz), la moitié des calculs sont precalcs (sauf shading) ce qui ne permet pas de bouger les objets, il me semble que sans ça il tourne à ~50fps.

Je l'ai porté en flash d'ailleurs (20fps ici): http://garzul.tonsite.biz/RTR/AS3/

Une optimisation qui peut être sympa niveau résultat et qui n'est pas difficile c'est d'utiliser les instructions SSE pour les calculs vectoriels, je sais pas si c'est faisable en PB par contre (mais ça devrait l'être) ou sinon la meilleur solution actuellement niveau perf et celle qui est utilisé dans les démos récentes, exemple: http://www.youtube.com/watch?v=hYD58OdL_bA c'est d'utiliser un pixel shader comme tu l'as dit. :)

PS: Un excellent site pour le raytracing temp réel: http://ompf.org/
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Bravo Cpl.Bator, j'avais pas vu ce sujet... tes codes sont vraiment super pédagogique ! Vraiment très intéressant !
Anonyme

Message par Anonyme »

Merci. ;)
(il faudrait faire le même pour les voxels, juste une idée :p)
je me suis jamais vraiment penché sur le problème , la seule chose que j'avais pensé , c'est d'utiliser un tel système ( voxels ) pour soustraire des formes (CSG) , puis de triangularisé le résultat ( Méthode de Delaunay )
cela peu être utile pour faire des trous dans n'importe quelle forme complexe !
Répondre