Zwei Fragen - Rotation und Text3D

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

Zwei Fragen - Rotation und Text3D

Beitrag von Makke »

Hallo zusammen,

als ich endlich mal wieder etwas Zeit gefunden habe und FreeOrion spielte, kam mir die Idee, ob man so eine Galaxiekarte nicht auch in 3D erstellen könnte. Also Purebasic gestartet und direkt mal was ausprobiert. Direkt nach dem Start bin ich auf zwei Probleme gestoßen. Doch hier zunächst der Beispielcode:

Code: Alles auswählen

#APPNAME = "SpaceTest"
#FRONTCAM = 0
#COLOR_LINE = $202020

UsePNGImageDecoder()

Structure CameraPositionOuter
  x.i
  y.i
  z.i
  deg.f
  rad.i
  spd.f
EndStructure

Structure PlanetPositionOuter
  name.s
  x.i
  y.i
  z.i
  size.i
  material.i
  mesh.i
  entity.i
  text3d.i
EndStructure

Procedure CalculateCameraPosHor(*pos.CameraPositionOuter, right.i=#False)
  If right
    *pos\deg - *pos\spd
  Else
    *pos\deg + *pos\spd
  EndIf
  If *pos\deg < 0
    *pos\deg = 359 + (1-*pos\deg)
  ElseIf *pos\deg > 360
    *pos\deg = *pos\deg - 360
  EndIf : Debug *pos\deg
  *pos\x = *pos\rad * Cos(*pos\deg) + 2500
  *pos\z = *pos\rad * Sin(*pos\deg) + 2500
EndProcedure

; init
If InitEngine3D()
  CurrentDir.s = GetCurrentDirectory()
  If Right(CurrentDir, 1) <> "\"
    CurrentDir = CurrentDir + "\"
  EndIf
  Add3DArchive(CurrentDir, #PB_3DArchive_FileSystem)
Else
  Debug "Can not init 3D Engine"
  End
EndIf

If InitSprite()
  If InitMouse()
    If InitKeyboard()
      If OpenWindow(0, 0, 0, 1600, 900, #APPNAME, #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
        If OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0), 0, 0, 0, #PB_Screen_NoSynchronization)
          Debug "init done"
        Else
          Debug "Can not open screen"
        EndIf
      Else
        Debug "Can not open window"
      EndIf
    Else
      Debug "Can not init keyboard"
    EndIf
  Else
    Debug "Can not init mouse"
  EndIf
Else
  Debug "Can not init sprite"
EndIf

Dim SolarSystem.PlanetPositionOuter(51)
Define FrontCam.CameraPositionOuter

; textures & materials
tex1 = CreateTexture(#PB_Any, 256, 256)
StartDrawing(TextureOutput(tex1))
Box(0, 0, 256, 256, RGB(192, 192, 192))
StopDrawing()
mat1 = CreateMaterial(#PB_Any, TextureID(tex1))
mesh8 = CreateSphere(#PB_Any, 80, 16, 16)
mesh9 = CreateSphere(#PB_Any, 90, 16, 16)
mesh10 = CreateSphere(#PB_Any, 100, 16, 16)
mesh11 = CreateSphere(#PB_Any, 110, 16, 16)
mesh12 = CreateSphere(#PB_Any, 120, 16, 16)

; starfield
For n = 1 To 50
  With SolarSystem(n)
    \name = "Star " + Str(n)
    \x = Random(5000,0)
    \y = Random(5000,0)
    \z = Random(5000,0)
    \material = mat1
    \mesh = Random(12,8)
    If \mesh = 8
      \mesh = mesh8
    ElseIf \mesh = 9
      \mesh = mesh9
    ElseIf \mesh = 10
      \mesh = mesh10
    ElseIf \mesh = 11
      \mesh = mesh11
    ElseIf \mesh = 12
      \mesh = mesh12
    EndIf
    \entity = CreateEntity(#PB_Any, MeshID(\mesh), MaterialID(\material), \x, \y, \z)
    \text3d = CreateText3D(#PB_Any, \name, "Arial", 1.0, RGBA(0,0,255,255))
    Text3DAlignment(\text3d, #PB_Text3D_HorizontallyCentered)
    ;AttachEntityObject(\entity, "", \text3d)
    MoveText3D(\text3d, 0, 0, 80)
  EndWith
Next

; space cube
CreateLine3D(#PB_Any,    0,    0,    0, #COLOR_LINE, 5000,    0,    0, #COLOR_LINE)
CreateLine3D(#PB_Any,    0, 5000,    0, #COLOR_LINE, 5000, 5000,    0, #COLOR_LINE)
CreateLine3D(#PB_Any,    0,    0, 5000, #COLOR_LINE, 5000,    0, 5000, #COLOR_LINE)
CreateLine3D(#PB_Any,    0, 5000, 5000, #COLOR_LINE, 5000, 5000, 5000, #COLOR_LINE)

CreateLine3D(#PB_Any,    0,    0,    0, #COLOR_LINE,    0, 5000,    0, #COLOR_LINE)
CreateLine3D(#PB_Any, 5000,    0,    0, #COLOR_LINE, 5000, 5000,    0, #COLOR_LINE)
CreateLine3D(#PB_Any,    0,    0, 5000, #COLOR_LINE,    0, 5000, 5000, #COLOR_LINE)
CreateLine3D(#PB_Any, 5000,    0, 5000, #COLOR_LINE, 5000, 5000, 5000, #COLOR_LINE)

CreateLine3D(#PB_Any,    0,    0,    0, #COLOR_LINE,    0,    0, 5000, #COLOR_LINE)
CreateLine3D(#PB_Any,    0, 5000,    0, #COLOR_LINE,    0, 5000, 5000, #COLOR_LINE)
CreateLine3D(#PB_Any, 5000,    0,    0, #COLOR_LINE, 5000,    0, 5000, #COLOR_LINE)
CreateLine3D(#PB_Any, 5000, 5000,    0, #COLOR_LINE, 5000, 5000, 5000, #COLOR_LINE)
; space cube end

; light
looklight = CreateLight(#PB_Any, RGB(255, 255, 128), 0, 0, 0, #PB_Light_Spot)
MoveLight(looklight, 2500, 2500, 10000)

; camera
FrontCam\x = 2500
FrontCam\y = 2500
FrontCam\z = 10000
FrontCam\spd = 0.005
FrontCam\rad = 10000
FrontCam\deg = 0
CreateCamera(#FRONTCAM, 0, 0, 100, 100)
CalculateCameraPosHor(FrontCam)
MoveCamera(#FRONTCAM, FrontCam\x, FrontCam\y, FrontCam\z)

; loop
Repeat
  
  ; catch all window events
  Repeat
    WindowEventId = WindowEvent()
    If WindowEventId = #PB_Event_CloseWindow
      ExitLoop = #True
    EndIf
    Delay (1)
  Until WindowEventId = 0
  
  ; get keyboard
  If ExamineKeyboard()
    
    If KeyboardPushed(#PB_Key_Left)  
      CalculateCameraPosHor(@FrontCam)
    ElseIf KeyboardPushed(#PB_Key_Right)
      CalculateCameraPosHor(@FrontCam, #True)
    EndIf 
    
    MoveLight(looklight, FrontCam\x, FrontCam\y, FrontCam\z, #PB_Absolute)
    MoveCamera(#FRONTCAM, FrontCam\x, FrontCam\y, FrontCam\z, #PB_Absolute)
    CameraLookAt(#FRONTCAM, 2500, 2500, 2500) ; the center

  EndIf
  
  ; get mouse
  If ExamineMouse()
    ; wheel ?!
  EndIf
  
  RenderWorld()
  FlipBuffers()
   
  SetWindowTitle(0, #APPNAME + " - " + Str(Engine3DFrameRate(#PB_Engine3D_Current)) + " fps")
  
Until KeyboardPushed(#PB_Key_Escape) Or ExitLoop = #True

End
Problem 1:

Wenn ich den Code so starte, bekomme ich die Fehlermeldung: Ungültiger Speicherzugriff die Zeile 115:

Code: Alles auswählen

AttachEntityObject(\entity, "", \text3d)
produziert den Fehler. Die Vorgehensweise habe ich direkt aus dem Beispiel von Purebasic entnommen, dort funktioniert sie. Ich habe keine Idee woran es hier scheitert.

Problem 2:

Wenn man den Text3D Block auskommentiert, funktioniert die Anzeige, wenn ich die Pfeiltasten (Rechts/Links) drücke, rotiert die Kamera auch um das Zentrum des Sternenfelds, aber, sobald der Umbruch von 0 auf 360 Grad oder umgekehrt kommt, sieht man einen "Sprung" in der Anzeige, die Galaxie macht auf einmal einen Sprung um ca. 270°.

Ich danke schonmal im voraus für Eure Tips und Hilfestellungen.

Edit: PureBasic 5.10 x86; Windows 7-64bit

Edit2: Problem 2 gelöst:

Code: Alles auswählen

*pos\x = *pos\rad * Cos(Radian(*pos\deg)) + 2500
*pos\z = *pos\rad * Sin(Radian(*pos\deg)) + 2500
---
Windows 11 (64 bit)
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: Zwei Fragen - Rotation und Text3D

Beitrag von Chimorin »

Hi,

erstmal: Benutze immer "EnableExplicit", da können dir keine Schreibfehler mehr passieren und es ist einfach übersichtlicher.

Code: Alles auswählen

EnableExplicit

Define.s CurrentDir
Define.i tex1, mat1, mesh8, mesh9, mesh10, mesh11, mesh12, n, looklight, WindowEventId, ExitLoop
Um dein Problem zu lösen, gehe mit dem Cursor auf den unauskommentierten Befehl und drücke F1.
Da steht, dass du die ID angeben sollst, nicht die Purebasicnummer (Korrigiert mich, wenn ich falsch liege, aber die ObjectID wird nur von OGRE verarbeitet, die PB-Nummer eben nur von PB).
Mit Text3D kenne ich mich nicht aus, hab ich noch nicht gebraucht, aber wie es aussieht, solltest du das so machen:

Code: Alles auswählen

    AttachEntityObject(\entity, "", Text3DID(\text3d))
Wo ich anmerken muss, dass zu Text3DID der Hinweis zu allen Attach... - Befehlen fehlt.

EDIT: Funktioniert doch nicht, ich schaue mir das mal an, aber eine ID muss das auf jeden Fall sein.

EDIT2: Deinen Code kannst du zudem auch sauberer gestalten, die ewigen Elseif in Bezug auf \mesh kann man auch einfach mit Select : EndSelect lösen.

EDIT3: Ich bin mit meinem Latein am Ende, der Text und das Entity werden erstellt. Hoffentlich löst sich das Problem, ich möchte zu gern wissen, was der Fehler ist.
Bild

- formerly known as Bananenfreak -
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

Re: Zwei Fragen - Rotation und Text3D

Beitrag von Makke »

Hallo Bananenfreak,

erstmal danke für Deine Tips, bei meinen Programmen verwende ich eigentlich immer "EnableExplicit". Bei dem Beispielcode habe ich es allerdings ... naja, den habe ich teilweise zusammenkopiert aus dem was ich gerade ausprobiere und einzelne Dinge kurzerhand abgeändert, nächstes mal mache ich das besser.

Findest Du If-Schleifen tatsächlich so unübersichtlich ? Naja, ich werde mal schauen, mich stört das jetzt nicht grad in meiner Übersichtlichkeit, aber das sollen ja auch andere gut durchblicken können. Auch das schreibe ich mir mal hinter die Ohren.

Nun zu der Text3D Sache, ich habe das Programm nur mal zum Spaß mit OpenGL-Subsystem, in Window-Mode und Fullscreen getestet, bringt alles nichts, immer der gleiche Fehler. Ich weiß mir auch keinen Rat mehr, da zum einen komischerweise keine Ogre-Log-Datei erstellt wird (das war meine ich bei PB 4.6 automatisch der Fall) und zum anderen mir die Fehlermeldung gar nichts sagt. Ich hoffe hier meldet sich noch ein Experte und lüftet das Geheimnis.

Aber, da ich unbedingt die Kugeln beschriftet haben wollte, habe ich eine Workaround gebastelt, statt der Text3D Passage folgenden Code:

Code: Alles auswählen

; structure ersetzen
Structure PlanetPositionOuter
  name.s
  x.i
  y.i
  z.i
  size.i
  texture.i
  material.i
  mesh.i
  entity.i
  text3d.i
  txt_tex.i
  txt_mat.i
  txt_mesh.i
  txt_ent.i
EndStructure

; workaround for text3d
    \txt_tex = CreateTexture(#PB_Any, 256, 128)
    drawfont.i = LoadFont(#PB_Any, "Calibri", 48, #PB_Font_Bold|#PB_Font_HighQuality) 
    StartDrawing(TextureOutput(\txt_tex))
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    DrawingFont(FontID(drawfont))
    Box(0, 0, 256, 128, RGBA(0,0,0,0))
    RoundBox(0, 0, 256, 128, 32, 32, RGBA(0,0,255,64))
    DrawText((256-TextWidth(\name))/2, (128-TextHeight(\name))/2, \name, RGBA(192,192,192,255), RGBA(0,0,255,64))
    StopDrawing()
    \txt_mat = CreateMaterial(#PB_Any, TextureID(\txt_tex))
    \txt_mesh = CreatePlane(#PB_Any, 256, 128, 1, 1, 1, 1)
    \txt_ent = CreateEntity(#PB_Any, MeshID(\txt_mesh), MaterialID(\txt_mat))
    RotateEntity(\txt_ent, 90, 180, 0, #PB_Absolute)
    MoveEntity(\txt_ent, \x, \y -200, \z, #PB_Absolute)
    ; end of workaround
In der Schleife sind auch noch Abfragen usw. aber das Grundproblem wird dadurch schon dargestellt

Erledigt: Wie man sieht wird die Textur im Alpha-Blend-Modus "bemalt". Wenn man das Programm dann startet, werden die Beschriftungen angezeigt aber die Transparenz nicht. Wo liegt hier mein Fehler ? Ich habe die Anleitung zu den Drawingmodes studiert und demnach die richtige Funktion gewählt, aber keine Transparenz. Zudem wird der Texthintergrund und das abgerundete Rechteck, obwohl es die selber Farbe ist zumindest bei mir anders dargestellt, also unterschiedliche Blautöne.

Und vielleicht noch ein kleiner Tip, wie kann ich einen Font direkt aus dem (Spiel-)Verzeichnis laden der nicht zu den Systemfonts gehört ?

Vielen Dank schonmal an alle Interessierten und Mithelfer.

Edit: Alpha-Blend-Modus hat sich erledigt: MaterialBlendingMode(#Material, #PB_Material_AlphaBlend) ist die Lösung ...
---
Windows 11 (64 bit)
Antworten