Page 1 sur 1

Tut [OpenGL 03] Texture animée dans un cube

Publié : mar. 06/nov./2007 2:18
par Buckethead
Salut :)

Je débute l'OpenGL et j'ai vraiment apprécié les tutos de Cpl.Bator. Je compte faire beaucoup d'OpenGL cette année, peut être même toucher à Opengl 2.0 et + ;\ (il faut importer des instructions?)
J'espère qu'il y aura d'autre tutos !

Image
Le fichier compilé + bonus : http://stanz05.free.fr/blobs.zip
Les includes: http://purebasic.myftp.org/?filename=fi ... OpenGL.rar

La source est très proche du "hello world" des premiers tutos. Pour mettre d'autre textures, il faudra faire comme dans le tuto précédant. Si c'est un problème, n'hésitez pas.
Pour l'effet "metaball" ou "blob", n'en tenez pas trop compte, autrement c'est juste une formule qui se dessine au point par point*, comme certains plasmas.
*idéal avec la routine LoadAlphaTexture
Il y a évidement d'autre méthodes, je sais que l'on peut copier une zone de l'écran. Perso je n'ai pas encore essayé, ca doit être très interressant pour faire des mirroirs ou l'effet "glow".
Pour l'instant je prèfère m'attaquer aux lumières ainsi qu'au "points" qui ont besoin d'OpenGL 2.0 si on veut leurs appliquer une texture. (éffet neige saybientonoyel) :|

merci Cpl.Bator. ;)

Code : Tout sélectionner

; Tut [OpenGL 03] Texture animée dans un cube.
;                   ou "texture procédurale"
; Il y a plusieurs méthodes, étant moi même débutant, je prèfère pour le moment m'exercer sur des choses simple.
;                                               - - - - -
; Les tutos OpenGL de Cpl.Bator:
; Tut [OPENGL 01] Cube3D :                 -----> http://www.purebasic.fr/french/viewtopic.php?t=5334
; Tut [OpenGL 02] Les bases du texturing   -----> http://www.purebasic.fr/french/viewtopic.php?t=5339&highlight=tut+opengl





;- # INIT
;---------------------------------------------------------------------------------------------------------------------------------------------------
IncludeFile "OpenGl.Pb"

; On déclare les procédures en bas du code, tuto de Cpl.Bator ;)
Declare Dessiner()
Declare LoadAlphaTexture(id) ; id sert ici à incrémenter la variable pour la metaball. (la texture animée)

; Le buffer pour la texture "metaball"
; Initialement j'avais utilisé pleins d'instructions pour dessinner dans "l'image" dans la proc Loadalphatexture.
; c'était inutile mais curieusement si je retire createimage, la demo est beaucoup plus lente.
CreateImage(1,128,128)
;---------------------------------------------------------------------------------------------------------------------------------------------------





;- # GL FENETRE
;---------------------------------------------------------------------------------------------------------------------------------------------------
; Ouvre une window maximizée (plein écran mais pas un Fullscreen) en fonction de la résolution du bureau.
; Sans bordure ni titlebar, l'avantage c'est d'être (normallement) en resolution native sur les LCD's
; Par contre un petit dialog affichant les résolutions c'est mieux ;)
; Auld's "4kb framework" pb-conversion by benny!weltenkonstrukteur.de (Thx Benny)
ExamineDesktops()
Sx = DesktopWidth(0)
Sy = DesktopHeight(0) 
pfd.PIXELFORMATDESCRIPTOR
pfd\cColorBits  = 32
pfd\cDepthBits  = 32
pfd\dwFlags     = #PFD_SUPPORT_OPENGL | #PFD_DOUBLEBUFFER 
hDC = GetDC_ ( CreateWindow_("edit", 0, #WS_POPUP | #WS_VISIBLE | #WS_MAXIMIZE, 0, 0 ,0 ,0, 0 ,0 ,0, 0 ) )
SetPixelFormat_ ( hDC, ChoosePixelFormat_( hDC, pfd), pfd )
wglMakeCurrent_ ( hDC, wglCreateContext_(hDC) )
ShowCursor_(#False); 
;---------------------------------------------------------------------------------------------------------------------------------------------------




;- # GL INIT
;---------------------------------------------------------------------------------------------------------------------------------------------------
glMatrixMode_(#GL_PROJECTION) 

; Important, Sx/Sy c'est le ratio pour le moniteur. Sur un 22" wide LCD et un 17" 4/3 RTC un cube n'est plus forcement carré en fonction du ratio.
; En 1600*1200, ratio = 1.66. 1.3 est plus courant.
; 500 c'est le clipping sur Z (au fond)
; On met 1 de preference pour le clipping devant. Notez que ce sont des chiffres positif.
; 52 le "field of view angle" ou FOV, tentez d'autre valeurs, plus c'est petit plus on tend vers une perspective orthogonale.
gluPerspective_(52,Sx/Sy,1,500)

glMatrixMode_(#GL_MODELVIEW)
glEnable_(#GL_TEXTURE_2D) 
glHint_(#GL_PERSPECTIVE_CORRECTION_HINT,#GL_NICEST) ; Correction de perspective pour le mapping (Obligatoire avec les damiers, "checkerboard" ;p)
 
glEnable_(#GL_DEPTH_TEST) ;Z buffer, car il y a plusieurs cube (entre autre)
glEnable_(#GL_CULL_FACE) ; Back face culling, on aura jamais plus de 3 faces sur un cube à afficher grace à cette technique.

; Comme je ne maitrise pas les lumières, qui semblent devoir être "controllées" comme le objets, j'utilise le FOG
; qui est facile à implémenter.
; Le fog, R,G,B et Alpha. Puis l'intensité.
Dim fFogColor.f(4) : fFogColor(0) = 0.05: fFogColor(1) = 0.025 : fFogColor(2) = 0.035 : fFogColor(3) = 0.0
fFogDensity.f = 0.02
glEnable_ (#GL_FOG)
glFogi_ (#GL_FOG_MODE, #GL_EXP2)
glFogfv_ (#GL_FOG_COLOR,  fFogColor());
glFogf_ (#GL_FOG_DENSITY, fFogDensity.f);
glHint_ (#GL_FOG_HINT, #GL_NICEST);
;---------------------------------------------------------------------------------------------------------------------------------------------------




;- # MAIN
;---------------------------------------------------------------------------------------------------------------------------------------------------
Repeat 
angle+1

;Appel de la routine qui "charge" la texture. Elle ne lira rien sur le disque dur, vue que c'est une texture générée en temps réel.
  LoadAlphaTexture(angle) ; texture metaball 2D, angle sert juste à incrémenter l'effet (variable à double emploi)


  

; On efface l'écran avec de la couleur.
; Notez que j'ai rencontré un problème avec les premier tutos et mes routines, il manquait #GL_COLOR_BUFFER_BIT.
glClearColor_(0.2 ,0.0 , 0.1  ,0)
glClear_(#GL_DEPTH_BUFFER_BIT | #GL_COLOR_BUFFER_BIT ) 


;- ## Caméra
glLoadIdentity_( ) 
gluLookAt_(45,0,0,0,0,0,0,0,1)              ; position
glRotated_(360*Sin(angle/512),0.0,1.0,0.0)  ; mal de mer 
;glRotated_(360*Sin(angle/256),0.0,0.0,1.0) ; donnait l'illusion que les cubes tournent autour du plus gros.


;- ## Ceinture de petits cubes 

glEnable_ (#GL_FOG)

For t = 0 To 24
glPushMatrix_() ; pose la matrice courante sur une pile.

; Pas la meilleur technique, mais ca permet quand même de faire tourner les cubes, au lieu de le faire via la caméra.
glTranslatef_(0,0,0)
glRotated_(angle,0.0,0.0,1.0) 

glTranslatef_(26*Cos(t/4),26*Sin(t/4),0)

glRotated_(360/24*t,0.0,0.0,1.0) ; angle pour que les cubes se suivent

Dessiner() ; Dessine le cube
 
glPopMatrix_() ; récupère la matrice courante sur une pile. Ce qui revient à retrouver la matrice précedente pour la boucle.
Next



;-## Big Cube
glDisable_ (#GL_FOG) ; je trouve que ca ne va pas avec le cube du milieu.
glRotatef_(360*Abs(Sin(angle/200+t)),0.0,0.0,1.0) 

glScalef_(10,10,10) ; Le cube est grossi
Dessiner() 



; Vsync et sortie/gestion clavier
  SwapBuffers_ ( hDC )
Until (GetAsyncKeyState_(#VK_ESCAPE))
End

;---------------------------------------------------------------------------------------------------------------------------------------------------



; Les procs
; Merci Cpl.Bator 
; J'ai ajouté les normales, pour les lumières...


Procedure Dessiner() 

glBegin_(#GL_QUADS) 

;glNormal3d_(-1.0,0.0,0.0) ;face gauche
glTexCoord2d_(0,1) : glVertex3d_(-1,1,1)
glTexCoord2d_(0,0) : glVertex3d_(-1,1,-1)
glTexCoord2d_(1,0) : glVertex3d_(-1,-1,-1)
glTexCoord2d_(1,1) : glVertex3d_(-1,-1,1)

;glNormal3d_(0.0,1.0,0.0) ;face haut
glTexCoord2d_(0,1) : glVertex3d_(-1,1,1)
glTexCoord2d_(0,0) : glVertex3d_(1,1,1)
glTexCoord2d_(1,0) : glVertex3d_(1,1,-1)
glTexCoord2d_(1,1) : glVertex3d_(-1,1,-1)

;glNormal3d_(0.0,-1.0,0.0) ;face bas
glTexCoord2d_(0,1) : glVertex3d_(-1,-1,1)
glTexCoord2d_(0,0) : glVertex3d_(-1,-1,-1)
glTexCoord2d_(1,0) : glVertex3d_(1,-1,-1)
glTexCoord2d_(1,1) : glVertex3d_(1,-1,1)

;glNormal3d_(0.0,0.0,-1.0) ;face arriere
glTexCoord2d_(0,1) : glVertex3d_(1,1,-1)
glTexCoord2d_(0,0) : glVertex3d_(1,-1,-1) 
glTexCoord2d_(1,0) : glVertex3d_(-1,-1,-1)
glTexCoord2d_(1,1) : glVertex3d_(-1,1,-1)

;glNormal3d_(1.0,0.0,0.0) ;face gauche
glTexCoord2d_(0,1) : glVertex3d_(1,1,1)
glTexCoord2d_(0,0) : glVertex3d_(1,-1,1)
glTexCoord2d_(1,0) : glVertex3d_(1,-1,-1)
glTexCoord2d_(1,1) : glVertex3d_(1,1,-1)

;glNormal3d_(0.0,0.0,1.0) ; Face avant
glTexCoord2d_(0,1) : glVertex3d_(-1,1,1)
glTexCoord2d_(0,0) : glVertex3d_(-1,-1,1)
glTexCoord2d_(1,0) : glVertex3d_(1,-1,1)
glTexCoord2d_(1,1) : glVertex3d_(1,1,1)

glEnd_() 
 
EndProcedure 


; La texture = 128*128, plus vraiment Alpha ;P
Procedure LoadAlphaTexture(id) 
  ;img.l = 1
  Width.l  = 128
  Height.l = 128 
  Size.l   = Width * Height 

  Dim ImageData.b(Size*4) 
  


   For y = 0 To 127
     n = 64*id ; pour la metaball
      For x = 0 To 127
 
 ; Calcul metaball (3 dans c) 
 k.f = -8 * Sin(2*n/4192)
 l.f = 8 * Cos(-2*n/8192)
 m.f = 8 * Sin(4*n/4192)
 c = (1000000/(Pow(-64+x+4*k,2)+Pow(-64+y+2*m,2))  +  1000000/(Pow(-64+x-4*k,2)+1*Pow(-64+y-8*l,2))  +  1000000/(Pow(-64+x-2*m,2)+Pow(-64+y-4*l,2))) / 16
 If c > 255 : c = 255 : Else : c = c : EndIf
 ; --/fin metaball 
    
      ImageData(i)= c    : i+1 
      ImageData(i)= c/10 : i+1 
      ImageData(i)= c/2  : i+2
     Next 
  Next 
  

  
 ; glGenTextures_(1, @Tex) 
  
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR) 
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR) 
  glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGBA, Width, Height, 0, #GL_RGBA, #GL_UNSIGNED_BYTE, @ImageData()) 
  
  ProcedureReturn Tex 
EndProcedure

Publié : mar. 06/nov./2007 9:50
par tmyke
Excellent, et bon boulot. J'aime bien l'effet blob en rendertexture.

Et surtout bienvenu dans le monde féerique de la prog 3D.

;)

Publié : mar. 06/nov./2007 10:25
par Buckethead
Merci Tmyke, j'en profite pour te demander une ou deux questions vu que tu maitrises bien la 3D ;p
Peut on envisager d'utiliser OpenGL 2.0 en PB ? Il faut un fichier comme opengl.pb ? Je ne pense pas que l'on puisse importer des fonctions sans activer quelque chose avant. (je suis dans le fog total ;))

Publié : mar. 06/nov./2007 11:08
par tmyke
Je ne suis pas un super pro d'OpenGL, mon rayon (cela ne te surprendra pas) c'est DirectX.
Ceci dit, je pense qu'il n'y a pas de raison que tu ne puisse pas t'attaquer à OpenGL 2.x
avec PB, si ta carte video le supporte.

voici un lien qui peut t'aider à la mise en oeuvre et pour en savoir un peu plus la dessus:
http://www.siteduzero.com/tuto-3-17911- ... sions.html

Une lib comme GREW semble etre un bon tremplin, et de plus elle te permet aussi de connaitre
facilement les extensions GL dont tu disposes au niveau des drivers GL de ta carte video.

Publié : mar. 06/nov./2007 14:16
par Anonyme
Merci Buckethead.
Tu peut utilisé sans problème OpenGL 2.0 dans PB. je ne sais pas quelle version est en natif sur purebasic par contre (1.1?) , avec windows , c'est la 1.1 je crois, tu devrais pouvoir télécharger les extensions (glext.h) puis faire le fichier .pbi en fonction.
Et si tu maîtrises le c++ , rien ne t'empêche d'importer tes propres fonctions.


@++

Publié : mar. 06/nov./2007 15:01
par Ar-S
Wouaaa c'est vraiment joli !
J'aime beaucoup l'espece d'effet shader qui adoucie le tout, ça fait très pro !

Bravo

Publié : mer. 07/nov./2007 1:04
par Buckethead
Merci, c'est sympa. Je vais jeter un coup d'oeil à tout ça. (je ne connais rien au C++, mais je farfouille souvent dedans vu qu'on trouve plus facillement des infos dans ce langage , finallement j'apprend un peu la syntaxe en faisant du PureBasic lol)
Ps: Tmyke je savais pour direct X ;) Je me suis dit que tu avais surement touché à OpenGL.

Publié : mer. 07/nov./2007 9:39
par tmyke
Buckethead a écrit :Merci, c'est sympa. Je vais jeter un coup d'oeil à tout ça. (je ne connais rien au C++, mais je farfouille souvent dedans
vu qu'on trouve plus facillement des infos dans ce langage , finallement j'apprend un peu la syntaxe en faisant du PureBasic lol)...
Si tu as besoin d'un coups de main pour décripter certains points en C/C++, alors n'hésite pas,
je pense pouvoir t'aider dans la majorité des cas ;)
Buckethead a écrit :Ps: Tmyke je savais pour direct X ;) Je me suis dit que tu avais surement touché à OpenGL.
oui, je connais un peu, de loin, dans les grandes lignes, mais cela en reste la pour l'instant...
mais il va bien falloir qui je m'y interesse moi aussi, donc j'aime bien parler de GL moi aussi
de temps en temps :)

Publié : jeu. 08/nov./2007 23:22
par Buckethead
Merci, je n'hésiterais pas ;)


J'ai vu un peu les lumières, j'obtiens de bon résultats avec une sphère dont la tesselation est automatique, (j'aurais aimé utilisé aussi teapot) à mon avis elle contient les "bonnes" normales. Pour faire un cube j'avoue galèrer un peu. Dans tous les cas j'ai des objets d'un seul ton, qu'importe la couleur. Tout devient monochrome. J'ai trifouillé les valeurs des lumières et matières, ca passe du noir à une couleur que lorsque je met des valeurs négatives. :?

Pour les "normales" que j'ai mis dans le tuto je ne suis pas du tout sur de moi. J'ai l'impression qu'il faut faire le produit scalaire et "normaliser" le résultat. (via calcul ou instruction GL pratique mais lente) Comme si il y avait une partie non accèlèré pour gèrer les lumières.

Bref je vais voir pour un autre tuto avec un cube "à la hello word" mais ombré comme sur le dessin. (ou pas ;))

Image

Code : Tout sélectionner

glShadeModel_(#GL_SMOOTH)
glLightModeli_(#GL_LIGHT_MODEL_LOCAL_VIEWER,#GL_TRUE)

glEnable_(#GL_LIGHTING)
glEnable_(#GL_LIGHT0)
glEnable_(#GL_LIGHT1)


Dim L0dif(3) : L0dif(0) = 0.3 : L0dif(1) = 0.3 : L0dif(2) = 0.8
;Dim L1dif(3) : L1dif(0) = 0.5 : L1dif(1) = 0.5 : L1dif(2) = 0.5

;Dim L0dif(3) : L0dif(0) = -1.0 : L0dif(1) = -1.0 : L0dif(2) = -1.0
Dim L1dif(3) : L1dif(0) = -1.0 : L1dif(1) = -100.90 : L1dif(2) = 0.99


 glLightfv_(#GL_LIGHT0,#GL_DIFFUSE,L0dif())
 glLightfv_(#GL_LIGHT0,#GL_SPECULAR,L0dif())
 glLightfv_(#GL_LIGHT1,#GL_DIFFUSE,L1dif())
 glLightfv_(#GL_LIGHT1,#GL_SPECULAR,L1dif())

;Paramétrage du matériau
Dim Mshiny(1) : Mshiny(0) = 150
Dim Mspec(3) : Mspec(0) = 10.5 : Mspec(1) = 0.5 : Mspec(2) = 0.5
;Dim Mspec(3) : Mspec(0) = Sin(tp/105) : Mspec(1) = Cos(tp/15) : Mspec(2) = Sin(tp/51)
;Dim Mspec(3) : Mspec(0) = -1.0 : Mspec(1) = 0.0 : Mspec(2) = 0.0

 glMaterialfv_(#GL_FRONT_AND_BACK,#GL_SPECULAR,Mspec())
 glMaterialf_(#GL_FRONT_AND_BACK,#GL_SHININESS,Mshiny())


;position
;Dim L0pos(3) : L0pos(0) = 0.0 : L0pos(1) = 2.0 : L0pos(2) = -1.0
;Dim L1pos(3) : L1pos(0) = 2.0 : L1pos(1) = 2.0 : L1pos(2) = 2.0
Dim L0pos(4) : L0pos(0) = 0.0 : L0pos(1) = 2.0 : L0pos(2) = 0.0 : L0pos(3) = 0.0
Dim L1pos(4) : L1pos(0) = 2.0 : L1pos(1) = 2.0 : L1pos(2) = 0.0 : L1pos(3) = 1.0

;Dim L0pos(3) : L0pos(0) = 100*Sin(tp/15) : L0pos(1) = 100*Sin(tp/15): L0pos(2) = 100*Sin(tp/25)
;Dim L1pos(3) : L1pos(0) = 100*Cos(tp/35) : L1pos(1) = 100*Sin(tp/25) : L1pos(2) = 100*Sin(tp/25)

glLightfv_(#GL_LIGHT0,#GL_POSITION,L0pos());
glLightfv_(#GL_LIGHT1,#GL_POSITION,L1pos());


glLightf_(#GL_LIGHT0,#GL_QUADRATIC_ATTENUATION,0.01)
glLightf_(#GL_LIGHT1,#GL_QUADRATIC_ATTENUATION,0.01)

Edit:
Pour avoir les faces du cube ombré:
ne pas utiliser le code plus haut et mettre seulement:

Code : Tout sélectionner

glShadeModel_(#GL_SMOOTH)
glLightModeli_(#GL_LIGHT_MODEL_LOCAL_VIEWER,#GL_TRUE)
glEnable_(#GL_LIGHTING)
glEnable_(#GL_LIGHT0)
et surtout la commande magique :lol:

Code : Tout sélectionner

glEnable_(#GL_COLOR_MATERIAL)
Le big cube ne rend pas bien avec le scale, ..
If scale factors other than 1 are applied to the modelview matrix and lighting is enabled, lighting often appears wrong. In that case, enable automatic normalization of normals by calling glEnable with the argument GL_NORMALIZE.
.. le rendu est quand même bon si on modifie la fonction Dessiner(), dynamiquement avec des glVertex3d_(-var,+var,-var)
J'ai lu que GL_NORMALIZE était gourmand en ressource (je vais quand même le tester...)
Et j'ai merdé aussi avec les double et float pour les normales (entre autre!).

Je vais tout mettre à plat et tacher de comprendre tout ça et faire un tuto ;)

Edit 2:
Je me suis pas mal embrouillé à cause des extensions, Dim L0pos(3) = 0.1 --> Dim L0pos.f(3) !! Ca marche mieux :p