Défi Fonction 2D d'éclairage super optimisé
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...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...

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)
Ne trace qu'un point par ligne (facile de modfier l'algo

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)
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
[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.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:
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.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
un petit bricolage rapide en reprenant mes fonctions
Je remettrai un peu plus en forme ce soir
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.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Exelent !!!! bravo !comtois a écrit :un petit bricolage rapide en reprenant mes fonctions
Je remettrai un peu plus en forme ce soir![]()
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)

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...

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...
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
- Progi1984
- Messages : 2659
- Inscription : mar. 14/déc./2004 13:56
- Localisation : France > Rennes
- Contact :
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...
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
Librairies & Applications : https://www.purebasic.fr/french/viewtop ... f=8&t=6220
Site Web : https://rootslabs.net
Site Web : https://rootslabs.net
Oui très bienThyphoon a écrit : (tu as dormi au moins cette nuit?)

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.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
-
- Messages : 264
- Inscription : ven. 28/oct./2005 8:20
- Localisation : Mayotte ( 976 ), Océan Indien, France
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)
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 ?
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 ?

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
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.
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.
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()
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.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
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.
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 .
Chez moi le FPS est à 17.
Si j'enlève le test de l'obstacle, le FPS monte à 25.
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.;Obstacle=PeekL(Surface(#Mask)\Address+x*4+Surface(#Map)\Pitch*y)
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.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avec le debugger ou sans ? tu as quoi comme machine ?comtois a écrit :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()
[/quote]
En tout cas c'est super ...
