Défi Fonction 2D d'éclairage super optimisé

Programmation d'applications complexes
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

Pour un poteau rond tu veux dire? Faudrait éviter mais si tu insistes, comme tu as le centre du poteau et son rayon, la distance entre la lampe et le poteau (hauteur du triangle isocèle), tu peux assez facilement calculer les 2 intersections du rayon sur le cercle...
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

djes a écrit :Pour un poteau rond tu veux dire? Faudrait éviter mais si tu insistes, comme tu as le centre du poteau et son rayon, la distance entre la lampe et le poteau (hauteur du triangle isocèle), tu peux assez facilement calculer les 2 intersections du rayon sur le cercle...
Faudrait essayer ....en théorie je comprends, mais en pratique je ne suis pa sur que ça fonctionne... En tout cas merci. Si tu as une idée de code pour faire ça n'hesite pas , je vais me pencher sur le problème...mais je vois pas trop comment je vais m'y prendre... pour l'instant... :roll:
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

Si tu veux le faire avec ton algo, utilises l'algo de bresenham pour les rayons.
Ne trace qu'un point par ligne (facile de modfier l'algo ;) ). Ensuite fait un remplissage ligne par ligne en inversant la couleur à chaque fois que tu rencontres un pixel plein.
Et n'oublie pas de réduire le nb de rayons!!! Utilise une table précalculée pour le cercle ou utilise un algo de tracé de cercle (bcp, bcp plus rapide). Il y a tout ça sur le forum anglais (et partout sur internet)
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

De mémoire il me semble que le temps était semblement identique entre cet algo et la commande circle de purebasic

http://purebasic.hmt-forum.com/viewtopic.php?t=1977

Peut-être qu'il y a des optimisations à faire mais je ne sais pas lesquelles.

et pour les lignes

http://purebasic.hmt-forum.com/viewtopic.php?t=2703

J'ai pas tout lu, tu parles de lancer de rayons ,d'obstacles , etc . ça ressemble à ce que je fais en 3D, tu devrais peut-être gérer les objets dans un quadtree, et faire ton lancer de rayon avec le quadtree pour détecter les obstacles, tu vas limiter les tests.
Qu'est-ce qui prend le plus de temps dans ton prog ? la recherche des collisions ou le calcul de l'éclairage ?
Il parait que dans les progs de lancer de rayons , plus de 80% du temps est consommé par la recherche des intersections rayon/Objet, d'où l'intérêt de réduire au maximum ce temps par l'utilisation d'un quadtree en 2D ou d'un octree en 3D.

Ceci dit je devrais tout lire depuis le début , je suis peut-être à côté de la plaque là :)

[EDIT]
Tu sais que tu peux utiliser un Break à la place de ton goto ?
Enfin je pense que ça devrait faire le même effet en plus propre :)

Code : Tout sélectionner

    ;If Color>1: Goto nextAngle: :EndIf ; si c'est le cas on arrête le rayon et on passe au suivant
    Next p   
    nextAngle:
[EDIT2]

Ta méthode est peut-être plus simple et plus rapide, mais faudrait essayer pour voir ce que ça donne en faisant :

Boucle Pour tous les rayons à lancer
Test la collision du rayon pour déterminer sa longueur
Quand on connait sa longueur il n'y a plus à tester à chaque pixel un éventuel obstacle, on peut se contenter de tracer le rayon.
C'est peut-être là qu'il y a un gain en vitesse possible ? à tester
Fin de la boucle
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 : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

un petit bricolage rapide en reprenant mes fonctions
Je remettrai un peu plus en forme ce soir :)

Code : Tout sélectionner

InitSprite()
InitKeyboard()
OpenScreen(800,600,32,"")
UsePNGImageDecoder()
;LoadImage(1,"image.png")
CreateImage(2,800,600,16)
Structure s_Vecteur
   x.f
   y.f
EndStructure
Structure s_Sphere
	Origine.s_Vecteur
	Rayon.f
	DistanceCarre.f
EndStructure
Structure s_Rayon
	;Informations dans R3
	Origine.s_Vecteur
	Direction.s_Vecteur
	;Informations collisions
 	CollisionDetectee.l
 	DistanceLaPlusCourte.f
 	PointIntersection.s_Vecteur	 
EndStructure

Macro SOUSTRACTION_VECTEUR(V, V1, V2)
   V\x = V1\x - V2\x
  	V\y = V1\y - V2\y
EndMacro 

Macro NORME_AU_CARRE(V)
	 (V\x * V\x + V\y * V\y)  
EndMacro

Macro PRODUIT_SCALAIRE(V1, V2)
  	(V1\x * V2\x + V1\y * V2\y) 
EndMacro

#Rad=2*3.1415/360
Global Sphere.s_Sphere
Global Rayon.s_Rayon
Sphere\Origine\x = 300
Sphere\Origine\y = 300
Sphere\Rayon = 10
Procedure IntersectionRayonSphere()
   Define.f RayonCarre, ProjectionOrthogonale 
   Define.f DistanceCentreRayon
   Define.s_Vecteur RayonSphere
   
   SOUSTRACTION_VECTEUR(RayonSphere, Sphere\Origine, Rayon\Origine)
   Sphere\DistanceCarre = NORME_AU_CARRE(RayonSphere)	
   RayonCarre    = Sphere\Rayon * Sphere\Rayon
   
   ;L'origine du rayon est à l'intérieur de la sphère
   If Sphere\DistanceCarre <= RayonCarre 
      ;t.f = ProjectionOrthogonale + Sqr(RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale)))
      ;Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
      ;Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
      ProcedureReturn #True
   EndIf
   
   ;Projection orthogonale du centre de la sphère sur le rayon
   ProjectionOrthogonale = PRODUIT_SCALAIRE(RayonSphere, Rayon\Direction)

   If ProjectionOrthogonale < 0
      ProcedureReturn #False
   EndIf
   
   ;Calcul intermédiaire à faire dans une variable !
   If RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale)) < 0
      ProcedureReturn #False  
   EndIf
   t.f = ProjectionOrthogonale - Sqr(RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale)))
   Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
   Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
   ProcedureReturn #True
       
EndProcedure

Procedure Norme(*V.s_Vecteur)
    Norme.f = Sqr(*V\x * *V\x + *V\y * *V\y)
    If Norme= 0
        *V\x = 0
        *V\y = 0
    Else
     	*V\x / Norme
        *V\y / Norme
    EndIf
EndProcedure 

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l)
StartDrawing(ScreenOutput())
  For i = -Anglef*2 To Anglef*2 Step 2
    p = puissance
    ;For p = 0 To Puissance
      a.f=(i/4+Angle)
      X = LightX + P * Cos(a*#Rad)
      Y = LightY + P * Sin(a*#Rad)
      Rayon\Origine\x = LightX
      Rayon\Origine\y = LightY
      Rayon\Direction\x = X-LightX
      Rayon\Direction\y = Y-LightY

      Norme(@Rayon\Direction)
      
      If IntersectionRayonSphere()
      LineXY(LightX,LightY,Rayon\PointIntersection\x,Rayon\PointIntersection\y,$0000FF)
      Else
      LineXY(LightX,LightY,x,y,$0000FF)
      EndIf
      
      ;lightlevel=((Puissance-p)*255/Puissance+(255*(Anglef/2-Abs(i))/Anglef/2))/2;ça donne la forme de la luminosité
      ;If X>0 And X<800 And Y>0 And Y<600
      ;PokeL(*pixel+DrawingBufferPitch()*y+DrawingBufferPixelFormat()*x,RGB(255,0,255))
      ;    Plot(X,Y,RGB(255,255,255))
      ;EndIf
      ;On verfie maintenant si quelques choses est sur le chemin du rayon
      ;Color = Mask(X,Y)
      ;If Color>1: Goto nextAngle: :EndIf ; si c'est le cas on arrête le rayon et on passe au suivant
    ;Next p   

  Next i
StopDrawing()
EndProcedure


Repeat
ClearScreen(0)
ExamineKeyboard() 
If KeyboardPushed(#PB_Key_Up)
ElseIf KeyboardPushed(#PB_Key_Down)
EndIf
 
Light(320,300,A,30,280,RGB(255,255,255))
Light(400,250,-A,60,150,RGB(255,255,255))
A=A+1
If A>360:A=A-360:EndIf
  If Val(FormatDate("%ss", Date()))=sek
    FPS+1
  Else
    FPS$=Str(FPS)
    FPS=0
  EndIf
  sek=Val(FormatDate("%ss", Date()))
StartDrawing(ScreenOutput())
   Circle(Sphere\Origine\x,Sphere\Origine\y,Sphere\Rayon,$FF0000)
 DrawingMode(1)
    FrontColor(RGB(255,255,255))
    DrawText(320,1,"FPS: "+FPS$)
  StopDrawing()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
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
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

comtois a écrit :un petit bricolage rapide en reprenant mes fonctions
Je remettrai un peu plus en forme ce soir :)
Exelent !!!! bravo !
maintenant si tu veux poucer le vis plus loin. a la place du tracé de rayon il faudrait tracer le décore en fonction d'une image (le plus c'est avec degradé de la luminosité pour faire effet lampe torche) :P
En tout cas bravo c'est déjà formidable. (tu as dormi au moins cette nuit?)
Avant d'approfondir ton programme....j'ai trouvé une solution interessante de mon côté... j'approfondie et je poste mon code...et je prendrais le meilleur... :o)
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

On approche du but ....

en utilisant les Poke c'est 40 fois plus rapide que ma première version avec des plots...
Et je suis sur qu'on peu encore optimisé.. car j'utilise toujours le même systeme de lancer de rayon. Peut être qu'en utilisant la technique de comptois ça pourrait nettement accelerer la chose...Reste a comprendre sa technique.... Si vous voyez ou optimisé n'hesitez pas...

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard()=0 Or InitMouse()=0
  MessageRequester("Error","DirectX 7+ is needed.",0)
EndIf

Global ScreenWidth.l,ScreenHeight.l
ScreenWidth=640
ScreenHeight=480
Enumeration
#Screen
#Map
#Buffer
EndEnumeration

;Constante
#Rad=2*3.1415/360 

Structure Surface
  *Address.l
  Pitch.l
  PixelFormat.l
  Width.l
  Height.l
EndStructure

Global Dim Surface.Surface(10)

;IncludeFile("2d.pb")
OpenScreen(ScreenWidth, ScreenHeight, 32, "Aliens")
  UsePNGImageDecoder()
  LoadSprite(1,"image.png")
  CreateSprite(2,640,480)

;Initialisation des différentes surfaces
StartDrawing(ScreenOutput())
  Surface(#Screen)\Address=DrawingBuffer() 
  Surface(#Screen)\Pitch=DrawingBufferPitch()
  Surface(#Screen)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Screen)\Width=ScreenWidth
  Surface(#Screen)\Height=ScreenHeight
StopDrawing()

StartDrawing(SpriteOutput(1))
  Surface(#Map)\Address=DrawingBuffer() 
  Surface(#Map)\Pitch=DrawingBufferPitch()
  Surface(#Map)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Map)\Width=SpriteWidth(1) 
  Surface(#Map)\Height=SpriteHeight(1) 
StopDrawing()  

StartDrawing(SpriteOutput(2))
  Surface(#Buffer)\Address=DrawingBuffer() 
  Surface(#Buffer)\Pitch=DrawingBufferPitch()
  Surface(#Buffer)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Buffer)\Width=SpriteWidth(2) 
  Surface(#Buffer)\Height=SpriteHeight(2) 
StopDrawing()  

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l) 

  For i = -Anglef/2 To Anglef/2
    For p = 0 To Puissance 
      a.f=(i/2+Angle) 
      X = LightX + P * Cos(a*#Rad) 
      Y = LightY + P * Sin(a*#Rad) 
      

      If X>0 And X<Surface(#Buffer)\Width And Y>0 And Y<Surface(#Buffer)\Height 
        ;col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
        col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
        ;lightlevel=(Puissance-p)*255/Puissance
        lightlevel=(((Puissance-p)*255/Puissance+(255*(Anglef/2-Abs(i))/Anglef/2))/2);ça donne la forme de la luminosité
        If lightlevel>1 And lightlevel<156 
        red=Int(Red(col)*lightlevel/255)
        green=Int(Green(col)*lightlevel/255)
        blue=Int(Blue(col)*lightlevel/255)
        col=RGB(red,green,blue) 
        PokeL(Surface(#Buffer)\Address+x*4+Surface(#Buffer)\Pitch*y,col) 
      EndIf
      EndIf 
    Next p    
    nextAngle:  
  Next i 

EndProcedure 

Repeat
  UseBuffer(2)
  ClearScreen(0)
  UseBuffer(-1)
  Light(320,300,A,60,140,RGB(255,255,255)) 
  Light(400,250,-A,60,140,RGB(255,255,255)) 
  A=A+1 
  If A>360:A=A-360:EndIf 
   
  ExamineKeyboard()
    
  Delay(1)
    
  If Val(FormatDate("%ss", Date()))=sek
    FPS+1
  Else
    FPS$=Str(FPS)
    FPS=0
  EndIf
  sek=Val(FormatDate("%ss", Date()))
  ;Affichage
  DisplaySprite(2,0,0)
  StartDrawing(ScreenOutput()) 
    DrawingMode(1)
    FrontColor(RGB(255,255,255))
    DrawText(320,1,"FPS: "+FPS$)
  StopDrawing()
    FlipBuffers()
  Until KeyboardPushed(#PB_Key_Escape)
End  
Avatar de l’utilisateur
Progi1984
Messages : 2659
Inscription : mar. 14/déc./2004 13:56
Localisation : France > Rennes
Contact :

Message par Progi1984 »

Truc con
J'ai déplacé le calcul de a.f
Ne serait il pas plus optimisé de faire des if imbriqué au lieu de faire des if... and... and... and...

Code : Tout sélectionner

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l)

  For i = -Anglef/2 To Anglef/2
      a.f=(i/2+Angle)
    For p = 0 To Puissance
      X = LightX + P * Cos(a*#Rad)
      Y = LightY + P * Sin(a*#Rad)
     

      If X>0 And X<Surface(#Buffer)\Width And Y>0 And Y<Surface(#Buffer)\Height
        ;col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
        col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
        ;lightlevel=(Puissance-p)*255/Puissance
        lightlevel=(((Puissance-p)*255/Puissance+(255*(Anglef/2-Abs(i))/Anglef/2))/2);ça donne la forme de la luminosité
        If lightlevel>1 And lightlevel<156
        red=Int(Red(col)*lightlevel/255)
        green=Int(Green(col)*lightlevel/255)
        blue=Int(Blue(col)*lightlevel/255)
        col=RGB(red,green,blue)
        PokeL(Surface(#Buffer)\Address+x*4+Surface(#Buffer)\Pitch*y,col)
      EndIf
      EndIf
    Next p   
    nextAngle: 
  Next i

EndProcedure
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Thyphoon a écrit : (tu as dormi au moins cette nuit?)
Oui très bien :)

Il m'a fallu un quart d'heure pour faire ce code, j'avais déjà les macros et la procédure, j'ai juste supprimé le z du vecteur.

C'est tellement vite fait qu'il y a une petite erreur.
Correction rapide de la procédure Light()

Code : Tout sélectionner

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l)
Define.s_Vecteur Vecteur
StartDrawing(ScreenOutput())
  For i = -Anglef*2 To Anglef*2 
    p = puissance
      a.f=(i/4+Angle)
      X = LightX + P * Cos(a*#Rad)
      Y = LightY + P * Sin(a*#Rad)
      Rayon\Origine\x = LightX
      Rayon\Origine\y = LightY
      Rayon\Direction\x = X-LightX
      Rayon\Direction\y = Y-LightY

      Norme(@Rayon\Direction)
      
      If IntersectionRayonSphere()
         Vecteur\x = Rayon\PointIntersection\x - LightX
         Vecteur\y = Rayon\PointIntersection\y - LightY
         Distance.f = NORME_AU_CARRE(Vecteur)
         If Distance < puissance * puissance
            LineXY(LightX,LightY,Rayon\PointIntersection\x,Rayon\PointIntersection\y,$0000FF)
         Else
            LineXY(LightX,LightY,x,y,$0000FF)
         EndIf
      Else
         LineXY(LightX,LightY,x,y,$0000FF)
      EndIf
  Next i
StopDrawing()
EndProcedure
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.
AWEAR
Messages : 264
Inscription : ven. 28/oct./2005 8:20
Localisation : Mayotte ( 976 ), Océan Indien, France

Message par AWEAR »

L'ennui avec vos codes c'est qu'il reste des "trous" dans les parties éclairées, ce qui est surement du à l'utilisation de rayon, mais bon je ne suis certainement pas le mieux placé pour critiquer, car j'aurais du mal à arriver à faire ce que vous faîtes..
La vie est une rose dont il faut accepter les épines, mais la mienne est fannée, arrosée par le goût de mes larmes. (Soprano)
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Bon j'ai toujours pas étudié le code de comtois mais je pense que c'est ce que je vais faire maintenant.

voivi ce que j'ai réussi a faire grace a vous tous
mais vous avez besoin de 2 images..que voici
image.png : http://img48.imageshack.us/img48/6555/image3tp.png
mask.png : http://img163.imageshack.us/img163/9489/mask8ro.png
Parcontre il vas faloire encore plus d'optimisation...et regler les problèmes de trou dont parle Awear.
Voilà si vous trouvez d'autre moyen d'améliorer tout ça n'hesitez pas.
Là j'utilise une image fixe pour le decor...mais apres dans le jeu le decore se fabriquera avec des bloques.... POur le système de Mask qui permet de savoir si on a un objet devant le faisceau on doit aussi pouvoir améliorer.
Alors qui propose mieux ? :P

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard()=0 Or InitMouse()=0
  MessageRequester("Error","DirectX 7+ is needed.",0)
EndIf

Global ScreenWidth.l,ScreenHeight.l
ScreenWidth=640
ScreenHeight=480
Enumeration
#Screen
#Map
#Mask
#Buffer
EndEnumeration

;Constante
#Rad=2*3.1415/360 

Structure Surface
  *Address.l
  Pitch.l
  PixelFormat.l
  Width.l
  Height.l
EndStructure

Global Dim Surface.Surface(10)

;IncludeFile("2d.pb")
OpenScreen(ScreenWidth, ScreenHeight, 32, "Aliens")
  UsePNGImageDecoder()
  LoadSprite(1,"image.png")
  LoadSprite(2,"mask.png")
  CreateSprite(3,640,480)

;Initialisation des différentes surfaces
StartDrawing(ScreenOutput())
  Surface(#Screen)\Address=DrawingBuffer() 
  Surface(#Screen)\Pitch=DrawingBufferPitch()
  Surface(#Screen)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Screen)\Width=ScreenWidth
  Surface(#Screen)\Height=ScreenHeight
StopDrawing()

StartDrawing(SpriteOutput(1))
  Surface(#Map)\Address=DrawingBuffer() 
  Surface(#Map)\Pitch=DrawingBufferPitch()
  Surface(#Map)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Map)\Width=SpriteWidth(1) 
  Surface(#Map)\Height=SpriteHeight(1) 
StopDrawing()  

StartDrawing(SpriteOutput(2))
  Surface(#Mask)\Address=DrawingBuffer() 
  Surface(#Mask)\Pitch=DrawingBufferPitch()
  Surface(#Mask)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Mask)\Width=SpriteWidth(2) 
  Surface(#Mask)\Height=SpriteHeight(2) 
StopDrawing()  


StartDrawing(SpriteOutput(3))
  Surface(#Buffer)\Address=DrawingBuffer() 
  Surface(#Buffer)\Pitch=DrawingBufferPitch()
  Surface(#Buffer)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Buffer)\Width=SpriteWidth(3) 
  Surface(#Buffer)\Height=SpriteHeight(3) 
StopDrawing()  

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l) 
  Dim MemPlot.b(640,480)  ; Un petit tableau pour verifier si la pixel au coordonée x et y du faisceau lumineux a déjà été traité
  For i = -Anglef/2 To Anglef/2 Step 1 
    a.f=(i/2+Angle) 
    f.l=0
    For p = 0 To Puissance 
      ;Calcul des coordonées X et Y a traité
      X = LightX + P * Cos(a*#Rad) 
      Y = LightY + P * Sin(a*#Rad) 
      ;On verifie si on tombe sur un obstacle: col=0,0,0 pas d'obstacte / col=255,255,255 il y a un obstacle 
      Obstacle=PeekL(Surface(#Mask)\Address+x*4+Surface(#Map)\Pitch*y)
      If Obstacle=0 Or f<10 ;Si il n'ya pas d'obstacle alors on trace (col=0) / si f>0 c'est qu'on a trouvé un obstacle mais il faut l'illuminé
        If Obstacle>0 Or f>0:f=f+1:EndIf ;Si on a trouvé un obstacle on l'illumine            
        If MemPlot(X,Y)=0 ; si cette pixel n'a pas été traité on la traite
          ;On verifie qu'on est bien dans les limites
          If X>0 And X<Surface(#Buffer)\Width And Y>0 And Y<Surface(#Buffer)\Height
            ;Je prélève la couleur dans le buffer au cas ou une autre source lumineuse serait déjà dans le coin 
            colb=PeekL(Surface(#Buffer)\Address+x*4+Surface(#Map)\Pitch*y)
            ;Je prend la couleur dans le decor
            col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
            If f=0 Or Obstacle=0
              ;si on a pas encore trouvé d'obstacle alors on calcul l'éclairage
              ;lightlevel=(Puissance-p)*255/Puissance
              lightlevel=(((Puissance-p)*255/Puissance+(255*(Anglef/2-Abs(i))/Anglef/2))/2);ça donne la forme de la luminosité
            Else
              ;si on a trouvé un obstacle on calcul l'illumination de cet objet
              lightlevel=255-(f*255/10)
            EndIf  
            ;il faut qu'il y est un minimum d'éclairage pour aller plus loin           
            If lightlevel>1 And lightlevel<256 
              ;Calcul de la couleur de la pixem
              red=(Red(col)*Red(Color)*lightlevel)/65025
              green=(Green(col)*Green(Color)*lightlevel)/65025
              blue=(Blue(col)*Blue(Color)*lightlevel)/65025
              ;col=RGB(red,green,blue)
              ;Melange de faisceau lumineux
              If Red(colb)>red:red=Red(colb):Else:red=red:EndIf
              If Green(colb)>green:green=Green(colb):Else:green=green:EndIf
              If Blue(colb)>blue:blue=Blue(colb):Else:blue=blue:EndIf
              col=RGB(red,green,blue)
              ;Je mémorise que cette pixel a été traité pour ce faisceau là
              MemPlot(X,Y)=1
              ;Hop on affiche dans le buffer le pixel
              PokeL(Surface(#Buffer)\Address+x*4+Surface(#Buffer)\Pitch*y,col) 
            EndIf
          EndIf 
        EndIf
      Else
        Break;
      EndIf
    Next p    
  Next i 
EndProcedure 

Repeat
  UseBuffer(3)
  ClearScreen(0)
  UseBuffer(-1)
  Light(250,250,A+120,90,150,RGB(255,255,255)) 
  Light(400,200,-A,90,90,RGB(255,255,255)) 
  Light(200,240,180+A,25,150,RGB(100,100,255))
  Light(200,240,A,25,150,RGB(100,100,255))  
  ;Trace()
  A=A+1 
  If A>360:A=A-360:EndIf 
   
  ExamineKeyboard()
    
  Delay(1)
   
  If Val(FormatDate("%ss", Date()))=sek
    FPS+1
  Else
    FPS$=Str(FPS)
    Time$=Str(ElapsedMilliseconds()-Elapsetime)
    FPS=0
  EndIf
  sek=Val(FormatDate("%ss", Date()))
  ;Affichage
  DisplaySprite(3,0,0)
  StartDrawing(ScreenOutput()) 
    DrawingMode(1)
    FrontColor(RGB(255,255,255))
    DrawText(320,1,"FPS: "+FPS$+" Time:"+Time$)
    Elapsetime=ElapsedMilliseconds()
  StopDrawing()
    FlipBuffers()
  Until KeyboardPushed(#PB_Key_Escape)
End  
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Je n'ai pas reussi a intégré le code de comtois ni a utilisé l'algo de bresenham dans les 2 cas je ne comprends pas comment je peu les intégrés le raisonement étant différent.(ou alors j'ai pas tout pigé)
Quelqu'un pourrait-il m'aider ?

EDIT: j'ai trouvé comment gagner encore quelques FPS
-en utilisante une table pour les COS et SIN c'est pas flagrant
-en utilisant un tableau comme buffer pour le croisement des faisceaux lumineux
-Et des toutes petites obtimisations dans les calcules
Au total j'ai gagner 5 FPS sur ma machine...et ça tourne a 42 FPS lorsque je desactive le debugger dans la compilation... Mais j'ai pas encore réussi a améliorer mon lancer de rayon.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Chez moi ta démo tourne à 17.


Bon un petit code qui ne te sera pas utile, mais je ne vais pas le jeter alors autant le mettre là :)

J'ai voulu tester avec la fonction de remplissage, AWEAR devrait être content il n'y a plus de trou, mais le FPS en prend un coup !!
Du coup je l'ai mis en commentaire, pour voir ce que ça donne
validez la ligne avec le FillArea()

Code : Tout sélectionner

InitSprite()
InitKeyboard()
OpenScreen(800,600,32,"")
UsePNGImageDecoder()
;LoadImage(1,"image.png")
CreateImage(2,800,600,16)
Structure s_Vecteur
   x.f
   y.f
EndStructure
Structure s_Sphere
	Origine.s_Vecteur
	Rayon.f
	DistanceCarre.f
EndStructure
Structure s_Rayon
	;Informations dans R3
	Origine.s_Vecteur
	Direction.s_Vecteur
	;Informations collisions
 	CollisionDetectee.l
 	DistanceLaPlusCourte.f
 	PointIntersection.s_Vecteur	 
EndStructure

Macro SOUSTRACTION_VECTEUR(V, V1, V2)
   V\x = V1\x - V2\x
  	V\y = V1\y - V2\y
EndMacro 

Macro NORME_AU_CARRE(V)
	 (V\x * V\x + V\y * V\y)  
EndMacro

Macro PRODUIT_SCALAIRE(V1, V2)
  	(V1\x * V2\x + V1\y * V2\y) 
EndMacro

#Rad=2*3.1415/360
Global Sphere.s_Sphere
Global Rayon.s_Rayon
Sphere\Origine\x = 400
Sphere\Origine\y = 300
Sphere\Rayon = 60
Procedure IntersectionRayonSphere()
   Define.f RayonCarre, ProjectionOrthogonale 
   Define.f DistanceCentreRayon
   Define.s_Vecteur RayonSphere
   
   SOUSTRACTION_VECTEUR(RayonSphere, Sphere\Origine, Rayon\Origine)
   Sphere\DistanceCarre = NORME_AU_CARRE(RayonSphere)	
   RayonCarre    = Sphere\Rayon * Sphere\Rayon
   
   ;L'origine du rayon est à l'intérieur de la sphère
   If Sphere\DistanceCarre <= RayonCarre 
      t.f = ProjectionOrthogonale + Sqr(RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale)))
      Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
      Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
      ProcedureReturn #True
   EndIf
   
   ;Projection orthogonale du centre de la sphère sur le rayon
   ProjectionOrthogonale = PRODUIT_SCALAIRE(RayonSphere, Rayon\Direction)

   If ProjectionOrthogonale < 0
      ProcedureReturn #False
   EndIf
   
   ;Calcul intermédiaire à faire dans une variable !
   CalculIntermediaire.f = RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale))
   If CalculIntermediaire < 0
      ProcedureReturn #False  
   EndIf
   t.f = ProjectionOrthogonale - Sqr(CalculIntermediaire)
   Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
   Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
   ProcedureReturn #True
       
EndProcedure

Procedure Norme(*V.s_Vecteur)
    Norme.f = Sqr(*V\x * *V\x + *V\y * *V\y)
    If Norme= 0
        *V\x = 0
        *V\y = 0
    Else
     	*V\x / Norme
        *V\y / Norme
    EndIf
EndProcedure 

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l)
   Define.s_Vecteur Vecteur
   Rayon\Origine\x = LightX
   Rayon\Origine\y = LightY
   OldX.f = LightX
   OldY.f = LightY
   
   ;StartDrawing(ScreenOutput())
      i.f=-Anglef*2
      While i < Anglef*2 
         a.f=(i/4+Angle)
         X = LightX + puissance * Cos(a*#Rad)
         Y = LightY + puissance * Sin(a*#Rad)

         Rayon\Direction\x = X-LightX
         Rayon\Direction\y = Y-LightY

         Norme(@Rayon\Direction)
      
         If IntersectionRayonSphere()
            Vecteur\x = Rayon\PointIntersection\x - LightX
            Vecteur\y = Rayon\PointIntersection\y - LightY
            Distance.f = NORME_AU_CARRE(Vecteur)
            If Distance < puissance * puissance
               LineXY(OldX,OldY,Rayon\PointIntersection\x,Rayon\PointIntersection\y,$0000FF)
               OldX = Rayon\PointIntersection\x
               OldY = Rayon\PointIntersection\y
            Else
               LineXY(OldX, OldY, x, y, $0000FF)
               OldX = x
               OldY = y
            EndIf
         Else
            LineXY(OldX, OldY,x,y,$0000FF)
            OldX = x
            OldY = y
         EndIf
         i + 3
      Wend
      LineXY(OldX, OldY,LightX,LightY,$0000FF)
      Fx.f = LightX + 5 * Cos(angle*#Rad)
      Fy.f = LightY + 5 * Sin(angle*#Rad)
      ;FillArea(Fx,Fy,$0000FF,$00FFFF)
   ;StopDrawing()
   
EndProcedure


Repeat
   ClearScreen(0)
   ExamineKeyboard() 

   A + 1
   If A > 360 : A = A - 360 : EndIf
   If Val(FormatDate("%ss", Date()))=sek
      FPS+1
   Else
      FPS$=Str(FPS)
      FPS=0
   EndIf
   sek=Val(FormatDate("%ss", Date()))
   StartDrawing(ScreenOutput())
      Circle(Sphere\Origine\x,Sphere\Origine\y,Sphere\Rayon,$FF0000)
    
      Light(280,300,A,90,180,RGB(255,255,255))
      Light(500,300,-A,90,250,RGB(255,255,255))
      Light(Sphere\Origine\x,Sphere\Origine\y,-A,60,250,RGB(255,255,255))
      DrawingMode(1)
      FrontColor(RGB(255,255,255))
      DrawText(320,1,"FPS: "+FPS$)
   StopDrawing()
   FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
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 : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

J'ai fait un essai avec ton code
Chez moi le FPS est à 17.
Si j'enlève le test de l'obstacle, le FPS monte à 25.
;Obstacle=PeekL(Surface(#Mask)\Address+x*4+Surface(#Map)\Pitch*y)
Alors j'ai essayé avec un cercle et le lancer de rayon sur un cercle, et le FPS reste à 25 et l'obstacle est bien pris en compte.
Si ça t'intéresse je peux te filer le code pour le calcul de l'intersection d'un rayon et d'une boite, apparemment c'est ce que tu utilises dans ton code.
Faudrait que je complète ma procédure, elle ne calcule pas le point d'intersection parce que je n'en avais pas besoin, mais je peux l'ajouter.

bien sûr , ici il n'y a qu'un obstacle, quand il y en aura plusieurs, il faudra faire une boucle, le FPS risque d'en prendre un coup aussi ?
Enfin il y a de la marge par rapport à ton test à chaque pixel , j'ai gagné 8 points, presque 1/3 .

Code : Tout sélectionner

If InitSprite() = 0 Or InitKeyboard()=0 Or InitMouse()=0
  MessageRequester("Error","DirectX 7+ is needed.",0)
EndIf

Global ScreenWidth.l,ScreenHeight.l
ScreenWidth=640
ScreenHeight=480
Enumeration
#Screen
#Map
#Mask
#Buffer
EndEnumeration

;Constante
#Rad=2*3.1415/360

Structure Surface
  *Address.l
  Pitch.l
  PixelFormat.l
  Width.l
  Height.l
EndStructure
Structure s_Vecteur
   x.f
   y.f
EndStructure
Structure s_Sphere
	Origine.s_Vecteur
	Rayon.f
	DistanceCarre.f
EndStructure
Structure s_Rayon
	;Informations dans R3
	Origine.s_Vecteur
	Direction.s_Vecteur
	;Informations collisions
 	CollisionDetectee.l
 	DistanceLaPlusCourte.f
 	PointIntersection.s_Vecteur	 
EndStructure

Macro SOUSTRACTION_VECTEUR(V, V1, V2)
   V\x = V1\x - V2\x
  	V\y = V1\y - V2\y
EndMacro 

Macro NORME_AU_CARRE(V)
	 (V\x * V\x + V\y * V\y)  
EndMacro

Macro PRODUIT_SCALAIRE(V1, V2)
  	(V1\x * V2\x + V1\y * V2\y) 
EndMacro

Global Dim Surface.Surface(10)

;IncludeFile("2d.pb")
OpenScreen(ScreenWidth, ScreenHeight, 32, "Aliens")
  UsePNGImageDecoder()
  LoadSprite(1,"image.png")
  LoadSprite(2,"mask.png")
  CreateSprite(3,640,480)

;Initialisation des différentes surfaces
StartDrawing(ScreenOutput())
  Surface(#Screen)\Address=DrawingBuffer()
  Surface(#Screen)\Pitch=DrawingBufferPitch()
  Surface(#Screen)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Screen)\Width=ScreenWidth
  Surface(#Screen)\Height=ScreenHeight
StopDrawing()

StartDrawing(SpriteOutput(1))
  Surface(#Map)\Address=DrawingBuffer()
  Surface(#Map)\Pitch=DrawingBufferPitch()
  Surface(#Map)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Map)\Width=SpriteWidth(1)
  Surface(#Map)\Height=SpriteHeight(1)
StopDrawing() 

StartDrawing(SpriteOutput(2))
  Surface(#Mask)\Address=DrawingBuffer()
  Surface(#Mask)\Pitch=DrawingBufferPitch()
  Surface(#Mask)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Mask)\Width=SpriteWidth(2)
  Surface(#Mask)\Height=SpriteHeight(2)
StopDrawing() 


StartDrawing(SpriteOutput(3))
  Surface(#Buffer)\Address=DrawingBuffer()
  Surface(#Buffer)\Pitch=DrawingBufferPitch()
  Surface(#Buffer)\PixelFormat=DrawingBufferPixelFormat()
  Surface(#Buffer)\Width=SpriteWidth(3)
  Surface(#Buffer)\Height=SpriteHeight(3)
StopDrawing() 
Global Sphere.s_Sphere
Global Rayon.s_Rayon
Sphere\Origine\x = 350
Sphere\Origine\y = 300
Sphere\Rayon = 60
Procedure IntersectionRayonSphere()
   Define.f RayonCarre, ProjectionOrthogonale 
   Define.f DistanceCentreRayon
   Define.s_Vecteur RayonSphere
   
   SOUSTRACTION_VECTEUR(RayonSphere, Sphere\Origine, Rayon\Origine)
   Sphere\DistanceCarre = NORME_AU_CARRE(RayonSphere)	
   RayonCarre    = Sphere\Rayon * Sphere\Rayon
   
   ;L'origine du rayon est à l'intérieur de la sphère
   If Sphere\DistanceCarre <= RayonCarre 
      t.f = ProjectionOrthogonale + Sqr(RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale)))
      Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
      Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
      ProcedureReturn #True
   EndIf
   
   ;Projection orthogonale du centre de la sphère sur le rayon
   ProjectionOrthogonale = PRODUIT_SCALAIRE(RayonSphere, Rayon\Direction)

   If ProjectionOrthogonale < 0
      ProcedureReturn #False
   EndIf
   
   ;Calcul intermédiaire à faire dans une variable !
   CalculIntermediaire.f = RayonCarre - (Sphere\DistanceCarre - (ProjectionOrthogonale * ProjectionOrthogonale))
   If CalculIntermediaire < 0
      ProcedureReturn #False  
   EndIf
   t.f = ProjectionOrthogonale - Sqr(CalculIntermediaire)
   Rayon\PointIntersection\x = Rayon\Origine\x + t * Rayon\Direction\x
   Rayon\PointIntersection\y = Rayon\Origine\y + t * Rayon\Direction\y
   ProcedureReturn #True
       
EndProcedure

Procedure Norme(*V.s_Vecteur)
    Norme.f = Sqr(*V\x * *V\x + *V\y * *V\y)
    If Norme= 0
        *V\x = 0
        *V\y = 0
    Else
     	*V\x / Norme
        *V\y / Norme
    EndIf
EndProcedure 

Procedure Light(LightX.l,LightY.l,Angle.l,Anglef.l,Puissance.l,Color.l)
  Define Vecteur.s_Vecteur
  Dim MemPlot.b(640,480)  ; Un petit tableau pour verifier si la pixel au coordonée x et y du faisceau lumineux a déjà été traité
  p = puissance
     Rayon\Origine\x = LightX
   Rayon\Origine\y = LightY
  For i = -Anglef/2 To Anglef/2 Step 1
    a.f=(i/2+Angle)
    f.l=0
    
      ;Calcul des coordonées X et Y a traité
      X = LightX + P * Cos(a*#Rad)
      Y = LightY + P * Sin(a*#Rad)
      
         Rayon\Direction\x = X-LightX
         Rayon\Direction\y = Y-LightY

         Norme(@Rayon\Direction)
      
         If IntersectionRayonSphere()
            Vecteur\x = Rayon\PointIntersection\x - LightX
            Vecteur\y = Rayon\PointIntersection\y - LightY
            Distance.f = Sqr(NORME_AU_CARRE(Vecteur))
            If Distance > puissance 
               Distance = puissance
            EndIf
         Else
             Distance = puissance
         EndIf

      For p = 0 To Int(Distance)   
            ;Calcul des coordonées X et Y a traité
      X = LightX + P * Cos(a*#Rad)
      Y = LightY + P * Sin(a*#Rad)
      
      ;On verifie si on tombe sur un obstacle: col=0,0,0 pas d'obstacte / col=255,255,255 il y a un obstacle
      ;Obstacle=PeekL(Surface(#Mask)\Address+x*4+Surface(#Map)\Pitch*y)
      If Obstacle=0 Or f<10 ;Si il n'ya pas d'obstacle alors on trace (col=0) / si f>0 c'est qu'on a trouvé un obstacle mais il faut l'illuminé
        If Obstacle>0 Or f>0:f=f+1:EndIf ;Si on a trouvé un obstacle on l'illumine           
        If MemPlot(X,Y)=0 ; si cette pixel n'a pas été traité on la traite
          ;On verifie qu'on est bien dans les limites
          If X>0 And X<Surface(#Buffer)\Width And Y>0 And Y<Surface(#Buffer)\Height
            ;Je prélève la couleur dans le buffer au cas ou une autre source lumineuse serait déjà dans le coin
            colb=PeekL(Surface(#Buffer)\Address+x*4+Surface(#Map)\Pitch*y)
            ;Je prend la couleur dans le decor
            col=PeekL(Surface(#Map)\Address+x*4+Surface(#Map)\Pitch*y)
            If f=0 Or Obstacle=0
              ;si on a pas encore trouvé d'obstacle alors on calcul l'éclairage
              ;lightlevel=(Puissance-p)*255/Puissance
              lightlevel=(((Puissance-p)*255/Puissance+(255*(Anglef/2-Abs(i))/Anglef/2))/2);ça donne la forme de la luminosité
            Else
              ;si on a trouvé un obstacle on calcul l'illumination de cet objet
              lightlevel=255-(f*255/10)
            EndIf 
            ;il faut qu'il y est un minimum d'éclairage pour aller plus loin           
            If lightlevel>1 And lightlevel<256
              ;Calcul de la couleur de la pixem
              red=(Red(col)*Red(Color)*lightlevel)/65025
              green=(Green(col)*Green(Color)*lightlevel)/65025
              blue=(Blue(col)*Blue(Color)*lightlevel)/65025
              ;col=RGB(red,green,blue)
              ;Melange de faisceau lumineux
              If Red(colb)>red:red=Red(colb):Else:red=red:EndIf
              If Green(colb)>green:green=Green(colb):Else:green=green:EndIf
              If Blue(colb)>blue:blue=Blue(colb):Else:blue=blue:EndIf
              col=RGB(red,green,blue)
              ;Je mémorise que cette pixel a été traité pour ce faisceau là
              MemPlot(X,Y)=1
              ;Hop on affiche dans le buffer le pixel
              PokeL(Surface(#Buffer)\Address+x*4+Surface(#Buffer)\Pitch*y,col)
            EndIf
          EndIf
        EndIf
      Else
        Break;
      EndIf
    Next p   
  Next i
EndProcedure

Repeat
  UseBuffer(3)
  ClearScreen(0)
  UseBuffer(-1)
  Light(250,250,A+120,90,150,RGB(255,255,255))
  Light(400,200,-A,90,90,RGB(255,255,255))
  Light(200,240,180+A,25,150,RGB(100,100,255))
  Light(200,240,A,25,150,RGB(100,100,255)) 
  ;Trace()
  A=A+1
  If A>360:A=A-360:EndIf
   
  ExamineKeyboard()
   
  Delay(1)
   
  If Val(FormatDate("%ss", Date()))=sek
    FPS+1
  Else
    FPS$=Str(FPS)
    Time$=Str(ElapsedMilliseconds()-Elapsetime)
    FPS=0
  EndIf
  sek=Val(FormatDate("%ss", Date()))
  ;Affichage
  DisplaySprite(3,0,0)
  StartDrawing(ScreenOutput())
    DrawingMode(1)
    FrontColor(RGB(255,255,255))
    DrawText(320,1,"FPS: "+FPS$+" Time:"+Time$)
    Elapsetime=ElapsedMilliseconds()
    ;Circle(Sphere\Origine\x,Sphere\Origine\y,Sphere\Rayon,$FF0000)
  StopDrawing()
    FlipBuffers()
  Until KeyboardPushed(#PB_Key_Escape)
End 
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
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

comtois a écrit :Chez moi ta démo tourne à 17.
Avec le debugger ou sans ? tu as quoi comme machine ?

Bon un petit code qui ne te sera pas utile, mais je ne vais pas le jeter alors autant le mettre là :)

J'ai voulu tester avec la fonction de remplissage, AWEAR devrait être content il n'y a plus de trou, mais le FPS en prend un coup !!
Du coup je l'ai mis en commentaire, pour voir ce que ça donne
validez la ligne avec le FillArea()
[/quote]
En tout cas c'est super ... :o) lol
Répondre