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
EndStructureCode : Tout sélectionner
Structure Vector3F
	x.f
	y.f
	z.f
EndStructureF 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...

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 )   )   )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
EndStructureon 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
EndProcedureRevenons à 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 :
en code :Direction = B - A
Normalize(Direction)
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\zNotre 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 
EndProcedurel'utilisation de la procédure :
Si intersection <>-1 alors il y a une intersection... simple non ?Coef.d = 20000
Intersection.b = intersection_sphere(Sphere,Rayon,@Coef)
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 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")


