Author Topic: 2d pixels text to 3d mesh text  (Read 432 times)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
2d pixels text to 3d mesh text
« on: November 27, 2018, 05:40:14 PM »
Code: [Select]
;see next posts for latest code

Offline MrmediamanX

  • Jr. Member
  • **
  • Posts: 12
Re: 2d pixels text to 3d mesh text
« Reply #1 on: November 28, 2018, 02:51:38 AM »
nice but couldn't one just use milkshapes text tool?
assuming the code turns text into a 3d mesh.

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #2 on: November 28, 2018, 04:31:59 PM »
Code: [Select]
assuming the code turns text into a 3d mesh.
so you have not tested the code and you comment... very constructive, thanks for the useful feedback  :-*


there are many uses of such code, especially if you like to build scenes / maps proceduraly, which is my thing...
(this is a just a start, i plan to improve it, to remove notvisible tris, and to auto uvmap the resulting shape with a precise texel size)

Online Steve Elliott

  • Hero Member
  • *****
  • Posts: 1343
  • You secure that shit Hudson!!
Re: 2d pixels text to 3d mesh text
« Reply #3 on: November 28, 2018, 08:47:56 PM »
Quote
assuming the code turns text into a 3d mesh.

When you assume, you make an ass out of u and me   ;D  Well out of RemiD.
Windows 10, 64-bit, 8Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb)

Offline MrmediamanX

  • Jr. Member
  • **
  • Posts: 12
Re: 2d pixels text to 3d mesh text
« Reply #4 on: November 29, 2018, 03:41:16 AM »
tested though unfortunately wouldn't function ... hence presumed assumption.
according to the title.
granted for procedurally generated based maps, I can see how it could be of use.
like this one time at band camp I took a 3d maze generation code,shifted the camera to a top down
view, rotated everything to align to the zaxis/wall[now floor] and came up with a 2.5d proc gen platformer.
good times. :)



Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #5 on: November 29, 2018, 04:54:03 PM »
Quote
tested though unfortunately wouldn't function
what is the error / problem ? (the code above does not need any external file to run, you only have to have Blitz3d installed)



For the demo i am making, i need to have an uniform texel size on all shapes / terrain, so even if there is never only one way to reach a result, i don't see myself modeling and uvmaping 26 letters, so i am going to do it in code !

Offline MrmediamanX

  • Jr. Member
  • **
  • Posts: 12
Re: 2d pixels text to 3d mesh text
« Reply #6 on: November 29, 2018, 05:15:39 PM »
 my bad, it occurred when selecting the code ... one minor letter t'was all ... darn 'functio' >:(
looks good,does what's stated ... very nice. :)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #7 on: November 29, 2018, 05:26:02 PM »
Ok...

Actually it is just a start, to demonstrate how to do it for those who are interested to learn...

It is not optimised at all (notvisible tris within the mesh, not uvmapped)

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #8 on: December 01, 2018, 11:20:50 AM »
what seems like a simple thing to create (3d letters, with the same proportions than the 2d letters of a font), becomes a nightmare when you want to uvmap these 3d shapes with a uniform texel size (especially when it must be big (corresponding to 0.125unit), like what i want)

so i have done some test to modelize these 3d letters in Fragmotion, and then to uvmap them one by one, but since i want a big texel size, again i encounter this problem of cut texels... (since they are big...)

so back inside Blitz3d to try to do it all in code...

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #9 on: December 01, 2018, 05:43:39 PM »
done ! 8)

so in this new version, there are no notvisible tris (within the mesh), and the shapes are uvmapped and the texel size is almost uniform (but it also depends on how the chars of the font are structured, because fitmesh() can stretch some chars if they don't fill all extremities of the average char area (example a 12x16y area for a 16font))
Code: [Select]
;2dchars (pixels) to 3dchars (meshes) by RemiD (20181201)
;this will convert the 2d chars of a font to 3d chars meshes (made of uvmaped quads)
;this can work with any font, however if you want to keep a uniform texel size,
;it is preferable to use a font in which the chars have approximately the same width,height (for example a 12x16y area for a 16font),
;and each char fills most extremities of the 12x16y area (because of the use of fitmesh() which uses the vertices at the extremities to resize the mesh)

;graphics window
Graphics3D(640,480,32,2)

HidePointer()

SeedRnd(MilliSecs())

;Camera
Global Camera = CreateCamera()
CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())
CameraRange(Camera,0.15,150)
CameraClsColor(Camera,000,000,000)

;Listener
Global Listener = CreateListener(Camera)

;Input
Global MX%, MY%
Global MXDiff%, MYDiff%

;Origine
Global Origine = CreateCube()
ScaleMesh(Origine,0.01,0.01,0.01)
EntityColor(Origine,255,000,255)
EntityFX(Origine,1)

;InteractionMode
Global InteractionMode%
Const C2D% = 1
Const C3D% = 2
InteractionMode = C3D
HidePointer()

;Ghost
Global GhostRoot
Global GhostRootYaw#
Global GhostEyes
Global GhostEyesPitch#
AddGhost()

;Chars
Global CharsCount%
Dim CharStr$(100)
Dim CharPWidth%(100)
Dim CharPHeight%(100)
Dim CharImage(100)
Dim CharMesh(100)
Dim CharTexture(100)

XFont = LoadFont("Blitz",16,False,False,False)
SetFont(XFont)

AllStr$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;"abcdefghijklmnopqrstuvwxyz" ;"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
AllWidth% = StringWidth(AllStr) : AllHeight% = StringHeight(AllStr)

For n% = 1 To Len(AllStr) Step 1
 CharsCount = CharsCount + 1 : I% = CharsCount
 CharStr(I) = Mid(AllStr,n,1)
 CharPWidth(I) = StringWidth(CharStr(I)) : CharPHeight(I) = StringHeight(CharStr(I))
 DebugLog(CharStr(I)+" "+CharPWidth(I)+","+CharPHeight(I))
 CharImage(I) = CreateImage(CharPWidth(I),CharPHeight(I))
 SetBuffer(ImageBuffer(CharImage(I)))
 ClsColor(Rand(025,255),Rand(025,255),Rand(025,255)) : Cls()
 Color(125,125,125) : Text(0,0,CharStr(I))
 CharMesh(I) = CreateMesh() : CreateSurface(CharMesh(I))
 CharTexture(I) = CreateTexture(2048,8)
 SetBuffer(TextureBuffer(CharTexture(I)))
  ClsColor(255,255,255) : Cls()
  For nn% = 1 To 256 Step 1
   SPX% = (nn-1)*8 : SPY% = 0
   ColR% = Rand(025,225) : ColG% = Rand(025,225) : ColB% = Rand(025,225)
   For PX% = SPX To SPX+8 Step 1
    For PY% = SPY To SPY+8 Step 1
     PR% = ColR+Rand(-012,+012) : PG% = ColG+Rand(-012,+012) : PB% = ColB+Rand(-012,+012)
     Color(PR,PG,PB) : Plot(PX,PY)
    Next
   Next
  Next
 EntityTexture(CharMesh(I),CharTexture(I))
Next
DebugLog(CharsCount)

PX% = 0 : PY% = 0
SetBuffer(BackBuffer())
ClsColor(000,000,000) : Cls()
For I% = 1 To CharsCount Step 1
 DrawImage(CharImage(I),PX,PY)
 PX% = PX+ImageWidth(CharImage(I))
Next
Flip()
;WaitKey()

;pixels list
Global PixsCount%
Dim PixPX%(16*16)
Dim PixPY%(16*16)

;premodel + preuvmap the part which will compose the chars meshes (1texel corresponds to 0.125unit)
Global XPart = CreateMesh()
Surface = CreateSurface(XPart)
AddVertex(Surface,-0.5,+0.5,0.0) : VertexTexCoords(Surface,0,Float(0)/8,Float(0)/8)
AddVertex(Surface,+0.5,+0.5,0.0) : VertexTexCoords(Surface,1,Float(8)/8,Float(0)/8)
AddVertex(Surface,-0.5,-0.5,0.0) : VertexTexCoords(Surface,2,Float(0)/8,Float(8)/8)
AddVertex(Surface,+0.5,-0.5,0.0) : VertexTexCoords(Surface,3,Float(8)/8,Float(8)/8)
AddTriangle(Surface,0,1,2)
AddTriangle(Surface,2,1,3)
UpdateNormals(XPart)
HideEntity(XPart)

OffsetX# = 0 : OffsetY# = 0
;for each char
For I% = 1 To CharsCount Step 1

 PixsCount = 0
 PartsCount% = 0
 VerticesCount% = 0
 CPX% = 0 : CPY% = 0

 SetBuffer(ImageBuffer(CharImage(I)))
 ;for each pixel in the char image
 ;list the pixels composing the char
 For PX% = 0 To ImageWidth(CharImage(I))-1 Step 1
  For PY% = 0 To ImageHeight(CharImage(I))-1 Step 1
   GetColor(PX,PY)
   PixRed = ColorRed() : PixGreen = ColorGreen() : PixBlue = ColorBlue()
   If( PixRed = 125 And PixGreen = 125 And PixBlue = 125 )
    PixsCount = PixsCount + 1 : II% = PixsCount
    PixPX(II) = PX : PixPY(II) = PY
   EndIf
  Next
 Next
 ;DebugLog(PixsCount)

 Surface = GetSurface(CharMesh(I),1)
 ;for each pixel composing the char
 For II% = 1 To PixsCount Step 1
  PX% = PixPX(II) : PY% = PixPY(II)

  ;add a part at front
  PartsCount = PartsCount + 1
  TPart = CopyMesh(XPart)
  X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = -0.5
  PositionMesh(TPart,X,Y,Z)
  AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
  VerticesCount = VerticesCount + 4
  CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
  CPX = CPX + 8 : CPY = 0

  ;add a part at back
  PartsCount = PartsCount + 1
  TPart = CopyMesh(XPart)
  RotateMesh(TPart,0,180,0)
  X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = +0.5
  PositionMesh(TPart,X,Y,Z)
  AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
  VerticesCount = VerticesCount + 4
  CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
  CPX = CPX + 8 : CPY = 0

  ;check if there is a neighboor at top
  ;if no
  If( IsPix(CharImage(I),PX,PY-1,125,125,125)=False )
   ;add a part on sidetop
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,+90,0,0)
   X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+1.0 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

  ;check if there is a neighboor at bottom
  ;if no
  If( IsPix(CharImage(I),PX,PY+1,125,125,125)=False )
   ;add a part on sidebottom
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,-90,0,0)
   X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

  ;check if there is a neighboor at left
  ;if no
  If( IsPix(CharImage(I),PX-1,PY,125,125,125)=False )
   ;add a part on sideleft
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,0,-90,0)
   X# = PX+0 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf
 
  ;check if there is a neighboor at right
  ;if no
  If( IsPix(CharImage(I),PX+1,PY,125,125,125)=False )
   ;add a part on sideright
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,0,+90,0)
   X# = PX+1 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

 Next
 DebugLog(PartsCount)
 DebugLog(VerticesCount)
 DebugLog(CountVertices(GetSurface(CharMesh(I),1))+" "+CountTriangles(GetSurface(CharMesh(I),1)))

 ;resize the mesh to fit in an ideal area (for a 16font this would be a 12x16y area (in 2D) and a 1.2w1.6h0.2d area (in 3D))
 FitMesh(CharMesh(I),0,0,0,1.2,1.6,0.2)

 PositionEntity(CharMesh(I),OffsetX,OffsetY,0,True)
 RotateEntity(CharMesh(I),Rand(-12.5,+12.5),0,0,True)

 ;OffsetX = OffsetX + CharPWidth(I)
 ;OffsetY = Rand(-2,+2)

 OffsetX = OffsetX + (0.1+1.2+0.1)
 OffsetY = Rnd(-0.2,+0.2)

 ;export the char image

 ;export the char mesh

Next

;DebugBox = CreateCube()
;ScaleMesh(DebugBox,Float(AllWidth)/2,Float(AllHeight)/2,1.0/2)
;PositionMesh(DebugBox,Float(AllWidth)/2,Float(AllHeight)/2,0)
;EntityAlpha(DebugBox,0.1)
;EntityFX(DebugBox,1)

;for each char

 ;load the char image

 ;load the char mesh

;specify a word

;write the word using 2d letters (in a 2d world with images)

;write the word using 3d letters (in a 3d world with meshes)

;light
DLight = CreateLight(1)
LightColor(DLight,255,255,255)
PositionEntity(DLight,0,1000,-1000,True)
RotateEntity(DLight,45,0,0,True)

AmbientLight(025,025,025)

PositionEntity(GhostRoot,0,0+1.65,-3,True)
GhostRootYaw = 0 : GhostEyesPitch = 0

Global MainLoopTimer = CreateTimer(30)

Main()

End()

Function Main()

 Repeat
 
  MainLoopMilliStart% = MilliSecs()

  MX = MouseX() : MY = MouseY()

  MXDiff = MouseXSpeed() : MYDiff = MouseYSpeed()

  UpdateInteractionMode()
  If( InteractionMode = C2D )
   ;
  Else If( InteractionMode = C3D )
   UpdateGhost()    
  EndIf    

  WireFrame(False)
  If( KeyDown(2)=1 )
   WireFrame(True)
  EndIf

  PositionEntity(Camera,EntityX(GhostEyes,True),EntityY(GhostEyes,True),EntityZ(GhostEyes,True),True)
  RotateEntity(Camera,EntityPitch(GhostEyes,True),EntityYaw(GhostEyes,True),EntityRoll(GhostEyes,True),True)

  CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())
  CameraClsColor(Camera,000,000,000)
  SetBuffer(BackBuffer())
  RenderWorld()

  Color(255,255,255)
  If( KeyDown(3)=1 )
   Text(0,0,"Tris = "+TrisRendered())
   Text(0,15,"FPS = "+FPS)
  EndIf

  ;Flip(1)
  WaitTimer(MainLoopTimer)
  VWait():Flip(False)

  MainLoopMilliTime = MilliSecs() - MainLoopMilliStart
  If( MainLoopMilliTime < 1 )
   MainLoopMilliTime = 1
  EndIf

  FPS% = 1000.0/MainLoopMilliTime

 Until( KeyDown(1)=1 )

End Function

Function IsPix%(Image,PX%,PY%,PR%,PG%,PB%)

 SetBuffer(ImageBuffer(Image))
 GetColor(PX,PY)
 PixRed = ColorRed() : PixGreen = ColorGreen() : PixBlue = ColorBlue()
 If( PixRed = PR And PixGreen = PG And PixBlue = PB )
  Return True
 Else
  Return False
 EndIf

End Function

Function CalculatePartUVs(Surface,V0I%,V1I%,V2I%,V3I%,CPX%,CPY%)
 
 V0U# = Float(CPX+0)/2048 : V0V# = Float(CPY+0)/8 : VertexTexCoords(Surface,V0I,V0U,V0V)
 V1U# = Float(CPX+8)/2048 : V1V# = Float(CPY+0)/8 : VertexTexCoords(Surface,V1I,V1U,V1V)
 V2U# = Float(CPX+0)/2048 : V2V# = Float(CPY+8)/8 : VertexTexCoords(Surface,V2I,V2U,V2V)
 V3U# = Float(CPX+8)/2048 : V3V# = Float(CPY+8)/8 : VertexTexCoords(Surface,V3I,V3U,V3V)

End Function

Function UpdateInteractionMode()

 If( KeyHit(15)=1 )
  If( InteractionMode = C2D )
   InteractionMode = C3D
   HidePointer()
  Else If( InteractionMode = C3D )
   InteractionMode = C2D
   ShowPointer()
  EndIf
 EndIf

End Function

Function AddGhost()
 
 GhostRoot = CreatePivot()

 GhostEyes = CreatePivot()

 EntityParent(GhostEyes,GhostRoot,True)

End Function

Function UpdateGhost()

 MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2)
 GhostEyesPitch = GhostEyesPitch + Float(MYDiff)/10
 If( GhostEyesPitch < -89 )
  GhostEyesPitch = -89
 Else If( GhostEyesPitch > 89 )
  GhostEyesPitch = 89
 EndIf
 RotateEntity(GhostEyes,GhostEyesPitch,0,0,False)
 GhostRootYaw = GhostRootYaw - Float(MXDiff)/10
 RotateEntity(GhostRoot,0,GhostRootYaw,0,False)

 If( KeyDown(42) = 0 And KeyDown(29) = 0 )
  Speed# = 0.1
 Else If( KeyDown(42) = 1 And KeyDown(29) = 0 )
  Speed# = 1
 Else If( KeyDown(42) = 0 And KeyDown(29) = 1 )
  Speed# = 0.01
 EndIf

 If( KeyDown(17)=1 )
  MoveEntity(GhostRoot,0,0,Speed)
 Else If( KeyDown(31)=1 )
  MoveEntity(GhostRoot,0,0,-Speed)
 EndIf
 If( KeyDown(30)=1 )
  MoveEntity(GhostRoot,-Speed,0,0)
 Else If( KeyDown(32)=1 )
  MoveEntity(GhostRoot,Speed,0,0)
 EndIf
 If( KeyDown(16)=1 )
  MoveEntity(GhostRoot,0,-Speed,0)
 Else If( KeyDown(18)=1 )
  MoveEntity(GhostRoot,0,Speed,0)
 EndIf
 
End Function


Offline STEVIE G

  • Sr. Member
  • ****
  • Posts: 252
Re: 2d pixels text to 3d mesh text
« Reply #10 on: December 02, 2018, 12:00:35 AM »
done ! 8)

so in this new version, there are no notvisible tris (within the mesh), and the shapes are uvmapped and the texel size is almost uniform (but it also depends on how the chars of the font are structured, because fitmesh() can stretch some chars if they don't fill all extremities of the average char area (example a 12x16y area for a 16font))
Code: [Select]
;2dchars (pixels) to 3dchars (meshes) by RemiD (20181201)
;this will convert the 2d chars of a font to 3d chars meshes (made of uvmaped quads)
;this can work with any font, however if you want to keep a uniform texel size,
;it is preferable to use a font in which the chars have approximately the same width,height (for example a 12x16y area for a 16font),
;and each char fills most extremities of the 12x16y area (because of the use of fitmesh() which uses the vertices at the extremities to resize the mesh)

;graphics window
Graphics3D(640,480,32,2)

HidePointer()

SeedRnd(MilliSecs())

;Camera
Global Camera = CreateCamera()
CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())
CameraRange(Camera,0.15,150)
CameraClsColor(Camera,000,000,000)

;Listener
Global Listener = CreateListener(Camera)

;Input
Global MX%, MY%
Global MXDiff%, MYDiff%

;Origine
Global Origine = CreateCube()
ScaleMesh(Origine,0.01,0.01,0.01)
EntityColor(Origine,255,000,255)
EntityFX(Origine,1)

;InteractionMode
Global InteractionMode%
Const C2D% = 1
Const C3D% = 2
InteractionMode = C3D
HidePointer()

;Ghost
Global GhostRoot
Global GhostRootYaw#
Global GhostEyes
Global GhostEyesPitch#
AddGhost()

;Chars
Global CharsCount%
Dim CharStr$(100)
Dim CharPWidth%(100)
Dim CharPHeight%(100)
Dim CharImage(100)
Dim CharMesh(100)
Dim CharTexture(100)

XFont = LoadFont("Blitz",16,False,False,False)
SetFont(XFont)

AllStr$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;"abcdefghijklmnopqrstuvwxyz" ;"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
AllWidth% = StringWidth(AllStr) : AllHeight% = StringHeight(AllStr)

For n% = 1 To Len(AllStr) Step 1
 CharsCount = CharsCount + 1 : I% = CharsCount
 CharStr(I) = Mid(AllStr,n,1)
 CharPWidth(I) = StringWidth(CharStr(I)) : CharPHeight(I) = StringHeight(CharStr(I))
 DebugLog(CharStr(I)+" "+CharPWidth(I)+","+CharPHeight(I))
 CharImage(I) = CreateImage(CharPWidth(I),CharPHeight(I))
 SetBuffer(ImageBuffer(CharImage(I)))
 ClsColor(Rand(025,255),Rand(025,255),Rand(025,255)) : Cls()
 Color(125,125,125) : Text(0,0,CharStr(I))
 CharMesh(I) = CreateMesh() : CreateSurface(CharMesh(I))
 CharTexture(I) = CreateTexture(2048,8)
 SetBuffer(TextureBuffer(CharTexture(I)))
  ClsColor(255,255,255) : Cls()
  For nn% = 1 To 256 Step 1
   SPX% = (nn-1)*8 : SPY% = 0
   ColR% = Rand(025,225) : ColG% = Rand(025,225) : ColB% = Rand(025,225)
   For PX% = SPX To SPX+8 Step 1
    For PY% = SPY To SPY+8 Step 1
     PR% = ColR+Rand(-012,+012) : PG% = ColG+Rand(-012,+012) : PB% = ColB+Rand(-012,+012)
     Color(PR,PG,PB) : Plot(PX,PY)
    Next
   Next
  Next
 EntityTexture(CharMesh(I),CharTexture(I))
Next
DebugLog(CharsCount)

PX% = 0 : PY% = 0
SetBuffer(BackBuffer())
ClsColor(000,000,000) : Cls()
For I% = 1 To CharsCount Step 1
 DrawImage(CharImage(I),PX,PY)
 PX% = PX+ImageWidth(CharImage(I))
Next
Flip()
;WaitKey()

;pixels list
Global PixsCount%
Dim PixPX%(16*16)
Dim PixPY%(16*16)

;premodel + preuvmap the part which will compose the chars meshes (1texel corresponds to 0.125unit)
Global XPart = CreateMesh()
Surface = CreateSurface(XPart)
AddVertex(Surface,-0.5,+0.5,0.0) : VertexTexCoords(Surface,0,Float(0)/8,Float(0)/8)
AddVertex(Surface,+0.5,+0.5,0.0) : VertexTexCoords(Surface,1,Float(8)/8,Float(0)/8)
AddVertex(Surface,-0.5,-0.5,0.0) : VertexTexCoords(Surface,2,Float(0)/8,Float(8)/8)
AddVertex(Surface,+0.5,-0.5,0.0) : VertexTexCoords(Surface,3,Float(8)/8,Float(8)/8)
AddTriangle(Surface,0,1,2)
AddTriangle(Surface,2,1,3)
UpdateNormals(XPart)
HideEntity(XPart)

OffsetX# = 0 : OffsetY# = 0
;for each char
For I% = 1 To CharsCount Step 1

 PixsCount = 0
 PartsCount% = 0
 VerticesCount% = 0
 CPX% = 0 : CPY% = 0

 SetBuffer(ImageBuffer(CharImage(I)))
 ;for each pixel in the char image
 ;list the pixels composing the char
 For PX% = 0 To ImageWidth(CharImage(I))-1 Step 1
  For PY% = 0 To ImageHeight(CharImage(I))-1 Step 1
   GetColor(PX,PY)
   PixRed = ColorRed() : PixGreen = ColorGreen() : PixBlue = ColorBlue()
   If( PixRed = 125 And PixGreen = 125 And PixBlue = 125 )
    PixsCount = PixsCount + 1 : II% = PixsCount
    PixPX(II) = PX : PixPY(II) = PY
   EndIf
  Next
 Next
 ;DebugLog(PixsCount)

 Surface = GetSurface(CharMesh(I),1)
 ;for each pixel composing the char
 For II% = 1 To PixsCount Step 1
  PX% = PixPX(II) : PY% = PixPY(II)

  ;add a part at front
  PartsCount = PartsCount + 1
  TPart = CopyMesh(XPart)
  X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = -0.5
  PositionMesh(TPart,X,Y,Z)
  AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
  VerticesCount = VerticesCount + 4
  CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
  CPX = CPX + 8 : CPY = 0

  ;add a part at back
  PartsCount = PartsCount + 1
  TPart = CopyMesh(XPart)
  RotateMesh(TPart,0,180,0)
  X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = +0.5
  PositionMesh(TPart,X,Y,Z)
  AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
  VerticesCount = VerticesCount + 4
  CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
  CPX = CPX + 8 : CPY = 0

  ;check if there is a neighboor at top
  ;if no
  If( IsPix(CharImage(I),PX,PY-1,125,125,125)=False )
   ;add a part on sidetop
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,+90,0,0)
   X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+1.0 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

  ;check if there is a neighboor at bottom
  ;if no
  If( IsPix(CharImage(I),PX,PY+1,125,125,125)=False )
   ;add a part on sidebottom
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,-90,0,0)
   X# = PX+0.5 : Y# = ImageHeight(CharImage(I))-PY+0 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

  ;check if there is a neighboor at left
  ;if no
  If( IsPix(CharImage(I),PX-1,PY,125,125,125)=False )
   ;add a part on sideleft
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,0,-90,0)
   X# = PX+0 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf
 
  ;check if there is a neighboor at right
  ;if no
  If( IsPix(CharImage(I),PX+1,PY,125,125,125)=False )
   ;add a part on sideright
   PartsCount = PartsCount + 1
   TPart = CopyMesh(XPart)
   RotateMesh(TPart,0,+90,0)
   X# = PX+1 : Y# = ImageHeight(CharImage(I))-PY+0.5 : Z# = 0
   PositionMesh(TPart,X,Y,Z)
   AddMesh(TPart,CharMesh(I)) : FreeEntity(TPart)
   VerticesCount = VerticesCount + 4
   CalculatePartUVs(Surface,VerticesCount-4,VerticesCount-3,VerticesCount-2,VerticesCount-1,CPX,CPY)
   CPX = CPX + 8 : CPY = 0
  EndIf

 Next
 DebugLog(PartsCount)
 DebugLog(VerticesCount)
 DebugLog(CountVertices(GetSurface(CharMesh(I),1))+" "+CountTriangles(GetSurface(CharMesh(I),1)))

 ;resize the mesh to fit in an ideal area (for a 16font this would be a 12x16y area (in 2D) and a 1.2w1.6h0.2d area (in 3D))
 FitMesh(CharMesh(I),0,0,0,1.2,1.6,0.2)

 PositionEntity(CharMesh(I),OffsetX,OffsetY,0,True)
 RotateEntity(CharMesh(I),Rand(-12.5,+12.5),0,0,True)

 ;OffsetX = OffsetX + CharPWidth(I)
 ;OffsetY = Rand(-2,+2)

 OffsetX = OffsetX + (0.1+1.2+0.1)
 OffsetY = Rnd(-0.2,+0.2)

 ;export the char image

 ;export the char mesh

Next

;DebugBox = CreateCube()
;ScaleMesh(DebugBox,Float(AllWidth)/2,Float(AllHeight)/2,1.0/2)
;PositionMesh(DebugBox,Float(AllWidth)/2,Float(AllHeight)/2,0)
;EntityAlpha(DebugBox,0.1)
;EntityFX(DebugBox,1)

;for each char

 ;load the char image

 ;load the char mesh

;specify a word

;write the word using 2d letters (in a 2d world with images)

;write the word using 3d letters (in a 3d world with meshes)

;light
DLight = CreateLight(1)
LightColor(DLight,255,255,255)
PositionEntity(DLight,0,1000,-1000,True)
RotateEntity(DLight,45,0,0,True)

AmbientLight(025,025,025)

PositionEntity(GhostRoot,0,0+1.65,-3,True)
GhostRootYaw = 0 : GhostEyesPitch = 0

Global MainLoopTimer = CreateTimer(30)

Main()

End()

Function Main()

 Repeat
 
  MainLoopMilliStart% = MilliSecs()

  MX = MouseX() : MY = MouseY()

  MXDiff = MouseXSpeed() : MYDiff = MouseYSpeed()

  UpdateInteractionMode()
  If( InteractionMode = C2D )
   ;
  Else If( InteractionMode = C3D )
   UpdateGhost()    
  EndIf    

  WireFrame(False)
  If( KeyDown(2)=1 )
   WireFrame(True)
  EndIf

  PositionEntity(Camera,EntityX(GhostEyes,True),EntityY(GhostEyes,True),EntityZ(GhostEyes,True),True)
  RotateEntity(Camera,EntityPitch(GhostEyes,True),EntityYaw(GhostEyes,True),EntityRoll(GhostEyes,True),True)

  CameraViewport(Camera,0,0,GraphicsWidth(),GraphicsHeight())
  CameraClsColor(Camera,000,000,000)
  SetBuffer(BackBuffer())
  RenderWorld()

  Color(255,255,255)
  If( KeyDown(3)=1 )
   Text(0,0,"Tris = "+TrisRendered())
   Text(0,15,"FPS = "+FPS)
  EndIf

  ;Flip(1)
  WaitTimer(MainLoopTimer)
  VWait():Flip(False)

  MainLoopMilliTime = MilliSecs() - MainLoopMilliStart
  If( MainLoopMilliTime < 1 )
   MainLoopMilliTime = 1
  EndIf

  FPS% = 1000.0/MainLoopMilliTime

 Until( KeyDown(1)=1 )

End Function

Function IsPix%(Image,PX%,PY%,PR%,PG%,PB%)

 SetBuffer(ImageBuffer(Image))
 GetColor(PX,PY)
 PixRed = ColorRed() : PixGreen = ColorGreen() : PixBlue = ColorBlue()
 If( PixRed = PR And PixGreen = PG And PixBlue = PB )
  Return True
 Else
  Return False
 EndIf

End Function

Function CalculatePartUVs(Surface,V0I%,V1I%,V2I%,V3I%,CPX%,CPY%)
 
 V0U# = Float(CPX+0)/2048 : V0V# = Float(CPY+0)/8 : VertexTexCoords(Surface,V0I,V0U,V0V)
 V1U# = Float(CPX+8)/2048 : V1V# = Float(CPY+0)/8 : VertexTexCoords(Surface,V1I,V1U,V1V)
 V2U# = Float(CPX+0)/2048 : V2V# = Float(CPY+8)/8 : VertexTexCoords(Surface,V2I,V2U,V2V)
 V3U# = Float(CPX+8)/2048 : V3V# = Float(CPY+8)/8 : VertexTexCoords(Surface,V3I,V3U,V3V)

End Function

Function UpdateInteractionMode()

 If( KeyHit(15)=1 )
  If( InteractionMode = C2D )
   InteractionMode = C3D
   HidePointer()
  Else If( InteractionMode = C3D )
   InteractionMode = C2D
   ShowPointer()
  EndIf
 EndIf

End Function

Function AddGhost()
 
 GhostRoot = CreatePivot()

 GhostEyes = CreatePivot()

 EntityParent(GhostEyes,GhostRoot,True)

End Function

Function UpdateGhost()

 MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2)
 GhostEyesPitch = GhostEyesPitch + Float(MYDiff)/10
 If( GhostEyesPitch < -89 )
  GhostEyesPitch = -89
 Else If( GhostEyesPitch > 89 )
  GhostEyesPitch = 89
 EndIf
 RotateEntity(GhostEyes,GhostEyesPitch,0,0,False)
 GhostRootYaw = GhostRootYaw - Float(MXDiff)/10
 RotateEntity(GhostRoot,0,GhostRootYaw,0,False)

 If( KeyDown(42) = 0 And KeyDown(29) = 0 )
  Speed# = 0.1
 Else If( KeyDown(42) = 1 And KeyDown(29) = 0 )
  Speed# = 1
 Else If( KeyDown(42) = 0 And KeyDown(29) = 1 )
  Speed# = 0.01
 EndIf

 If( KeyDown(17)=1 )
  MoveEntity(GhostRoot,0,0,Speed)
 Else If( KeyDown(31)=1 )
  MoveEntity(GhostRoot,0,0,-Speed)
 EndIf
 If( KeyDown(30)=1 )
  MoveEntity(GhostRoot,-Speed,0,0)
 Else If( KeyDown(32)=1 )
  MoveEntity(GhostRoot,Speed,0,0)
 EndIf
 If( KeyDown(16)=1 )
  MoveEntity(GhostRoot,0,-Speed,0)
 Else If( KeyDown(18)=1 )
  MoveEntity(GhostRoot,0,Speed,0)
 EndIf
 
End Function

You can get around the extremities issues by adding dummy vertices at the extremities for each character mesh.  You don't have to add any triangles.  Had to use something like this when building my own 3d font for Polymaniacs.

Offline RemiD

  • Hero Member
  • *****
  • Posts: 754
Re: 2d pixels text to 3d mesh text
« Reply #11 on: December 02, 2018, 08:57:31 AM »
Quote
You can get around the extremities issues by adding dummy vertices at the extremities for each character mesh.
yes good idea, thanks  :)

but i think that it is preferable to slightly edit an existing font, or to make your own font, because some chars can cause problems (for example "I" "i") because depending on the font, the char is not centered in the 12x16y area, so even if you don't stretch it (by adding vertices at each corner, like you suggest) it still looks weird imo. It depends how the author has decided to draw some chars...