Trying to create a mesh from each face of another mesh

Everything related to 3D programming
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Trying to create a mesh from each face of another mesh

Post by Psychophanta »

I am trying to create a mesh from each face of another existing mesh, but don't know if there is a bug or is me who am making the things bad done.
The issue is i GetMeshData() form an Ico sphere and iterate each one of its faces to build a triangle mesh form each one, but it does not work because compiler seems unable to create the meshes.
The tip code should display at the left side the icosphere normally created, and at the right side, one of its triangle faces created as a new mesh and a new entity.
In the tip code are the comments about issue:

Code: Select all

ExamineDesktops()
RX=1280:RY=720
InitEngine3D()
InitSprite():InitKeyboard():InitMouse()
OpenWindow(0,0,0,RX,RY,"Title",#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,RX,RY,1,0,0,#PB_Screen_WaitSynchronization)
Enumeration; Camaras
  #Camara
EndEnumeration
Enumeration; Luces
  #Luz
EndEnumeration
Enumeration; Texturas
  #Textura
EndEnumeration
Enumeration; Materiales
  #Material
EndEnumeration
Enumeration; Mallas
  #Object0malla
  #Object1malla=100
EndEnumeration
Enumeration; Entidades
  #Object0
  #Object1=100
EndEnumeration
Enumeration; Nodos
  #Pivotcamara
EndEnumeration
CreateLight(#luz,$EEEEEE,4,4,2,#PB_Light_Point)
CreateCamera(#Camara,0,0,100,100):CameraRange(#Camara,0.1,10000):CameraBackColor(#Camara,$181911)
MoveCamera(#Camara,0,0,6,#PB_Absolute)
;CameraRenderMode(#Camara,#PB_Camera_Wireframe)
CreateIcoSphere(#Object0malla,1,1)
CreateEntity(#Object0,MeshID(#Object0malla),#PB_Material_None,-2,0,0)

vertices.l=MeshIndexCount(#Object0malla,0)
caras.l=vertices/3

Dim vertice.MeshVertex(vertices)
Dim celda.i(caras)
GetMeshData(#Object0malla,0,vertice.MeshVertex(),#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate|#PB_Mesh_Normal|#PB_Mesh_Color|#PB_Mesh_Tangent,0,vertices-1)
vertn.l=0
For t.l=1 To caras
  celda.i(t)=CreateMesh(#Object1malla+t-1,#PB_Mesh_TriangleList)
  debug celda.i(t); <-  MeshID(#Object1malla+t-1) number is always the same. Why ?!?!?!?!
  MeshVertex(vertice.MeshVertex(vertn)\x,vertice.MeshVertex(vertn)\y,vertice.MeshVertex(vertn)\z,0,0,$FFFFFF,vertice.MeshVertex(vertn)\NormalX,vertice.MeshVertex(vertn)\NormalY,vertice.MeshVertex(vertn)\NormalZ)
  MeshVertex(vertice.MeshVertex(vertn+1)\x,vertice.MeshVertex(vertn+1)\y,vertice.MeshVertex(vertn+1)\z,0.5,0.5,$FFFFFF,vertice.MeshVertex(vertn+1)\NormalX,vertice.MeshVertex(vertn+1)\NormalY,vertice.MeshVertex(vertn+1)\NormalZ)
  MeshVertex(vertice.MeshVertex(vertn+2)\x,vertice.MeshVertex(vertn+2)\y,vertice.MeshVertex(vertn+2)\z,1,1,$FFFFFF,vertice.MeshVertex(vertn+2)\NormalX,vertice.MeshVertex(vertn+2)\NormalY,vertice.MeshVertex(vertn+2)\NormalZ)
  MeshFace(0,1,2)
  vertn+3
  FinishMesh(1)
Next
CreateEntity(#Object1+2,MeshID(#Object1malla+2),#PB_Material_None,2,0,0) ; <- try to create only the triangle entity number 2, but it does not create nothing!!
Repeat
  ExamineMouse():ExamineKeyboard()
  WaitWindowEvent(10)
  RotateEntity(#Object0,-1,0.25,-0.5,#PB_Relative)
  RotateEntity(#Object1+2,-1,0.25,-0.5,#PB_Relative)
  TimeSinceLastFrame.i=RenderWorld(50)
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
STARGÅTE
Addict
Addict
Posts: 2232
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Trying to create a mesh from each face of another mesh

Post by STARGÅTE »

The result of GetMeshData() is 0 in your code, which means, the function fails to get the mesh data and the vertex array is empty.
However, I don't understand why GetMeshData fails here.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Trying to create a mesh from each face of another mesh

Post by Psychophanta »

My 2 cents that more tan 99% of the bugs now are related to 3D :evil: :evil: :evil:
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Trying to create a mesh from each face of another mesh

Post by yuki »

Not a PB bug. You're trying to extract more vertices than are present:

Code: Select all

vertices.l=MeshIndexCount(#Object0malla,0)
caras.l=vertices/3

Dim vertice.MeshVertex(vertices)
Dim celda.i(caras)
GetMeshData(#Object0malla,0,vertice.MeshVertex(),#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate|#PB_Mesh_Normal|#PB_Mesh_Color|#PB_Mesh_Tangent,0,vertices-1)
Changing vertices.l to MeshVertexCount(#Object0malla) will fix the failing GetMeshData(...) call.

If you want to copy/extract faces, though, you should use #PB_Mesh_Face instead of #PB_Mesh_Vertex.

The ratio between faces and vertices is unlikely to be 1:3 as vertices will often be shared/reused.

Here's an adjustment of your example, demonstrating successful copying of each triangular face from a given mesh out to their own entities:

Code: Select all

ExamineDesktops()
RX=1280:RY=720
InitEngine3D()
InitSprite():InitKeyboard():InitMouse()
OpenWindow(0,0,0,RX,RY,"Title",#PB_Window_BorderLess|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,DesktopScaledX(RX),DesktopScaledY(RY),1,0,0,#PB_Screen_WaitSynchronization)
Enumeration; Camaras
  #Camara
EndEnumeration
Enumeration; Luces
  #Luz
EndEnumeration
Enumeration; Texturas
  #Textura
EndEnumeration
Enumeration; Materiales
  #Material
EndEnumeration
Enumeration; Mallas
  #Object0malla
  #Object1malla=100
EndEnumeration
Enumeration; Entidades
  #Object0
  #Object1=100
EndEnumeration
Enumeration; Nodos
  #Pivotcamara
EndEnumeration
CreateLight(#luz,$EEEEEE,4,4,2,#PB_Light_Point)
CreateCamera(#Camara,0,0,100,100):CameraRange(#Camara,0.1,10000):CameraBackColor(#Camara,$181911)
MoveCamera(#Camara,0,0,6,#PB_Absolute)
;CameraRenderMode(#Camara,#PB_Camera_Wireframe)
CreateIcoSphere(#Object0malla,1,1)
CreateEntity(#Object0,MeshID(#Object0malla),#PB_Material_None,-2,0,0)

; Accepts a given mesh and copies each face to a new entity.
;
;  - meshToCopy    : Mesh from which faces should be copied.
;  - submeshToCopy : Submesh from which faces should be copied.
;  - outEntities   : Array which will be resized and filled with entities built.
;  - faceIndex     : Index of the mesh face to start copying from. 0-based.
;  - faceCount     : Count of faces to copy to their own entities, starting from `faceIndex`.
;
; Returns: the total count of entities created.
Procedure.i copyMeshFacesToIndividualEntities(meshToCopy.i, submeshToCopy.i, Array outEntities.i(1), faceIndex.i = 0, faceCount.i = -1)
  Protected numSrcVertices = MeshVertexCount(meshToCopy, submeshToCopy)
  Protected numSrcIndices = MeshIndexCount(meshToCopy, submeshToCopy)
  Protected numSrcFaces = numSrcIndices / 3
  
  ; Apply zero base index given OOB value.
  If faceIndex < 0
    faceIndex = 0
  EndIf
  ; Apply default face count given OOB value.
  If faceCount < 0 Or faceCount > numSrcFaces
    faceCount = numSrcFaces
  EndIf
  
  ; Calculate number of faces available after the target index.
  ; We can exit immediately if there are no such faces.
  ; Additionally, we must make sure to restrict the number of out faces based upon this
  ; (so we don't read past the end of our mesh data).
  Define numFacesAfterIndex = numSrcFaces - faceIndex
  If numFacesAfterIndex <= 0
    Goto fail
  ElseIf numFacesAfterIndex < faceCount
    faceCount = numFacesAfterIndex
  EndIf
  
  ReDim outEntities(faceCount - 1)
  
  ; Extract all vertices ahead of time, since faces could arbitrarily reference these.
  Dim vertices.MeshVertex(numSrcVertices - 1)
  If Not GetMeshData(meshToCopy, submeshToCopy, vertices(), #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_UVCoordinate | #PB_Mesh_Color | #PB_Mesh_Tangent, 0, numSrcVertices - 1)
    Debug "Failed to read mesh vertex data!"
    Goto fail
  EndIf
  
  ; Extract only indices we're interested in.
  Dim indices.MeshFace(faceCount * 3 - 1)
  If Not GetMeshData(meshToCopy, submeshToCopy, indices(), #PB_Mesh_Face, faceIndex * 3, (faceIndex + faceCount) * 3 - 1)
    Debug "Failed to read mesh face data!"
    Goto fail
  EndIf 
  
  Define x = 0, y = 0
  Define idx = 0
  For x = 0 To faceCount - 1
    Define currentOutFaceMesh = CreateMesh(#PB_Any, #PB_Mesh_TriangleList)
    For y = 0 To 2
      Define *currentSrcVertex.MeshVertex = vertices(indices(idx)\Index)
      MeshVertex(*currentSrcVertex\x,
                 *currentSrcVertex\y,
                 *currentSrcVertex\z,
                 *currentSrcVertex\u,
                 *currentSrcVertex\v,
                 *currentSrcVertex\Color,
                 *currentSrcVertex\NormalX,
                 *currentSrcVertex\NormalY,
                 *currentSrcVertex\NormalZ)
      MeshVertexTangent(*currentSrcVertex\TangentX, *currentSrcVertex\TangentY, *currentSrcVertex\TangentZ)
      idx + 1
    Next y
    MeshFace(0, 1, 2)
    FinishMesh(1)
    outEntities(x) = currentOutFaceMesh
  Next x
  
  ProcedureReturn faceCount
  
  fail:
  ReDim outEntities(0)
  ProcedureReturn 0
EndProcedure


Dim faceEntities.i(0)
Define numFaces = copyMeshFacesToIndividualEntities(#Object0malla, 0, faceEntities())

; Create an entity for each cloned face.
For x = 0 To numFaces - 1
  CreateEntity(#Object1 + x + 2, MeshID(faceEntities(x)), #PB_Material_None, 2, 0, 0)
Next x

; Create an extremely basic cursor sprite.
Define cursorSprite = CreateSprite(#PB_Any, 16, 16)
StartDrawing(SpriteOutput(cursorSprite))
Box(0, 0, OutputWidth(), OutputHeight(), $ff00ff)
StopDrawing()

Define mouseX, mouseY
Define highlightedEntity = -1
Define matDefault = CreateMaterial(#PB_Any, 0, $ffffff)
Define matHighlight = CreateMaterial(#PB_Any, #Null, $ff00ff)

Repeat
  ; Make sure to drain the event queue!
  Repeat
    Select WindowEvent()
      Case #PB_Event_CloseWindow
        Break 2
      Case #PB_Event_None
        Break
    EndSelect
  ForEver
  
  ExamineKeyboard()
  
  If ExamineMouse()
    mouseX = MouseX()
    mouseY = MouseY()
  EndIf
  
  RotateEntity(#Object0,-1,0.25,-0.5,#PB_Relative)
  ; Rotate each cloned face.
  For x = 0 To numFaces - 1 
    RotateEntity(#Object1 + x + 2,-1,0.25,-0.5,#PB_Relative)
  Next x
  
  RenderWorld()
  
  ; Render our simple cursor.
  DisplaySprite(cursorSprite, mouseX, mouseY)
  
  ; Highlight any actively hovered entity.
  Define currentHoveredEntity = MousePick(#Camara, mouseX, mouseY)
  If currentHoveredEntity <> highlightedEntity
    ; Clear previously highlighted entity since we've a change.
    If highlightedEntity >= 0
      SetEntityMaterial(highlightedEntity, MaterialID(matDefault))
      highlightedEntity = -1
    EndIf
    ; Apply highlight if we've an entity actively hovered.
    If currentHoveredEntity >= 0
      highlightedEntity = currentHoveredEntity
      SetEntityMaterial(highlightedEntity, MaterialID(matHighlight))
    EndIf
  EndIf
    
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
You can hover over the cloned entities to have the active face highlighted. (Mesh-per-face isn't an optimal approach for this scenario, but it solves OP if I've understood correctly.)

edited: fixed doc typo, removed extra event query.
Last edited by yuki on Sun Mar 12, 2023 4:56 pm, edited 1 time in total.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Trying to create a mesh from each face of another mesh

Post by Psychophanta »

All right, then no bug here this time, many thanks.
But then there is the manual that lacks elementary documentation on 3D commands and functions.

Great function really :!: :idea: , thanks again. :)
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: Trying to create a mesh from each face of another mesh

Post by Psychophanta »

I take advantage from this thread instead to open a new one.
The fact is I found a bug manifested in for the 'MeshVertexTextureCoordinate()' function.

To check it, just please replace, in the last code by "yuki", these lines:

Code: Select all

      MeshVertex(*currentSrcVertex\x,
                 *currentSrcVertex\y,
                 *currentSrcVertex\z,
                 *currentSrcVertex\u,
                 *currentSrcVertex\v,
                 *currentSrcVertex\Color,
                 *currentSrcVertex\NormalX,
                 *currentSrcVertex\NormalY,
                 *currentSrcVertex\NormalZ)
by these ones, which should be absolutely equivalent:

Code: Select all

      MeshVertexPosition(*currentSrcVertex\x,*currentSrcVertex\y,*currentSrcVertex\z)
      MeshVertexTextureCoordinate(*currentSrcVertex\u,*currentSrcVertex\v)
      MeshVertexColor(*currentSrcVertex\Color)
      MeshVertexNormal(*currentSrcVertex\NormalX,*currentSrcVertex\NormalY,*currentSrcVertex\NormalZ)
The program halts at function 'MeshVertexTextureCoordinate()' :shock:
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply