[Résolu] Calcul des normales d'un mesh 2: La Revanche
Publié : jeu. 19/juin/2008 16:33
[profonde inspiration, court instant de préparation mentale, puis: ]
AU SECOURS !!!
J'vais devenir dingue avec ces @#£$ de normales!
Sur les conseils d'Ollivier, j'ai tenté de passer en "Phong" ma géosphère issue de la subdivision d'un mesh plus simple. Et là, l'horreur.
D'abord, ça me donne le même résultat qu'en "Flat", et puis ça me donne vraiment l'impression que mes normales sont attribuées n'importe comment.
Pire: l'ordre des vertices dans les triangles affecte le rendu! (mais seulement en "Flat" et "Phong", pas en Gouraud)
<= Et ça!? Vous allez pas m'dire que c'est correct, ça quand même!!
Bref, je craque.
Faites l'essai par vous-même:
- Lancez le code ci-dessous;
- Appuyez 3-4 fois sur "S" pour subdiviser;
- Appuyez sur "N" pour normaliser => ça paraît presque bon, mais il subsiste des dentelures bizarres sur les bords et je ne sais pas comment les virer (appuyez sur "R" pour mieux voir).
Recommencez en appuyant sur "I" après chaque appui sur "S", ce qui vous donne une sphère. Appuyez sur "N" => les normales sont un gros tas de n'importe quoi (pour rester poli)...
Ô dieux de la 3D en PureBasic, venez à mon aide! Esprits de Comtois, Tmyke et Cpl_Bator, j'en appelle à vous ! Ne laissez pas une brebis égarée en ces contrées sauvages céder au découragement !
(Et pour constater l'effet de l'ordre des triangles sur l'ombrage "Phong", appuyez sur 1,2,3, ou 4, ce qui change l'ordre des vertices dans un triangle sur 4)
AU SECOURS !!!
J'vais devenir dingue avec ces @#£$ de normales!
Sur les conseils d'Ollivier, j'ai tenté de passer en "Phong" ma géosphère issue de la subdivision d'un mesh plus simple. Et là, l'horreur.
D'abord, ça me donne le même résultat qu'en "Flat", et puis ça me donne vraiment l'impression que mes normales sont attribuées n'importe comment.
Pire: l'ordre des vertices dans les triangles affecte le rendu! (mais seulement en "Flat" et "Phong", pas en Gouraud)


Bref, je craque.
Faites l'essai par vous-même:
- Lancez le code ci-dessous;
- Appuyez 3-4 fois sur "S" pour subdiviser;
- Appuyez sur "N" pour normaliser => ça paraît presque bon, mais il subsiste des dentelures bizarres sur les bords et je ne sais pas comment les virer (appuyez sur "R" pour mieux voir).
Recommencez en appuyant sur "I" après chaque appui sur "S", ce qui vous donne une sphère. Appuyez sur "N" => les normales sont un gros tas de n'importe quoi (pour rester poli)...
Ô dieux de la 3D en PureBasic, venez à mon aide! Esprits de Comtois, Tmyke et Cpl_Bator, j'en appelle à vous ! Ne laissez pas une brebis égarée en ces contrées sauvages céder au découragement !
Code : Tout sélectionner
; Author: Kelebrindae
; Date: june,19, 2008
; PB version: v4.10
; OS: Windows XP
#SQRT03=0.577350269189625764
;- Initialisation
Resultat = MessageRequester("Mesh Subdivision","Full Screen ?",#PB_MessageRequester_YesNo)
If Resultat = 6
FullScreen=1
Else
FullScreen=0
EndIf
If InitEngine3D() = 0
MessageRequester( "Error" , "Can't initialize 3D, check if engine3D.dll is available" , 0 )
End
ElseIf InitSprite() = 0 Or InitKeyboard() = 0
MessageRequester( "Error" , "Can't find DirectX 7.0 or above" , 0 )
End
EndIf
If Fullscreen
OpenScreen(800,600,32,"Mesh Subdivision")
Else
OpenWindow(0,0, 0, 800 , 600 ,"Mesh Subdivision",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0, 800 , 600,0,0,0)
EndIf
;- Data structures and definitions
Global CameraMode.l
Structure Vector3
x.f
y.f
z.f
EndStructure
Structure Vertex
px.f
py.f
pz.f
nx.f
ny.f
nz.f
couleur.l
U.f
V.f
EndStructure
Structure FaceTri
f1.w
f2.w
f3.w
EndStructure
Structure dynMesh_struct
id.s
numMesh.l
sizeX.f
sizeY.f
sizeZ.f
nbVert.l
nbTri.l
*vertexBuffer.Vertex
*faceBuffer.faceTri
EndStructure
#MAXMESH=2
Global Dim dynMesh.dynMesh_struct(#MAXMESH)
Enumeration
#octahedron
#pointyCube
#Face
EndEnumeration
EnableExplicit
;- ---- Procedures ----
;************************************************************************************
; Name: NormalizeVector
; Purpose: Normalizes a vector to the length 1 without changing its orientation.
; Parameters:
; - vector to normalize
;************************************************************************************
Procedure.l NormalizeVector(*Vec1.Vector3)
Protected length.f
length.f = Sqr(*Vec1\x * *Vec1\x + *Vec1\y * *Vec1\y + *Vec1\z * *Vec1\z)
*Vec1\x / length
*Vec1\y / length
*Vec1\z / length
EndProcedure
; Macro version
Macro NORME(V)
(Sqr(V\x * V\x + V\y * V\y + V\z * V\z))
EndMacro
;************************************************************************************
; Name: CreateDynMesh
; Purpose: Creates a mesh, scaled and UV mapped dynamically, and stores vertices/faces
; infos in the "dynMesh" array
; Parameters:
; - id of the mesh
; - mesh type: #octahedron,#pointyCube
; - X size
; - Y size
; - Z size
; - origin of mapping coord U
; - origin of mapping coord V
; - Vertices color
; Return value: mesh indice in the "dynMesh" array, or -1 if an error occurs
;************************************************************************************
Procedure.l CreateDynMesh(id.s,solid.l,sizeX.f,sizeY.f,sizeZ.f,Uorigin.f,Vorigin.f,Uscale.f,Vscale.f,color.l)
Protected x.f,y.f,z.f ; vertex position
Protected nx.f,ny.f,nz.f ; vertex normals
Protected u.f,v.f ; vertex UV coords (texture mapping)
Protected v1.w,v2.w,v3.w
Protected *PtrV.Vertex ; vertices buffer in memory
Protected *PtrF.FaceTri ; Faces buffer in memory
Protected num.l,i.l
; Restore the good set of meshdatas
Select solid
Case #octahedron
Restore octahedron
Case #pointyCube
Restore pointyCube
Case #Face
Restore Face
Default
ProcedureReturn -1
EndSelect
; Find first free slot in dynMesh()
While num<#MAXMESH And dynMesh(num)\nummesh>0
num+1
Wend
; Read number of vertices and triangles
Read dynMesh(num)\nbVert
Read dynMesh(num)\nbTri
; Allocate the needed memory for vertices
dynMesh(num)\vertexBuffer = AllocateMemory(SizeOf(Vertex)*dynMesh(num)\nbVert)
*PtrV = dynMesh(num)\vertexBuffer
; Allocate the needed memory for faces
dynMesh(num)\faceBuffer=AllocateMemory(SizeOf(FaceTri)*dynMesh(num)\nbTri)
*PtrF=dynMesh(num)\faceBuffer
; Read and store vertices position, normals, uv coords
For i = 1 To dynMesh(num)\nbVert
Read x
Read y
Read z
Read nx
Read ny
Read nz
Read u
Read v
color=RGB(255,0,0)
If i%3 = 1
color=RGB(0,255,0)
EndIf
If i%3 = 2
color=RGB(0,0,255)
EndIf
*PtrV\px = x * sizex
*PtrV\py = y * sizey
*PtrV\pz = z * sizez
*PtrV\nx = nx
*PtrV\ny = ny
*PtrV\nz = nz
*PtrV\couleur = color
*PtrV\u = uorigin + (u * uscale)
*PtrV\v = vorigin + (v * vscale)
*PtrV + SizeOf(Vertex)
Next i
;Read and store faces infos
For i=1 To dynMesh(num)\nbTri
Read v1
Read v2
Read v3
*PtrF\f1=v1
*PtrF\f2=v2
*PtrF\f3=v3
*PtrF + SizeOf(FaceTri)
Next i
; Create mesh from stored infos
dynMesh(num)\numMesh = CreateMesh(#PB_Any,dynMesh(num)\nbVert)
If IsMesh(dynMesh(num)\numMesh)
SetMeshData(dynMesh(num)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_UVCoordinate | #PB_Mesh_Color,dynMesh(num)\vertexBuffer,dynMesh(num)\nbVert)
SetMeshData(dynMesh(num)\numMesh,#PB_Mesh_Face,dynMesh(num)\faceBuffer,dynMesh(num)\nbTri)
dynMesh(num)\id = id
dynMesh(num)\sizeX = sizeX
dynMesh(num)\sizeY = sizeY
dynMesh(num)\sizeZ = sizeZ
ProcedureReturn num
Else
; free memory if "createMesh" has failed
FreeMemory(dynMesh(num)\vertexBuffer)
FreeMemory(dynMesh(num)\faceBuffer)
ProcedureReturn -1
EndIf
EndProcedure
;************************************************************************************
; Name: deleteDynMesh
; Purpose: deletes a mesh and all vertices/faces infos in the "dynMesh" array
; Parameters:
; - mesh indice in the "dynMesh" array
; - mesh type: #octahedron,#pointyCube
;************************************************************************************
Procedure deleteDynMesh(num.l)
If dynMesh(num)\numMesh=0
ProcedureReturn -1
EndIf
;FreeMesh(dynMesh(num)\numMesh)
FreeMemory(dynMesh(num)\vertexBuffer)
FreeMemory(dynMesh(num)\faceBuffer)
dynMesh(num)\numMesh=0
EndProcedure
;************************************************************************************
; Name: inflateMesh
; Purpose: normalizes each vertex' position so they're at the same distance from the center
; of the mesh => makes the mesh spheric
; Parameters:
; - mesh indice in the "dynMesh" array
; - mesh type: #octahedron,#pointyCube
;************************************************************************************
Procedure inflateMesh(numMesh.l)
Protected i.l
Protected *ptrVert.Vertex
Protected vector3.Vector3
Protected NormeVecteur.f
*ptrVert = dynMesh(numMesh)\vertexBuffer
For i = 1 To dynmesh(numMesh)\nbVert
vector3\x = *ptrVert\px
vector3\y = *ptrVert\py
vector3\z = *ptrVert\pz
NormalizeVector(@vector3)
; Equivalent:
; NormeVecteur = NORME(vector3)
; If NormeVecteur <> 0.0
; vector3\x / NormeVecteur
; vector3\y / NormeVecteur
; vector3\z / NormeVecteur
; EndIf
*ptrVert\px = vector3\x * dynMesh(numMesh)\sizeX
*ptrVert\py = vector3\y * dynMesh(numMesh)\sizeY
*ptrVert\pz = vector3\z * dynMesh(numMesh)\sizeZ
*ptrVert\nx = vector3\x
*ptrVert\ny = vector3\y
*ptrVert\nz = vector3\z
*ptrVert+SizeOf(Vertex)
Next i
EndProcedure
;************************************************************************************
; Name: subdivideTriangle
; Purpose: Subdivides a triangle of the mesh into 4 smaller triangles
; - mesh indice in the "dynMesh" array
; - triangle to subdivide
;************************************************************************************
Procedure subdivideTriangle(nummesh.l,numtri.l)
Protected VertexA.Vertex
Protected VertexB.Vertex
Protected VertexC.Vertex
Protected *PtrV0.Vertex,*PtrV1.Vertex,*PtrV2.Vertex
Protected *PtrNewV.vertex,*PtrNewF.faceTri
Protected oldNbVert.w,oldNbFace.l,newVertNum.w,temp.w
Debug "Mesh n°" + Str(nummesh) + ", " + Str(dynmesh(nummesh)\nbvert) + " vertices, " + Str(dynmesh(nummesh)\nbtri) + " triangles"
Debug "Subdivision du triangle n°" + Str(numtri)
Debug " ->Taille mémoire pour vertices/faces: " + Str(MemorySize(dynMesh(nummesh)\vertexBuffer)) + " / " + Str(MemorySize(dynMesh(nummesh)\faceBuffer))
Debug " ->Taille mémoire des structures vertices/faces: " + Str(SizeOf(Vertex)) + " / " + Str(SizeOf(faceTri))
; Store current end of vertices/faces datas
oldNbVert = dynMesh(nummesh)\nbVert
oldNbFace = dynMesh(nummesh)\nbTri
newVertNum = oldNbVert
; Extend allocated memory for new vertices and faces
dynmesh(nummesh)\nbvert+9
dynMesh(nummesh)\vertexBuffer = ReAllocateMemory(dynMesh(nummesh)\vertexBuffer,SizeOf(Vertex)*dynMesh(nummesh)\nbVert)
dynmesh(nummesh)\nbtri+3
dynMesh(nummesh)\faceBuffer = ReAllocateMemory(dynMesh(nummesh)\faceBuffer,SizeOf(FaceTri)*dynMesh(nummesh)\nbTri)
; NB: on ajoute que 3 triangles, car le triangle subdivisé est réutilisé
Debug " Augmentation nb vertices/faces à: " + Str(dynmesh(nummesh)\nbvert) + " / " + Str(dynmesh(nummesh)\nbtri)
Debug " ->Taille mémoire demandée pour vertices/faces: " + Str(SizeOf(Vertex) * dynmesh(nummesh)\nbvert) + " / " + Str(SizeOf(FaceTri) * dynmesh(nummesh)\nbtri)
Debug " Resultat de ReAllocate: " + Str(dynMesh(nummesh)\vertexBuffer) + " / " + Str(dynMesh(nummesh)\FaceBuffer)
Debug " ->Nouvelle taille mémoire: " + Str(MemorySize(dynMesh(nummesh)\vertexBuffer)) + " / " + Str(MemorySize(dynMesh(nummesh)\faceBuffer))
; le triangle est divisé en 4
; Phase 1: on repère l'emplacement des vertices du triangle
*PtrV0 = dynMesh(nummesh)\vertexBuffer + (numtri * SizeOf(Vertex) * 3)
*PtrV1 = dynMesh(nummesh)\vertexBuffer + (numtri * SizeOf(Vertex) * 3) + SizeOf(Vertex)
*PtrV2 = dynMesh(nummesh)\vertexBuffer + (numtri * SizeOf(Vertex) * 3) + SizeOf(Vertex) * 2
Debug " Vertex réf., n°" + Str((*PtrV0 - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrV0\px)+","+StrF(*PtrV0\py)+","+StrF(*PtrV0\pz)
Debug " Vertex réf., n°" + Str((*PtrV1 - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrV1\px)+","+StrF(*PtrV1\py)+","+StrF(*PtrV1\pz)
Debug " Vertex réf., n°" + Str((*PtrV2 - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrV2\px)+","+StrF(*PtrV2\py)+","+StrF(*PtrV2\pz)
; Phase 2: on calcule la position des nouveaux vertices
VertexA\px = (*PtrV0\px + *PtrV1\px) / 2.0
VertexA\py = (*PtrV0\py + *PtrV1\py) / 2.0
VertexA\pz = (*PtrV0\pz + *PtrV1\pz) / 2.0
VertexA\nx = VertexA\px / dynMesh(nummesh)\sizex
VertexA\ny = VertexA\py / dynMesh(nummesh)\sizey
VertexA\nz = VertexA\pz / dynMesh(nummesh)\sizez
VertexA\couleur = (*PtrV0\couleur + *PtrV1\couleur) / 2.0
VertexA\U = (*PtrV0\U + *PtrV1\U) / 2.0
VertexA\V = (*PtrV0\V + *PtrV1\V) / 2.0
VertexB\px = (*PtrV0\px + *PtrV2\px) / 2.0
VertexB\py = (*PtrV0\py + *PtrV2\py) / 2.0
VertexB\pz = (*PtrV0\pz + *PtrV2\pz) / 2.0
VertexB\nx = VertexB\px / dynMesh(nummesh)\sizex
VertexB\ny = VertexB\py / dynMesh(nummesh)\sizey
VertexB\nz = VertexB\pz / dynMesh(nummesh)\sizez
VertexB\couleur = (*PtrV0\couleur + *PtrV2\couleur) / 2.0
VertexB\U = (*PtrV0\U + *PtrV2\U) / 2.0
VertexB\V = (*PtrV0\V + *PtrV2\V) / 2.0
VertexC\px = (*PtrV1\px + *PtrV2\px) / 2.0
VertexC\py = (*PtrV1\py + *PtrV2\py) / 2.0
VertexC\pz = (*PtrV1\pz + *PtrV2\pz) / 2.0
VertexC\nx = VertexC\px / dynMesh(nummesh)\sizex
VertexC\ny = VertexC\py / dynMesh(nummesh)\sizey
VertexC\nz = VertexC\pz / dynMesh(nummesh)\sizez
VertexC\couleur = (*PtrV1\couleur + *PtrV2\couleur) / 2.0
VertexC\U = (*PtrV1\U + *PtrV2\U) / 2.0
VertexC\V = (*PtrV1\V + *PtrV2\V) / 2.0
; on écrira les nouveaux vertices/faces à ces endroits:
*PtrNewV = dynMesh(nummesh)\vertexBuffer + (SizeOf(Vertex) * (oldNbVert) )
*PtrNewF = dynMesh(nummesh)\faceBuffer + (SizeOf(FaceTri) * (oldNbFace) )
; Add a new triangle...
;AddTri( *PtrV1, VertexC, VertexA)
*PtrNewV\px = *PtrV1\px
*PtrNewV\py = *PtrV1\py
*PtrNewV\pz = *PtrV1\pz
*PtrNewV\nx = *PtrV1\nx
*PtrNewV\ny = *PtrV1\ny
*PtrNewV\nz = *PtrV1\nz
*PtrNewV\couleur = *PtrV1\couleur
*PtrNewV\u = *PtrV1\u
*PtrNewV\v = *PtrV1\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexC\px
*PtrNewV\py = VertexC\py
*PtrNewV\pz = VertexC\pz
*PtrNewV\nx = VertexC\nx
*PtrNewV\ny = VertexC\ny
*PtrNewV\nz = VertexC\nz
*PtrNewV\couleur = VertexC\couleur
*PtrNewV\u = VertexC\u
*PtrNewV\v = VertexC\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexA\px
*PtrNewV\py = VertexA\py
*PtrNewV\pz = VertexA\pz
*PtrNewV\nx = VertexA\nx
*PtrNewV\ny = VertexA\ny
*PtrNewV\nz = VertexA\nz
*PtrNewV\couleur = VertexA\couleur
*PtrNewV\u = VertexA\u
*PtrNewV\v = VertexA\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewF\f1=newVertNum +1
*PtrNewF\f2=newVertNum +2
*PtrNewF\f3=newVertNum
Debug " => new triangle, n°" + Str((*PtrNewF - dynMesh(nummesh)\faceBuffer)/SizeOf(FaceTri)) + ": " + Str(*PtrNewF\f1)+","+Str(*PtrNewF\f2)+","+Str(*PtrNewF\f3)
*PtrNewF + SizeOf(FaceTri)
newVertNum+3
; ...add another...
;AddTri( *PtrV2, VertexB, VertexC)
*PtrNewV\px = *PtrV2\px
*PtrNewV\py = *PtrV2\py
*PtrNewV\pz = *PtrV2\pz
*PtrNewV\nx = *PtrV2\nx
*PtrNewV\ny = *PtrV2\ny
*PtrNewV\nz = *PtrV2\nz
*PtrNewV\couleur = *PtrV2\couleur
*PtrNewV\u = *PtrV2\u
*PtrNewV\v = *PtrV2\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexB\px
*PtrNewV\py = VertexB\py
*PtrNewV\pz = VertexB\pz
*PtrNewV\nx = VertexB\nx
*PtrNewV\ny = VertexB\ny
*PtrNewV\nz = VertexB\nz
*PtrNewV\couleur = VertexB\couleur
*PtrNewV\u = VertexB\u
*PtrNewV\v = VertexB\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexC\px
*PtrNewV\py = VertexC\py
*PtrNewV\pz = VertexC\pz
*PtrNewV\nx = VertexC\nx
*PtrNewV\ny = VertexC\ny
*PtrNewV\nz = VertexC\nz
*PtrNewV\couleur = VertexC\couleur
*PtrNewV\u = VertexC\u
*PtrNewV\v = VertexC\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewF\f1=newVertNum +1
*PtrNewF\f2=newVertNum +2
*PtrNewF\f3=newVertNum
Debug " => new triangle, n°" + Str((*PtrNewF - dynMesh(nummesh)\faceBuffer)/SizeOf(FaceTri)) + ": " + Str(*PtrNewF\f1)+","+Str(*PtrNewF\f2)+","+Str(*PtrNewF\f3)
*PtrNewF + SizeOf(FaceTri)
newVertNum+3
; ...and another...
;AddTri( VertexA, VertexC, VertexB)
*PtrNewV\px = VertexA\px
*PtrNewV\py = VertexA\py
*PtrNewV\pz = VertexA\pz
*PtrNewV\nx = VertexA\nx
*PtrNewV\ny = VertexA\ny
*PtrNewV\nz = VertexA\nz
*PtrNewV\couleur = VertexA\couleur
*PtrNewV\u = VertexA\u
*PtrNewV\v = VertexA\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexC\px
*PtrNewV\py = VertexC\py
*PtrNewV\pz = VertexC\pz
*PtrNewV\nx = VertexC\nx
*PtrNewV\ny = VertexC\ny
*PtrNewV\nz = VertexC\nz
*PtrNewV\couleur = VertexC\couleur
*PtrNewV\u = VertexC\u
*PtrNewV\v = VertexC\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewV\px = VertexB\px
*PtrNewV\py = VertexB\py
*PtrNewV\pz = VertexB\pz
*PtrNewV\nx = VertexB\nx
*PtrNewV\ny = VertexB\ny
*PtrNewV\nz = VertexB\nz
*PtrNewV\couleur = VertexB\couleur
*PtrNewV\u = VertexB\u
*PtrNewV\v = VertexB\v
Debug " New Vertex, n°" + Str((*PtrNewV - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrNewV\px)+","+StrF(*PtrNewV\py)+","+StrF(*PtrNewV\pz)
*PtrNewV + SizeOf(Vertex)
*PtrNewF\f1=newVertNum +1
*PtrNewF\f2=newVertNum +2
*PtrNewF\f3=newVertNum
Debug " => new triangle, n°" + Str((*PtrNewF - dynMesh(nummesh)\faceBuffer)/SizeOf(FaceTri)) + ": " + Str(*PtrNewF\f1)+","+Str(*PtrNewF\f2)+","+Str(*PtrNewF\f3)
*PtrNewF + SizeOf(FaceTri)
newVertNum+3
; ...then resize base triangle.
*PtrV1\px = VertexA\px
*PtrV1\py = VertexA\py
*PtrV1\pz = VertexA\pz
*PtrV1\nx = VertexA\nx
*PtrV1\ny = VertexA\ny
*PtrV1\nz = VertexA\nz
*PtrV1\couleur = VertexA\couleur
*PtrV1\U = VertexA\U
*PtrV1\V = VertexA\V
Debug " Reposition Vertex, n°" + Str((*PtrV1 - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrV1\px)+","+StrF(*PtrV1\py)+","+StrF(*PtrV1\pz)
*PtrV2\px = VertexB\px
*PtrV2\py = VertexB\py
*PtrV2\pz = VertexB\pz
*PtrV2\nx = VertexB\nx
*PtrV2\ny = VertexB\ny
*PtrV2\nz = VertexB\nz
*PtrV2\ couleur= VertexB\couleur
*PtrV2\U = VertexB\U
*PtrV2\V = VertexB\V
Debug " Reposition Vertex, n°" + Str((*PtrV2 - dynMesh(nummesh)\vertexBuffer)/SizeOf(Vertex)) + ": " + StrF(*PtrV2\px)+","+StrF(*PtrV2\py)+","+StrF(*PtrV2\pz)
; *PtrNewF = dynmesh(nummesh)\faceBuffer + numtri*SizeOf(faceTri)
; temp = *PtrNewF\f3
; *PtrNewF\f3 = *PtrNewF\f2
; *PtrNewF\f2 = *PtrNewF\f1
; *PtrNewF\f1 = temp
; temp = *PtrNewF\f3
; *PtrNewF\f3 = *PtrNewF\f2
; *PtrNewF\f2 = *PtrNewF\f1
; *PtrNewF\f1 = temp
Debug "---------------------------------------------------"
EndProcedure
;************************************************************************************
; Name: subdivideMesh
; Purpose: Subdivides each triangle of a mesh, then inflates the mesh to make it look spheric
; - mesh indice in the "dynMesh" array
; - how many times the process will be repeated
;************************************************************************************
Procedure subdivideMesh(nummesh.l,nbiteration.b)
Protected i.l,j.l,top.l
; subdivision
For j = 1 To nbiteration
top = dynMesh(nummesh)\nbTri - 1
For i = 0 To top
subdivideTriangle(nummesh,i)
Next i
Next j
; modify mesh infos
SetMeshData(dynMesh(nummesh)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(nummesh)\vertexBuffer,dynMesh(nummesh)\nbVert)
SetMeshData(dynMesh(nummesh)\numMesh,#PB_Mesh_Face,dynMesh(nummesh)\faceBuffer,dynMesh(nummesh)\nbTri)
EndProcedure
;************************************************************************************
; Name: normalizeMesh
; Purpose: Subdivides each triangle of a mesh, then inflates the mesh to make it look spheric
; - mesh indice in the "dynMesh" array
; - how many times the process will be repeated
;************************************************************************************
Procedure normalizeMesh(nummesh.l)
Protected *ptrVert.vertex,*PtrV0.vertex,*PtrV1.vertex,*PtrV2.vertex
Protected *ptrFace.faceTri
Protected normVect1.Vector3,normVect2.Vector3,faceNormal.Vector3
Protected i.l,j.l,length.f
; Initialize vertices' normals to 0
*ptrVert = dynMesh(numMesh)\vertexBuffer
For i = 1 To dynmesh(numMesh)\nbVert
*ptrVert\nx = 0
*ptrVert\ny = 0
*ptrVert\nz = 0
*ptrVert+SizeOf(Vertex)
Next i
; For each facet of the mesh:
*ptrFace = dynMesh(nummesh)\faceBuffer
For i = 1 To dynMesh(nummesh)\nbTri
;Debug "Face n°" + Str(i-1) + " - vertices " + Str(*ptrface\f1)+","+ Str(*ptrface\f2)+","+ Str(*ptrface\f3)
; Get facet normal
*PtrV0 = dynMesh(nummesh)\vertexBuffer + (*ptrface\f1 * SizeOf(Vertex))
*PtrV1 = dynMesh(nummesh)\vertexBuffer + (*ptrface\f2 * SizeOf(Vertex))
*PtrV2 = dynMesh(nummesh)\vertexBuffer + (*ptrface\f3 * SizeOf(Vertex))
normVect1\x = (*PtrV1\px - *PtrV0\px)
normVect1\y = (*PtrV1\py - *PtrV0\py)
normVect1\z = (*PtrV1\pz - *PtrV0\pz)
normVect2\x = (*PtrV2\px - *PtrV0\px)
normVect2\y = (*PtrV2\py - *PtrV0\py)
normVect2\z = (*PtrV2\pz - *PtrV0\pz)
faceNormal\x = ((normVect1\y * normVect2\z) - (normVect1\z * normVect2\y))
faceNormal\y = ((normVect1\z * normVect2\x) - (normVect1\x * normVect2\z))
faceNormal\z = ((normVect1\x * normVect2\y) - (normVect1\y * normVect2\x))
Length = Sqr(faceNormal\x*faceNormal\x + faceNormal\y*faceNormal\y + faceNormal\z*faceNormal\z)
faceNormal\x / Length
faceNormal\y / Length
faceNormal\z / Length
;Debug "=> Normal = "+StrF(faceNormal\x)+","+StrF(faceNormal\y)+","+StrF(faceNormal\z)
; First vertex of face
*ptrVert = dynMesh(numMesh)\vertexBuffer
; for all vertices at the same position, add face normal to vertex normal
For j = 1 To dynmesh(numMesh)\nbVert
If *ptrVert\px = *ptrV0\px And *ptrVert\py = *ptrV0\py And *ptrVert\pz = *ptrV0\pz
*ptrVert\nx + faceNormal\x
*ptrVert\ny + faceNormal\y
*ptrVert\nz + faceNormal\z
;Debug " vertex " + Str(*ptrface\f1) +" = vertex " + Str(j-1)
EndIf
*ptrVert+SizeOf(Vertex)
Next j
; Second vertex of face
*ptrVert = dynMesh(numMesh)\vertexBuffer
; for all vertices at the same position, add face normal to vertex normal
For j = 1 To dynmesh(numMesh)\nbVert
If *ptrVert\px = *ptrV1\px And *ptrVert\py = *ptrV1\py And *ptrVert\pz = *ptrV1\pz
*ptrVert\nx + faceNormal\x
*ptrVert\ny + faceNormal\y
*ptrVert\nz + faceNormal\z
;Debug " vertex " + Str(*ptrface\f2) +" = vertex " + Str(j-1)
EndIf
*ptrVert+SizeOf(Vertex)
Next j
; Third vertex of face
*ptrVert = dynMesh(numMesh)\vertexBuffer
; for all vertices at the same position, add face normal to vertex normal
For j = 1 To dynmesh(numMesh)\nbVert
If *ptrVert\px = *ptrV2\px And *ptrVert\py = *ptrV2\py And *ptrVert\pz = *ptrV2\pz
*ptrVert\nx + faceNormal\x
*ptrVert\ny + faceNormal\y
*ptrVert\nz + faceNormal\z
;Debug " vertex " + Str(*ptrface\f3) +" = vertex " + Str(j-1)
EndIf
*ptrVert+SizeOf(Vertex)
Next j
*ptrFace+SizeOf(faceTri)
Next i
; Then, average (= normalize) all the vertices' normals
*ptrVert = dynMesh(numMesh)\vertexBuffer
For j = 1 To dynmesh(numMesh)\nbVert
normVect1\x = *ptrVert\nx
normVect1\y = *ptrVert\ny
normVect1\z = *ptrVert\nz
NormalizeVector(@normVect1)
*ptrVert\nx = normVect1\x
*ptrVert\ny = normVect1\y
*ptrVert\nz = normVect1\z
*ptrVert+SizeOf(Vertex)
Next j
; modify mesh infos
SetMeshData(dynMesh(nummesh)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(nummesh)\vertexBuffer,dynMesh(nummesh)\nbVert)
;SetMeshData(dynMesh(nummesh)\numMesh,#PB_Mesh_Face,dynMesh(nummesh)\faceBuffer,dynMesh(nummesh)\nbTri)
EndProcedure
DisableExplicit
;************************************************************************************
;- ---- Main loop ----
;-Mesh
; Change parameters 2 to 8 to test the effects on size and texturing
Global myOctaMesh.l
myOctaMesh = CreateDynMesh("Octa",#octahedron,1,1,1,0,0,4,4,RGB(0,127,200))
;-Texture
CreateTexture(0,128, 128)
StartDrawing(TextureOutput(0))
Box(0, 0, 128, 128, $FFFFFF)
DrawingMode(#PB_2DDrawing_Outlined)
StopDrawing()
;-Material
CreateMaterial(0,TextureID(0))
;MaterialAmbientColor(0,#PB_Material_AmbientColors)
MaterialShadingMode(0, #PB_Material_Phong)
CreateMaterial(1,TextureID(0))
;MaterialAmbientColor(1,#PB_Material_AmbientColors)
;-Entity
CreateEntity(0,MeshID(dynMesh(myOctaMesh)\numMesh),MaterialID(0))
;-Camera
CreateCamera(0, 0, 0 , 100 , 100)
MoveCamera(0,0,0,5)
CameraLookAt(0,EntityX(0),EntityY(0),EntityZ(0))
;-Light
AmbientColor(RGB(63,63,63))
CreateLight(0,RGB(255,255,255),300,300,300)
Global *ptrFace.faceTri,*ptrVert.vertex,temp.w
pas.f = 0.8
angle.f = 0
Repeat
If fullscreen = 0
While WindowEvent() : Wend
EndIf
; Rotate
If rotate=1
Angle + Pas
RotateEntity(0, angle,angle/2,-angle)
EndIf
; Manage camera views
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F1)
CameraMode=1-CameraMode
CameraRenderMode(0,CameraMode)
AmbientColor(RGB(105+cameramode*150,105+cameramode*150,105+cameramode*150))
EndIf
If KeyboardReleased(#PB_Key_S)
subdivideMesh(0,1)
EndIf
If KeyboardReleased(#PB_Key_N)
normalizeMesh(0)
EndIf
If KeyboardReleased(#PB_Key_G)
mat=1-mat
EntityMaterial(0,MaterialID(mat))
EndIf
If KeyboardReleased(#PB_Key_R)
rotate = 1-rotate
EndIf
If KeyboardReleased(#PB_Key_I)
inflateMesh(0)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
EndIf
If KeyboardReleased(#PB_Key_B)
*ptrVert = dynMesh(0)\vertexBuffer
For i = 1 To dynMesh(0)\nbVert
*ptrVert\ny=*ptrVert\px
*ptrVert\nx=*ptrVert\py
*ptrVert\nz=*ptrVert\pz
Debug Sqr( *ptrVert\px* *ptrVert\px+ *ptrVert\py* *ptrVert\py+ *ptrVert\pz* *ptrVert\pz)
*ptrFace+SizeOf(vertex)
Next i
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Face,dynMesh(0)\faceBuffer,dynMesh(0)\nbTri)
EndIf
If KeyboardReleased(#PB_Key_1)
*ptrFace = dynMesh(0)\faceBuffer
For i = 1 To dynMesh(0)\nbTri Step 4
Debug Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
temp = *ptrFace\f3
*ptrFace\f3 = *ptrFace\f2
*ptrFace\f2 = *ptrFace\f1
*ptrFace\f1 = temp
Debug "=> "+Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
*ptrFace+SizeOf(faceTri)*4
Next i
;normalizeMesh(0)
;SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Face,dynMesh(0)\faceBuffer,dynMesh(0)\nbTri)
EndIf
If KeyboardReleased(#PB_Key_2)
*ptrFace = dynMesh(0)\faceBuffer+SizeOf(faceTri)
For i = 1 To dynMesh(0)\nbTri Step 4
Debug Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
temp = *ptrFace\f3
*ptrFace\f3 = *ptrFace\f2
*ptrFace\f2 = *ptrFace\f1
*ptrFace\f1 = temp
Debug "=> "+Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
*ptrFace+SizeOf(faceTri)*4
Next i
;normalizeMesh(0)
;SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Face,dynMesh(0)\faceBuffer,dynMesh(0)\nbTri)
EndIf
If KeyboardReleased(#PB_Key_3)
*ptrFace = dynMesh(0)\faceBuffer+SizeOf(faceTri)*2
For i = 1 To dynMesh(0)\nbTri Step 4
Debug Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
temp = *ptrFace\f3
*ptrFace\f3 = *ptrFace\f2
*ptrFace\f2 = *ptrFace\f1
*ptrFace\f1 = temp
Debug "=> "+Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
*ptrFace+SizeOf(faceTri)*4
Next i
;normalizeMesh(0)
;SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Face,dynMesh(0)\faceBuffer,dynMesh(0)\nbTri)
EndIf
If KeyboardReleased(#PB_Key_4)
*ptrFace = dynMesh(0)\faceBuffer+SizeOf(faceTri)*3
For i = 1 To dynMesh(0)\nbTri Step 4
Debug Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
temp = *ptrFace\f3
*ptrFace\f3 = *ptrFace\f2
*ptrFace\f2 = *ptrFace\f1
*ptrFace\f1 = temp
Debug "=> "+Str(*ptrFace\f1)+","+Str(*ptrFace\f2)+","+Str(*ptrFace\f3)
*ptrFace+SizeOf(faceTri)*4
Next i
;normalizeMesh(0)
;SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate,dynMesh(0)\vertexBuffer,dynMesh(0)\nbVert)
SetMeshData(dynMesh(0)\numMesh,#PB_Mesh_Face,dynMesh(0)\faceBuffer,dynMesh(0)\nbTri)
EndIf
EndIf
; show it all
RenderWorld()
; A little help
StartDrawing(ScreenOutput())
DrawText(0,0,"[F1] to change RenderMode, [G] to swap between Gouraud/Phong, [R] to rotate", $00FFFF, $BB0000)
DrawText(0,15,"[S] to subdivide mesh, [I] to spherify mesh, [N] to smooth normals", $00FFFF, $BB0000)
DrawText(0,30,Str(dynMesh(0)\nbVert) + " vertices, taille du buffer = " + Str(MemorySize(dynMesh(0)\vertexBuffer)) + " octets", $00FFFF, $BB0000)
DrawText(0,45,Str(dynMesh(0)\nbTri) + " faces, taille du buffer = " + Str(MemorySize(dynMesh(0)\FaceBuffer)) + " octets", $00FFFF, $BB0000)
StopDrawing()
; Flip buffers to avoid tearing
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
deleteDynMesh(myOctaMesh)
DataSection:
octahedron:
; Nb sommets / Nb faces
Data.l 24,8
; Vertices: pos / normals / uv
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f 0,0,1
Data.f 0,0,1
Data.f 0,0
Data.f 1,0,0
Data.f 1,0,0
Data.f 1,0
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f 1,0,0
Data.f 1,0,0
Data.f 1,0
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 1,1
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 1,1
Data.f -1,0,0
Data.f -1,0,0
Data.f 0,1
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f -1,0,0
Data.f -1,0,0
Data.f 0,1
Data.f 0,0,1
Data.f 0,0,1
Data.f 0,0
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f 1,0,0
Data.f 1,0,0
Data.f 1,0
Data.f 0,0,1
Data.f 0,0,1
Data.f 0,0
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 1,1
Data.f 1,0,0
Data.f 1,0,0
Data.f 1,0
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f -1,0,0
Data.f -1,0,0
Data.f 0,1
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 1,1
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f 0,0,1
Data.f 0,0,1
Data.f 0,0
Data.f -1,0,0
Data.f -1,0,0
Data.f 0,1
; Faces
Data.w 0,1,2
Data.w 3,4,5
Data.w 6,7,8
Data.w 9,10,11
Data.w 12,13,14
Data.w 15,16,17
Data.w 18,19,20
Data.w 21,22,23
PointyCube:
; Nb sommets / Nb faces
Data.l 72,24
; Vertices: pos / uv
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 0,0
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,0
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,0
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 1,1
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 1,1
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 0,1
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 0,1
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 0,0
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 0,0
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 1,0
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 1,0
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 1,1
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 1,1
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 0,1
Data.f 0,-1,0
Data.f 0,-1,0
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 0,1
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 0,0
Data.f 1,0,0
Data.f 1,0,0
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 0,0
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,0
Data.f 1,0,0
Data.f 1,0,0
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,0
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 1,1
Data.f 1,0,0
Data.f 1,0,0
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 1,1
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 0,1
Data.f 1,0,0
Data.f 1,0,0
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 0,1
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 0,0
Data.f -1,0,0
Data.f -1,0,0
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 0,0
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 1,0
Data.f -1,0,0
Data.f -1,0,0
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 1,0
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 1,1
Data.f -1,0,0
Data.f -1,0,0
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 1,1
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 0,1
Data.f -1,0,0
Data.f -1,0,0
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 0,1
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 0,0
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 0,0
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 1,0
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f #SQRT03,#SQRT03,-#SQRT03
Data.f 1,0
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 1,1
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f #SQRT03,-#SQRT03,-#SQRT03
Data.f 1,1
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 0,1
Data.f 0,0,-1
Data.f 0,0,-1
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f -#SQRT03,-#SQRT03,-#SQRT03
Data.f 0,1
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f -#SQRT03,#SQRT03,-#SQRT03
Data.f 0,0
Data.f 0,0,1
Data.f 0,0,1
Data.f 0.5,0.5
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 0,0
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 1,0
Data.f 0,0,1
Data.f 0,0,1
Data.f 0.5,0.5
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 1,0
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,1
Data.f 0,0,1
Data.f 0,0,1
Data.f 0.5,0.5
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 1,1
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f #SQRT03,-#SQRT03,#SQRT03
Data.f 0,1
Data.f 0,0,1
Data.f 0,0,1
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 0,1
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f -#SQRT03,-#SQRT03,#SQRT03
Data.f 0,0
; Faces
Data.w 0,1,2
Data.w 3,4,5
Data.w 6,7,8
Data.w 9,10,11
Data.w 12,13,14
Data.w 15,16,17
Data.w 18,19,20
Data.w 21,22,23
Data.w 24,25,26
Data.w 27,28,29
Data.w 30,31,32
Data.w 33,34,35
Data.w 36,37,38
Data.w 39,40,41
Data.w 42,43,44
Data.w 45,46,47
Data.w 48,49,50
Data.w 51,52,53
Data.w 54,55,56
Data.w 57,58,59
Data.w 60,61,62
Data.w 63,64,65
Data.w 66,67,68
Data.w 69,70,71
Face:
; Nb sommets / Nb faces
Data.l 3,1
; Vertices: pos / uv
Data.f 0,1,0
Data.f 0,1,0
Data.f 0.5,0.5
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f -#SQRT03,#SQRT03,#SQRT03
Data.f 0,0
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f #SQRT03,#SQRT03,#SQRT03
Data.f 1,0
; Faces
Data.w 0,1,2
EndDataSection