J'ai ici un code qui part d'un mesh quelconque, puis subdivise ses faces et "sphérise" le tout en mettant tous les vertices à une distance identique du centre du mesh. (les spécialistes auront peut-être reconnu là l'algo qui permet de construire une géosphère).
Là dessus, je veux recalculer les normales des vertices du mesh afin de "smoother" le rendu (= lisser les facettes).
Avec une sphère de taille 1, c'est assez simple (la normale du vertex est égale à sa position, je crois), mais je veux une procédure qui puisse marcher avec n'importe quel mesh, histoire de me familiariser avec le concept.
Mais curieusement, le rendu me semble présenter des défauts: j'ai l'impression que l'éclairage de certains triangles est "inversé": à la limite lumière/ombre, ça fait un motif dentelé bizarroïde.


Est-ce mon calcul des normales qui est faux, ou bien me plante-je en construisant le mesh (genre: un triangle construit avec les vertices dans le mauvais ordre) ?
Voici le code:
Code : Tout sélectionner
; Author: Kelebrindae
; Date: june,13,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
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
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
*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
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
*PtrNewF\f2=newVertNum +1
*PtrNewF\f3=newVertNum +2
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
*PtrNewF\f2=newVertNum +1
*PtrNewF\f3=newVertNum +2
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
*PtrNewF\f2=newVertNum +1
*PtrNewF\f3=newVertNum +2
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\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\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)
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
; "Spherify"
inflateMesh(nummesh)
; 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: 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 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)
EndProcedure
;************************************************************************************
;- ---- Main loop ----
;-Mesh
; Change parameters 2 to 8 to test the effects on size and texturing
Global myOctaMesh.l
myOctaMesh = CreateDynMesh("Octa",#octahedron,3,3,3,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)
Box(0, 0, 128, 128, $0000FF)
StopDrawing()
;-Material
CreateMaterial(0,TextureID(0))
;-Entity
CreateEntity(0,MeshID(dynMesh(myOctaMesh)\numMesh),MaterialID(0))
;-Camera
CreateCamera(0, 0, 0 , 100 , 100)
MoveCamera(0,0,0,-15)
CameraLookAt(0,0,0,0)
;-Light
AmbientColor(RGB(63,63,63))
CreateLight(0,RGB(255,255,255),200,300,0)
;CreateLight(1,RGB(255,127,0),-200,-200,200)
Global pas.f,angle.f
pas = 0.8
angle = 0
Repeat
If fullscreen = 0
While WindowEvent() : Wend
EndIf
; Rotate
Angle + Pas
RotateEntity(0, angle,angle/2,-angle)
; Wireframe or not
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
EndIf
; show it all
RenderWorld()
; A little help
StartDrawing(ScreenOutput())
DrawText(0,0,"[F1] to change RenderMode, [S] to subdivide mesh, [N] to smooth normals ", $00FFFF, $BB0000)
DrawText(0,15,Str(dynMesh(0)\nbVert) + " vertices, taille du buffer = " + Str(MemorySize(dynMesh(0)\vertexBuffer)) + " octets", $00FFFF, $BB0000)
DrawText(0,30,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
EndDataSection