Perspektivenkorrektur für Gloweffekt

Übersicht BlitzBasic Blitz3D

Neue Antwort erstellen

 

Krischan

Betreff: Perspektivenkorrektur für Gloweffekt

BeitragDi, Nov 04, 2008 17:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bastel gerade an einem Gloweffekt für Planeten. Ich habe dazu auch schon alle möglichen Sourcecodes ausprobiert aber irgendwie gefällt mir das alles nicht. Jetzt habe ich folgendes selbst versucht und scheitere nur an der Perspektivenkorrektur, bzw. an der richtigen Formel.

Ich habe eine Sphere mit Radius 1, drumherum ist ein ringförmiges Mesh mit demselben Innenradius plus 0,5 Dicke, beides auf 0,0,0. Die Kamera ist Z-5 entfernt und der Ring geht passgenau auf die Sphere über. Der Ring zeigt ständig zur Kamera.

Gehe ich nun weiter weg, bleibt alles wie gehabt, gehe ich näher heran wird - bedingt durch die Perspektive der Kamera - die Sphere grösser als der Ring und verdeckt diesen fast ganz, je näher man der Sphere kommt. Jetzt habe ich schon alle möglichen Näherungsversuche gestartet, mit SQR, mit EXP, mit 1/EXP usw... aber es will mir nicht gelingen, dass der Ring im selben Masse grösser wird, wie die Sphere (scheinbar) grösser wird. Ich weiss, dass es funktionieren muss, da ich in einigen Formelversuchen "ins Blaue" einen ähnlichen Skalierungseffekt hinbekommen habe, aber nur näherungsweise (leider nicht gespeichert, waren aber auch haarsträubende Konstrukte).

Es geht also nur um die richtige Skalierung des Rings. Vielleicht habt Ihr eine Idee, hier erst einmal der Code zum herumspielen. Zum Testen einfach mit Pfeil-oben mal näher ran an den "Planeten", dann SPACE für Wireframe-Modus und dann den inneren Ringradius mit dem Rand der Sphere vergleichen. Es funktioniert, wenn der Ring - egal wie weit man weg ist - immer genau auf die Sphere aufsetzt.

Code: [AUSKLAPPEN]
Graphics3D 1024,768,32,2

; Variablengedöns
mousespeed#=0.1
cameraspeed#=0.05
camerasmoothness#=10

; Kamera
cam=CreateCamera()
PositionEntity cam,0,0,-5
CameraRange cam,0.1,100

; Planet
planet=CreateSphere(32)
EntityColor planet,0,255,0
EntityFX planet,1

; Glow
ring=CreateRing(1.25,0.5,60,0,360,1,255,255,255,32,32,32,0)
EntityFX ring,1+2+16+32

; Timer
timer=CreateTimer(60)

; Maus in die Mitte
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

While Not KeyHit(1)
   
   ; SPACE = Wireframe
   If KeyHit(57) Then wf=1-wf : WireFrame wf
   
   ; Mauskamera
   mx#=CurveValue(MouseXSpeed()*mousespeed,mx,camerasmoothness)
   my#=CurveValue(MouseYSpeed()*mousespeed,my,camerasmoothness)
   MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
   pitch#=EntityPitch(cam)
   yaw#=EntityYaw(cam)
   pitch=pitch+my
   yaw=yaw-mx
   If pitch>89 Then pitch=89
   If pitch<-89 Then pitch=-89
   RotateEntity cam,0,yaw,0
   TurnEntity cam,pitch,0,0
   
   ; Bewegung
   cx#=(KeyDown(205)-KeyDown(203))*cameraspeed
   cz#=(KeyDown(200)-KeyDown(208))*cameraspeed
   MoveEntity cam,cx,0,cz
   
   ; Ring zielt auf Kamera, immer 90° gedreht
   PointEntity ring,cam
   TurnEntity ring,-90,0,0
   
   RenderWorld
   
   WaitTimer timer
   
   Flip
   
Wend

End

; Smoothcam
Function CurveValue#(newvalue#,oldvalue#,increments )
   If increments>1 oldvalue#=oldvalue#-(oldvalue#-newvalue#)/increments
      If increments<=1 oldvalue=newvalue
         Return oldvalue#
End Function

; Single Surface Ring erstellen
Function CreateRing(radius#=1.0,width#=1.0,segmente%=360,beginn#=0.0,ende#=360.0,fx%=0,r1%=255,g1%=255,b1%=255,r2%=0,g2%=0,b2%=0,a#=1.0)
   
   Local mesh=CreateMesh()
   Local surf=CreateSurface(mesh)
   If fx>0 Then EntityFX mesh,fx
   
   ;Segmente auf 360 begrenzen
   If segmente>360 Then segmente=360
   
   ;Step festlegen
   Local inc#=360/segmente
   
   ;Kreisschnitt Beginn
   a1=beginn
   
   ;Volle Kreisdrehung solange im Kreisschnitt
   While a1<ende
      
      ;Winkel
      a2=(a1+inc) Mod 360
      
      ;Vertexpunkte berechnen
      v0=AddVertex(surf,(radius-(width/2))*Cos(a1),0,(radius-(width/2))*Sin(a1),0,0)
      v1=AddVertex(surf,(radius-(width/2))*Cos(a2),0,(radius-(width/2))*Sin(a2),0,0)
      v2=AddVertex(surf,(radius+(width/2))*Cos(a2),0,(radius+(width/2))*Sin(a2),1,1)
      v3=AddVertex(surf,(radius+(width/2))*Cos(a1),0,(radius+(width/2))*Sin(a1),1,1)
      
      ; Vertex einfärben
      VertexColor surf,v0,r1,g1,b1,1
      VertexColor surf,v1,r1,g1,b1,1
      VertexColor surf,v2,r2,g2,b2,a
      VertexColor surf,v3,r2,g2,b2,a
      
      ;Dreiecke basteln
      AddTriangle surf,v2,v1,v0
      AddTriangle surf,v0,v3,v2
      
      ;Step erhöhen
      a1=a1+inc
      
   Wend
   
   Return mesh
   
End Function


PS: die "Createring" Funktion kann man auch prima dazu verwenden, um z.B. einen Saturnring mit sehr wenigen Tris zu erzeugen, dazu einfach eine Gradienttextur, z.B. von Björn Jonssons Webseite nehmen und auf den Ring klatschen, fertig.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDi, Nov 04, 2008 18:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Sowas stinkt doch gewaltig nach 1 / entfernung oder etwa nicht?

Code: [AUSKLAPPEN]
Graphics 800,300,0,2
SetBuffer FrontBuffer()

Local X#,Y#

For X=0 To 799
   Y=(1/X)*300
   Plot X,Y
Next

WaitKey
End


Da in deinem Beispiel bedingt der Kollision des Planeten immer eine Mindestentfernung zum Mittelpunkt besteht, entstehen auch keine astronomischen Werte.

Edit1: mom... Aaaaalso, Der Ring müste ja im grunde ''zusammen klappen'' wenn man es ''realistisch'' haben möchte. Doch wird so ein zusammen klappen doch etwas schwieriger. Man könnte es aber mit deiner Idee auch zum Teil faken, und eine Skallierung muß erst beginnen, nachdem die Wölbung des Planeten durch die Perspektive den Ring-Äquator spürbar überblendet.

Edit2: Ähmmm, ok, ich hab eine halbherzige Lösung:

Code: [AUSKLAPPEN]
   PositionEntity ring,EntityX(planet),EntityY(planet),EntityZ(planet)
   PointEntity ring,cam
   TurnEntity ring,-90,0,0
   MoveEntity ring,0,1,0
   
   sscale#=12.0/Exp(EntityDistance(ring,cam))+1.1
   ScaleEntity ring,sscale,sscale,sscale
 

Krischan

BeitragDi, Nov 04, 2008 18:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Tja, Hectic, das meinte ich mit "näherungsweise" bzw. "haarsträubendes Konstrukt". Leider verschwindet auch hier der Ring völlig hinter der Sphere, sobald man auf eine "ISS-Umlaufbahn" einschwenkt. Ausserdem gibt es jetzt einen kleinen Raum zwischen Ring und Sphere, sobald man weiter weg ist.

Es muss doch irgendeine mathematische korrekte Formel geben.

Edit1: setze mal die Cameraposition auf 0,0,-1.2 und füge hinter entityfx ring...

ScaleEntity ring,1.8,1.8,1.8

ein. Man muss den Ring nicht "zusammenklappen", es sieht dann auf dieser Höhe schon fast wie eine Atmosphäre aus.

Edit 2: die kleine schwarze Störung auf der rechten Seite bekommt man weg, wenn man Createsphere(60) und den Ring auf dieselbe Anzahl Segmente setzt, also:

ring=CreateRing(1.25,0.5,60,0,360,1,255,255,255,32,32,32,0)
  • Zuletzt bearbeitet von Krischan am Di, Nov 04, 2008 18:50, insgesamt einmal bearbeitet

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDi, Nov 04, 2008 18:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Das Problem ist einfach dass, wenn man auf den Planeten stehen würde, müßte ja deine Sphäre biszu unendlich lang gestreck sein. Aus diesem Grund wäre ein zusammen klappen der Sphäre sinnvoller, was aber ein ewig neu zu erstellendes Konstrukt bedeuten würde.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragDi, Nov 04, 2008 19:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Man muss nicht auf dem Planeten stehen, es geht nur um die Distanz, die einer Umlaufbahn entspricht. Also nur die Illusion einer Atmosphäre.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDi, Nov 04, 2008 21:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Schlag mich nicht, aber es gibt eine erfreulichere Lösung die auch recht annehmbar ist.

Code: [AUSKLAPPEN]
      v0=AddVertex(surf,(radius-(width/2))*Cos(a1),0,(radius-(width/2))*Sin(a1),0,0)
      v1=AddVertex(surf,(radius-(width/2))*Cos(a2),0,(radius-(width/2))*Sin(a2),0,0)
      v2=AddVertex(surf,(radius+(width/2))*Cos(a2),-1,(radius+(width/2))*Sin(a2),1,1)
      v3=AddVertex(surf,(radius+(width/2))*Cos(a1),-1,(radius+(width/2))*Sin(a1),1,1)


Edit2: Mir fiel noch auf, dass die Triangles paralell geordnet sind. Bei Kreisen ist das nicht ganz sinnvoll, da man viele Triangles benötigt um solche Helligkeits-Treppeneffekte nicht zu bekommen. Daher bietet es sich an, sie um eine halbe Position zu ''verdrehen''. Siehe selbst und stelle statt 60 nur 20 Segmente dar bei denoch einer besseren Darstellungsqualität.

Code: [AUSKLAPPEN]
   For Winkel=1 To segmente
      
      a1#=Winkel*360/segmente
      a2#=Winkel*360/segmente +360/segmente
      a3#=Winkel*360/segmente +180/segmente
      a4#=Winkel*360/segmente -180/segmente
      
      ;Winkel
      ;Vertexpunkte berechnen
      v0=AddVertex(surf,(radius-(width/2))*Cos(a1),0,(radius-(width/2))*Sin(a1),0,0)
      v1=AddVertex(surf,(radius-(width/2))*Cos(a2),0,(radius-(width/2))*Sin(a2),0,0)
      v2=AddVertex(surf,(radius+(width/2))*Cos(a3),-1,(radius+(width/2))*Sin(a3),1,1)
      v3=AddVertex(surf,(radius+(width/2))*Cos(a4),-1,(radius+(width/2))*Sin(a4),1,1)
      
      ;Vertex einfärben
      VertexColor surf,v0,r1,g1,b1,1
      VertexColor surf,v1,r1,g1,b1,1
      VertexColor surf,v2,r2,g2,b2,a
      VertexColor surf,v3,r2,g2,b2,a
      
      ;Dreiecke basteln
      AddTriangle surf,v2,v1,v0
      AddTriangle surf,v0,v3,v2
   Next


Sorry nur, daß ich dein Code nicht übernommen habe. Hat eine mir nicht so bekannte Vorgehensweise.
 

Krischan

BeitragDi, Nov 04, 2008 22:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe jetzt aus lauter Frust darüber eine grelle Sonne draus gemacht, auch ganz nett und ganz ohne Texturen. Kann man auch gut gebrauchen...

Der Teil hier fällt mal wieder unter "näherungsweise":

d#=EntityDistance(cam,planet)-0.5
s#=((1.0/d^0.5)*1.33)
If s<1 Then s=1
ScaleEntity ring,s,s,s

Edit Coool... das läuft ja bei mir mit 2000FPS bei 1920x1200 Shocked Da stinkt jedes bepinselte Sprite voll bei ab...

Code: [AUSKLAPPEN]
Graphics3D 1024,768,32,2

; Variablengedöns
mousespeed#=0.1
cameraspeed#=0.05
camerasmoothness#=10

; Kamera
cam=CreateCamera()
PositionEntity cam,0,0,-5
CameraRange cam,0.1,100

; Planet
planet=CreateSphere(32)
EntityColor planet,255,255,160
EntityFX planet,1

; Glow
ring=CreateRing(1.5,1,90,0,360,1,255,224,128,32,32,32,0)
EntityFX ring,1+2+16+32

; Timer
timer=CreateTimer(60)

; Maus in die Mitte
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2

While Not KeyHit(1)
   
   ; SPACE = Wireframe
   If KeyHit(57) Then wf=1-wf : WireFrame wf
   
   ; Mauskamera
   mx#=CurveValue(MouseXSpeed()*mousespeed,mx,camerasmoothness)
   my#=CurveValue(MouseYSpeed()*mousespeed,my,camerasmoothness)
   MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
   pitch#=EntityPitch(cam)
   yaw#=EntityYaw(cam)
   pitch=pitch+my
   yaw=yaw-mx
   If pitch>89 Then pitch=89
   If pitch<-89 Then pitch=-89
   RotateEntity cam,0,yaw,0
   TurnEntity cam,pitch,0,0
   
   ; Bewegung
   cx#=(KeyDown(205)-KeyDown(203))*cameraspeed
   cz#=(KeyDown(200)-KeyDown(208))*cameraspeed
   MoveEntity cam,cx,0,cz
   
   ; Ring zielt auf Kamera, immer 90° gedreht
   PointEntity ring,cam
   TurnEntity ring,-90,0,0
   
   d#=EntityDistance(cam,planet)-0.5
   s#=((1.0/d^0.5)*1.33)
   If s<1 Then s=1
   ScaleEntity ring,s,s,s
   
   RenderWorld
   
   WaitTimer timer
   
   Flip
   
Wend

End

; Smoothcam
Function CurveValue#(newvalue#,oldvalue#,increments )
   If increments>1 oldvalue#=oldvalue#-(oldvalue#-newvalue#)/increments
      If increments<=1 oldvalue=newvalue
         Return oldvalue#
End Function

; Single Surface Ring erstellen
Function CreateRing(radius#=1.0,width#=1.0,segmente%=360,beginn#=0.0,ende#=360.0,fx%=0,r1%=255,g1%=255,b1%=255,r2%=0,g2%=0,b2%=0,a#=1.0)
   
   Local mesh=CreateMesh()
   Local surf=CreateSurface(mesh)
   If fx>0 Then EntityFX mesh,fx
   
   ;Kreisschnitt Beginn
   a1=beginn
   
   For Winkel=1 To segmente
      
      a1=Winkel*360/segmente
      a2=Winkel*360/segmente +360/segmente
      a3=Winkel*360/segmente +180/segmente
      a4=Winkel*360/segmente -180/segmente
      
      ;Winkel
      ;Vertexpunkte berechnen
      v0=AddVertex(surf,(radius-(width/2))*Cos(a1),0,(radius-(width/2))*Sin(a1),0,0)
      v1=AddVertex(surf,(radius-(width/2))*Cos(a2),0,(radius-(width/2))*Sin(a2),0,0)
      v2=AddVertex(surf,(radius+(width/2))*Cos(a3),-1,(radius+(width/2))*Sin(a3),1,1)
      v3=AddVertex(surf,(radius+(width/2))*Cos(a4),-1,(radius+(width/2))*Sin(a4),1,1)
      
      ;Vertex einfärben
      VertexColor surf,v0,r1,g1,b1,1
      VertexColor surf,v1,r1,g1,b1,1
      VertexColor surf,v2,r2,g2,b2,a
      VertexColor surf,v3,r2,g2,b2,a
      
      ;Dreiecke basteln
      AddTriangle surf,v2,v1,v0
      AddTriangle surf,v0,v3,v2
   Next
   
   Return mesh
   
End Function
 

Krischan

BeitragDo, Nov 06, 2008 0:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Sooo... auch mit näherungsweisen Formeln kann man akzeptable Ergebnisse erzielen (solange man mit der Kameranase nicht in die Sphere hineinstubst). In Anlehnung an einen früheren Code hier nenne ich ihn mal "Krischan's toller Planet" - basierend auf dem o.g. Code mit der Modifikation:

d#=EntityDistance(cam,planet)
sc#=1.0
If d<10 Then sc=(Exp(1.0/d^3.33))
ScaleEntity ring,sc,sc,sc


Das sieht dann hübsch aufpoliert so aus (ist keine Fotomontage, sondern ein Ingame-Screenshot, 8316 Tris bei 1920x1200@550FPS):

user posted image
user posted image
user posted image

Den kommentierten Code liefere ich am Wochenende nach - sofern hectic die Sterne gefallen dürfte auch der Sternenalgorithmus von Interesse sein...
 

Code der Verwirrung

BeitragFr, Nov 07, 2008 22:01
Antworten mit Zitat
Benutzer-Profile anzeigen
sieht alles sehr schön aus...aber:
die atmosphäre scheint überall gleich "hell" zu sein. die dunkle seite des planeten wirkt zu "blau". die angeleuchtete seite und der ring sind sehr gute arbeit. die wolkentextur passt auch super. die plantetenoberfläche sieht prozedual erstellt aus. wenn das so ist hast du richtig gute arbeit geleistet. sieht imho sogar besser aus als bei "infinty"! der weltraumnebel sieht meiner meinung nach etwas zu hell und zu bunt aus. die farbvariation ist zu hoch.ich würde auch den nebel "gewählt" platzieren um den planten noch besser rausstechen zu lassen.manchmal ist weniger mehr.

kannst du mir mal erklären wie man den die wolken hinbekommt ? ich bin da momentan "leicht" am verzweifeln.die wolken sind nahezu perfekt!
 

Omenaton_2

BeitragFr, Nov 07, 2008 23:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Gratuliere zu der Lösung mit dem Gloweffekt Korrektur !
Mit diesem Problem hatte ich auch zu kämpfen, ich habe es damals vorläufig aufgegeben. Das fiel mir auch deshalb leicht, weil ich entdeckt hatte, daß es meisten überflüssig ist, sich die ganze Mühe mit so einem 3D Planet zu machen. Es ist viel einfacher den Bild des Planeten samt Atmosphere schön groß auf eine Seite des Skyboxes zu setzen. Ein Planet dreht sich so langsam, daß die Bewegung gar nicht wahrnehmbar ist. Wenn der Planet sich praktisch nicht bewegt, dann kann es auch einfach als Standbild da sein.
In meinem Spiel fliegt man nie zu nahe an den Planeten ran, deshalb stört es nicht, wenn die Größe sich nicht ändert.

Die Wolken und die Sterne sind auch sehr schön.
Ich finde die Farbigkeit ist auch richtig, es ist nicht zu bunt. Das ist gut als eine Variante. Du machst bald bestimmt noch mehr Hintergründe, die dann weniger bunt sein werden.
 

Krischan

BeitragSo, Nov 09, 2008 14:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Juchhu ich habe die mathematisch exakte Lösung herausgefunden. Man braucht nur zwei rechtwinklige Dreiecke und etwas Trigonometrie. Das Licht ging mir beim Betrachten dieser Homepage auf.

Die gesuchte Skalierung des Rings ist identisch mit der C2 Hypotenuse des zweiten Dreiecks. Ich habe die Variablen so genannt, wie sie im Dreieck benannt würden. Wir benötigen nur die Scale (den Radius des Planeten) und die Distanz zwischen der Kamera und dem Planetenzentrum, der Rest ist simpel wenn man das Prinzip verstanden hat.

Hier eine einfache Zeichnung der zwei Dreiecke, der rote Punkt oben ist die Kamera, die rote Linie die Distanz, die schwarze Linie der Radius und die violette Linie die gesuchte C2 Hypotenuse, nach der wir suchen.

user posted image

radius#=scale
distance#=EntityDistance(cam,planet)

; First triangle
c1#=distance
a1#=radius
q1#=a1^2/c1
p1#=c1-q1
h1#=Sqr(p1*q1)
gamma1#=90
alpha1#=ATan(h1/p1)
beta1#=gamma1-alpha1

; Second Triangle
alpha2# = 90-(90-beta1)
b2# = a1/Tan(alpha2)
c2# = (Sqr(a1^2 + b2^2))/radius

ScaleEntity ring,c2,c2,c2


Code: [AUSKLAPPEN]
Graphics3D 1024,768,32,2

; Variables
mousespeed#=0.1
cameraspeed#=0.01
camerasmoothness#=10
scale#=1.0

timer=CreateTimer(60)

; Camera
cam=CreateCamera()
PositionEntity cam,0,0,-scale*2
CameraRange cam,0.01,1000

; Planet
planet=CreateSphere(60)
ScaleEntity planet,scale,scale,scale
EntityColor planet,0,255,0

ring=CreateRing(1*scale,1.5*scale,120,1+2+32,3,192,224,255,64,128,255,0,scale)

MoveMouse GraphicsWidth()/2,GraphicsHeight()/2


While Not KeyHit(1)
   
   If KeyHit(57) Then wf=1-wf : WireFrame wf
   
   ; Mousecam
   mx#=CurveValue(MouseXSpeed()*mousespeed,mx,camerasmoothness)
   my#=CurveValue(MouseYSpeed()*mousespeed,my,camerasmoothness)
   MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
   pitch#=EntityPitch(cam)
   yaw#=EntityYaw(cam)
   pitch=pitch+my
   yaw=yaw-mx
   If pitch>89 Then pitch=89
   If pitch<-89 Then pitch=-89
   RotateEntity cam,0,yaw,0
   TurnEntity cam,pitch,0,0
   
   ; Movement
   cx#=(KeyDown(205)-KeyDown(203))*cameraspeed
   cz#=(KeyDown(200)-KeyDown(208))*cameraspeed
   MoveEntity cam,cx,0,cz
   
   PointEntity ring,cam
   
   radius#=scale
   distance#=EntityDistance(cam,planet)
   
   ; First triangle
   c1#=distance
   a1#=radius
   q1#=a1^2/c1
   p1#=c1-q1
   h1#=Sqr(p1*q1)
   gamma1#=90
   alpha1#=ATan(h1/p1)
   beta1#=gamma1-alpha1
   
   ; Second Triangle
   alpha2# = 90-(90-beta1)
   b2# = a1/Tan(alpha2)
   c2# = (Sqr(a1^2 + b2^2))/radius
   
   ScaleEntity ring,c2,c2,c2
   
   RenderWorld
   
   WaitTimer timer
   
   Flip 0
   
Wend

End

; Smoothcam
Function CurveValue#(newvalue#,oldvalue#,increments )
   If increments>1 oldvalue#=oldvalue#-(oldvalue#-newvalue#)/increments
      If increments<=1 oldvalue=newvalue
         Return oldvalue#
End Function

; Ring
Function CreateRing(radius1#=1.0,radius2#=2.0,segments%=360,fx%=0,blend%=0,r1%=255,g1%=255,b1%=255,r2%=0,g2%=0,b2%=0,a#=1.0,scale#=1.0)
   
   Local a1#,a2#,a3#,a4#,angle%
   
   Local mesh=CreateMesh()
   Local surf=CreateSurface(mesh)
   
   ; Limit segments
   If segments>360 Then segments=360
   
   ; Create ring
   For angle=1 To segments
      
      a1=angle*360.0/segments
      a2=angle*360.0/segments +360.0/segments
      a3=angle*360.0/segments +180.0/segments
      a4=angle*360.0/segments -180.0/segments
      
      ; Calc vertex points
      v0=AddVertex(surf,radius1*Cos(a1),radius1*Sin(a1),0,0,0)
      v1=AddVertex(surf,radius1*Cos(a2),radius1*Sin(a2),0,0,0)
      v2=AddVertex(surf,radius2*Cos(a3),radius2*Sin(a3),0,1,1)
      v3=AddVertex(surf,radius2*Cos(a4),radius2*Sin(a4),0,0,1)
      
      ; Color
      VertexColor surf,v0,r1,g1,b1,1
      VertexColor surf,v1,r1,g1,b1,1
      VertexColor surf,v2,r2,g2,b2,a
      VertexColor surf,v3,r2,g2,b2,a
      
      ; Create Triangles
      AddTriangle surf,v2,v1,v0
      AddTriangle surf,v0,v3,v2
      
   Next
   
   If fx>0 Then EntityFX mesh,fx
   If blend>0 Then EntityBlend mesh,blend
   
   
   Return mesh
   
End Function

Jetzt muss ich mich mit der Beleuchtung des Rings näher auseinandersetzen, der Weltraumnebel ist nur die erste Version und kann noch angepasst werden, ich brauchte erst einmal einen schicken Hintergrund als Motivationsbeschleuniger (soviel zum Thema "zu bunt" Smile ). Ausserdem wird die Atmosphäre "dünner" je näher man an den Planeten kommt, es muss ja umgekehrt sein. Aber das wird leicht zu lösen sein, ich denke man muss nur den Ring in jedem Schleifendurchlauf löschen und mit einem grösseren radius2 Wert neu erstellen, irgendwas mit 1.0/entitydistance(cam,planet) oder so.


@Code der Verwirrung
Ja, das ist ein prozedural erstellter Planet, mit Hilfe dieses Scripts (3D Perlin Noise) und ein wenig Gradientverlauf in Photoshop - diesen Step muss ich noch BB-mässig automatisieren. Die Wolken habe ich von der Celestia Motherlode Homepage entnommen, ist eine verbesserte Version der Nasa Blue Marble Textur, "nur" halt transparent. Sieht einfach nur geil aus.

Link zur Wolkentextur (2048x1024 PNG24)

Zusätzlich hat der Planet noch eine Entityshininess von 0.25, eine Normalmap mit Textureblend 4, eine Detailmap und eine Spherical Reflection map (Loadtexture Flag 64). Wenn alles soweit fertig ist poste ich mal den Code mit Media im Codearchiv.


@Omenaton_2
Ich brauche für meinen Fall aber einen 3D Planeten, meine Planungen gehen ja noch viel weiter. Die letzten Wochen habe ich mich damit beschäftigt, wie man ein Sonnensystem mit 10 Mrd. km Durchmesser mit einer Camerarange von nur 1,10000 darstellt. Da kommt man bei einer 1:1 Darstellung schnell ins Straucheln (Floatproblem). Meine Lösung beruht hier auf exponentieller Vergrösserung / Verkleinerung des gesamten Systems unter Berücksichtigung zum nächsten Planeten, der dann X-fach vergrössert dargestellt wird. Auch die Anfluggeschwindigkeit wird entsprechend skaliert. Mein Ziel ist es, nicht nur eines sondern dutzende oder hunderte Sonnensysteme prozedural zu erstellen, und zwar mit nahtlosem Flug durch den Weltraum zwischen den Systemen und Planeten.

Vielleicht gibt es mal ein Projekt oder sogar ein Spiel, im Moment sind das nur zusammenhangslose Techdemos.

3D Perlin Noise Planet, bereits für die Nutzung auf einer Sphere verzerrt:Code: [AUSKLAPPEN]
Function DBInt( x# )
   If x >= 0
      Return Floor(x)
   Else
      Return Ceil(x)
   End If
End Function

xs%=512
ys%=256

start=MilliSecs()

Graphics xs,ys,32,2

   ; create arrays For perlin generator
Dim s#(15,2)
Dim r#(63,63,63)

   ; prepare the perlin
prepare_perlin(42,0.66)

   ; multisampling controller
multi% = 1
milti% = multi - 1
malt# = multi ^ 2
malt# = 1 / malt#

xsize1% = xs
ysize1% = ys

   ; get the base sizes
xsize2% = xsize1 * multi
ysize2% = ysize1 * multi

   ; get the scalers
xscaler1% = 360
yscaler1% = 180

xscaler2# = xscaler1*1.0 / xsize2
yscaler2# = yscaler1*1.0 / ysize2

width# = 2

   ; piece details
pxs% = xs-1
pys% = ys-1

xof% = 0
yof% = 0

SetBuffer FrontBuffer()

image=CreateImage(xs,ys)
ib=ImageBuffer(image)
LockBuffer ib

min=255
max=0

   ; loop the y position
For posx% = 0 To pxs Step 1
   
         ; loop the x
   For posy% = 0 To pys Step 1
      
            ; reset colours
      g = 0
      b = 0
      
            ; get the scaled sizes
      xp1% = (posx + xof) * multi
      yp1% = (posy + yof) * multi
      
            ; do the multisampling
      For posa% = 0 To milti
         
               ; get the baring around the sphere
         ba# = xp1 + posa
         ba# = (ba# + 0.5) * xscaler2#
         xp2# = Cos(ba#)
         zp2# = Sin(ba#)
         
         For poss% = 0 To milti
            
                  ; get the pitch around the sphere
            pa# = yp1 + poss
            pa# = ((pa# + 0.5) * yscaler2#)
            po# = Sin(pa#) * width#
            
                  ; get the positions in the space
            x# = (xp2# * po#) + 5
            y# = (Cos(pa#) * width#) + 5
            z# = (zp2# * po#) + 5
            
                  ; get the perlin result For that part
            h = DBInt(perl(x#,y#,z#,7) * 255)
            
                  ; cap the value
            If h => 255 Then h = 255
            If h <= 0 Then h = 0
            
            If h>max Then max=h
            If h<min Then min=h
            
            ; failsafe quit
            If KeyHit(1) Then End
            
         Next
         
      Next   
      
            ; scale down the colours
      c=c*malt#
      
      ;Color h,h,h
      ;Plot posx,posy
      
         ;g = g * malt#
      ;b = b * malt#
      
            ; get the colour
      rgb=h*$10000+h*$100+h
      
            ; put a dot there
      WritePixelFast posx,posy,rgb,ib
      
   Next
   
Next

For posx = 0 To pxs Step 1
   
   For posy = 0 To pys Step 1
      
      rgb=ReadPixelFast(posx,posy,ib)
      r1=(rgb And $ff0000)/$10000
      
      h=Normalisieren(r1,min,max,0,255)
      
      rgb=h*$10000+h*$100+h
      
      WritePixelFast posx,posy,rgb,ib
      
   Next
   
Next

UnlockBuffer ib

ende=MilliSecs()

While Not KeyHit(1)
   
   DrawImage image,0,0
   
   If KeyHit(57) Then SaveBuffer(ib,"planet.bmp") : End
   
   Text 0,0,(ende-start)
   
   Flip
   
Wend


End

; perlin Function
Function perl#(x#,y#,z#,octaves%)
   
   ; make sure the pass value is zerod
   h# = 0
   
   ; shift octaves down to Input works from 1 but system works from 0
   octaves=octaves-1
   
   ; make sue octaves are an ecceptable value
   If octaves <= 0 Then octaves = 0
   If octaves => 15 Then octaves = 15
   
   ; loop the octaves
   For oct% = 0 To octaves
      
      ; grab the frequency And amplitude For this
      fre# = s#(oct,0)
      amp# = s#(oct,1)
      

      ; convert the co-ordinates into steps
      xx = DBInt(x# * fre#)
      yy = DBInt(y# * fre#)
      zz = DBInt(z# * fre#)
      
      ; get the inbetween co-ords
      xb# = sine((x# * fre#) - flo(xx))
      yb# = sine((y# * fre#) - flo(yy))
      zb# = sine((z# * fre#) - flo(zz))
      xa# = 1 - xb#
      ya# = 1 - yb#
      za# = 1 - zb#
      
      ; get the values For the 8 corners
      v000# = vil(xx,yy,zz) * xa# * ya# * za#
      v100# = vil(xx+1,yy,zz) * xb# * ya# * za#
      v010# = vil(xx,yy+1,zz) * xa# * yb# * za#
      v001# = vil(xx,yy,zz+1) * xa# * ya# * zb#
      v101# = vil(xx+1,yy,zz+1) * xb# * ya# * zb#
      v110# = vil(xx+1,yy+1,zz) * xb# * yb# * za#
      v011# = vil(xx,yy+1,zz+1) * xa# * yb# * zb#
      v111# = vil(xx+1,yy+1,zz+1) * xb# * yb# * zb#
      
      ; add it on
      h#=h#+(v000# + v100# + v010# + v001# + v101# + v110# + v011# + v111#) * amp#
      
   Next
   
   ; scale it down
   h# = h# * s#(octaves,2)
   
    Return h#
   
End Function

; Function to get the random value of a co-ordinate
Function vil#(x,y,z)
   
   ; control edges
   If x < 0 Then x = x - (DBInt((x / 64) - 1) * 64) Else x = x - (DBInt(x/64) * 64)
   If y < 0 Then y = y - (DBInt((y / 64) - 1) * 64) Else y = y - (DBInt(y/64) * 64)
   If z < 0 Then z = z - (DBInt((z / 64) - 1) * 64) Else z = z - (DBInt(z/64) * 64)
   
   ; get the number
   v# = r#(x,y,z)
   
   Return v#
   
End Function


   ; Return an integer as a floating point
Function flo#(a)
   
   b# = a*1.0
   
   Return b#
   
End Function

; Function to turn a straight 0 - 1 into a sine curved 0 - 1
Function sine#(v#)
   
   ; perform the change
   v# = (1 - Cos(v# * 180)) * 0.5
   
   Return v
   
End Function


; Function to prepare Data For perlin noise
Function prepare_perlin(seed,persistance#)
   
   ; set the seed value
   SeedRnd seed
   
   ; create seed Data
   For x = 0 To 63
      
      For y = 0 To 63
         
         For z = 0 To 63
            
            zz# = Rnd(10000)
            r#(x,y,z) = (zz# * 0.0001)
            
         Next
         
      Next
      
   Next
   
   ; prepare octave Data
   For i = 0 To 15
      
      ; work out the frequence of the octave
      s#(i,0) = 2 ^ i
      
      ; get the amplitude
      s#(i,1) = persistance# ^ i
      
      ; work out the maximum amplitude of
      s#(i,2) = 0.0
      
      For j = 0 To i
         
         s#(i,2)=s#(i,2)+s#(j,1)
         
      Next
      
      s#(i,2) = 1.0 / s#(i,2)
      
   Next
   
End Function

Function Normalisieren#(value#=128.0,value_min#=0.0,value_max#=255.0,norm_min#=0.0,norm_max#=1.0)
   
   Return ((value-value_min)/(value_max-value_min))*(norm_max-norm_min)+norm_min
   
End Function


Hier die Planetentextur, die ich für meine Screenshots verwendet habe:
user posted image
 

Code der Verwirrung

BeitragSo, Nov 09, 2008 15:49
Antworten mit Zitat
Benutzer-Profile anzeigen
erstmal danke für die wolkentextur!
und ich hätte da noch ne frage:
wie schaffst du es die textur so zu verzerren? ich hab ewig nach ner möglichkeit gesucht sowas hinzubekommen.(sry aber ich verstehe erlichgesagt den code nicht so ganz)
und wird die textur nicht pixelig wenn man sich den planet aus der nähe betrachtet? bei vielen spielen wurde das (auf eine mir rätselhafte art und weise Wink ) durch aneinanderlegen der textur auf einem planeten gelöst. ich frage mich wie da die uvw-map ausehen soll. ich hab schon viel probiert, bin aber immer gescheitert.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragSo, Nov 09, 2008 16:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Um feinere Strukturen auf einer Oberfläche zu bekommen wird meisten Multitexturing benutzt. Damit aber die UV-Koordinaten nicht auf allen Texturen gleich sind, kann man sich unter Blitz3D zum Beispiel mit ScaleTexture weiter helfen.

@Krischan, deine neue Version sieht schon viel besser aus. Aber ich finde 120 Segmente schon höhst übertrieben. Bereits mit 20 Segmenten kann man gut damit leben. Bei 30 Segmenten muß man schon genau hinsehen (und vorher auch wissen) um es zu erkennen.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragSo, Nov 09, 2008 16:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Ehrlich gesagt verstehe ich den Code zur Planetentexturerzeugung auch nur halb, den habe ich nur von Darkbasic portiert. Nur so viel: es handelt sich hierbei um 3D Perlin Noise, also eine Wolkentextur, die auch noch in die dritte Dimension hineinreicht. Am Besten kann man sich das anhand des folgenden Bildes veranschaulichen:

user posted image

Stell Dir vor, Du schneidest jetzt mit einem Messer eine Scheibe aus dem Würfel heraus, dann hast Du eine 2D Wolkentextur. Wenn Du nun anstatt einer Scheibe eine Kugel aus dem Würfel schneidest und die Koordinaten der 3D-Kugel auf eine 2D Zylindertextur umrechnest, erhälst Du das Bild, welches der Code berechnet. Dabei wird anscheinend zu den Polen hin zusätzlich verzerrt. Noch genialer wäre es, direkt aus der Wolke eine Kugel oder Geosphere mit Vertices heraus zu "meisseln", wobei dann der Radius mal die "Höhe" des Perlinwertes die Erhöhung des Vertexpunktes ergibt, also z.B. die Höhe eines Berges oder Tiefe eines Tales auf dem Planeten. Und wenn man jetzt noch ein LOD-System dazu bastelt kann man einen Planeten bis auf Metergrösse (je nach Floatgenauigkeit) erstellen! Genaueres zu dem Thema kannst Du Dir hier anschauen:

Mein altes Thema im BB-Forum zum Thema Spherical Mapping
Infinity kennst Du ja, der Vollständigkeit halber
Hier ein Video von Infinity, wie es aussieht, wenn man es richtig macht
Ein Darkbasic-Beispiel, wie man das mit der Geosphere und dem LOD umsetzen kann

Der letzte Code ist mir persönlich zu hoch, aber die Demo ist relativ einfach gehalten und sehr anschaulich. Wenn jemand das Infinity-Prinzip in Blitz3D hinbekäme wäre das mein persönlicher heiliger Gral der Spacesimulationen in Blitz.

Mein Planet wird natürlich pixelig bzw. verwaschen, um das etwas zu kaschieren benutze ich die Wolkentextur und eine Detailtextur, damit das nicht so gleich ins Auge fällt. Mein Raumschiff fliegt sowieso nur max. auf ISS-Umlaufbahngrösse heran. Mein Ziel war es lediglich, einen Planeten ähnlich wie die in Freelancer zu basteln und das ist mir soweit ich das beurteilen kann gut gelungen (wobei der Freelancer-Planet noch ein einfaches LOD-System benutzt und die Details bei Annäherung erhöht, kann man gut beim Planeten "Leeds" erkennen, der hat so eine Zufalls-beleuchtete-Stadtstruktur). Anscheinend wird da aber nur ein wenig subdivided.
 

Krischan

BeitragSo, Nov 09, 2008 16:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Jaja hectic, hast ja recht. Aber schau Dir mal "unsere" Ringfunktion an, da hab ich noch was dran korrigiert, bei Dir waren die UVs durcheinander. Jetzt kann man da auch eine Textur drauflegen (also einen Farbverlauf von links nach rechts, wobei links die Planetenoberfläche und rechts der Weltraum sind).

hectic

Sieger des IS Talentwettbewerb 2006

BeitragSo, Nov 09, 2008 16:52
Antworten mit Zitat
Benutzer-Profile anzeigen
ok, die UV-Koordinaten habe ich garnicht berücksichtigt. Mir ging es erstmal um den Ring selbst.

Nur eine Frage: Lädst du die Texturen so, wie sie auf dem von dir geposteten Link zu sehen sind? Ich bin mir zwar nicht sicher, aber es könnte sein, dass einige Grafikkarten daraus dann eine 2048x2048er Textur machen. Das ist sehr verschwenderisch. aus diesem Grund habe ich mir mal folgendes erlaubt aus dem ersten Bild deines Links auszuprobieren.

http://www.hectic.de/data/ring.rar

Die Textur sieht in meinem Beispiel wie unten aus. Sie ist 128x128 Pixel groß und beinhaltet eine volle 1024er Breitenauflösung. Wie man sieht, könnte man das ganze noch ohne Einschränkung auf 64x64 bringen. Dazu dann die lila Lücken stopfen und den Streifen 4 Pixel hoch statt 8 (-2 Rand) machen.

user posted image
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Code der Verwirrung

BeitragSo, Nov 09, 2008 17:15
Antworten mit Zitat
Benutzer-Profile anzeigen
@hectic:

mir ist klar, dass man mit scaletexture einiges an detail rausholen kann, aber dann würde es an den polen texturstauchungen geben. ich habe bisher keine möglichkeit gefunden das zu verhindern. bei spielen wie z.b. X3 Terran Conflict wurden 1024 er texturen aneinandergereiht ohne verzerrung an den polen. dummerweise komme ich nicht drauf, wie die uvw map aussehen muss.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragSo, Nov 09, 2008 17:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Mit einer gewöhnlichen CreateSphere wo zu den Polen hin die Triangles immer enger werden, bleibt es immer ein Problem. Der Vorteil so einer Kugel ist einfach nur, dass sich schnell berechnet ist und leicht mit UV-Koordinaten gefüttert werden kann. Ansonsten bleibt nur noch eine andere Triangulierung einer Kugel als Lösung. Das ginge zum Beispiel mit einem Ikosaeder (noch sehr kantig) oder besser einem Super Ikosaeder. Das entspricht ungefähr dem aussehen eines Fußballes wo die 5 und 6 eckigen Flächen aus Triangles bestehen. Ansonsten muß man diese Triangles weiter teilen. Also aus einem Triangle mach 4 Triangles und berechne dessen Radius neu, bis genügend davon da sind um von Außen als Kugel wahrgenommen zu werden.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

Krischan

BeitragSo, Nov 09, 2008 17:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Interessant. An sowas hatte ich bislang noch gar nicht gedacht. Wie müsste das aussehen, um es in unsere Ringfunktion einzubauen? Für das Rendering hatte ich nur schnell was zusammengehauen:

user posted image

Basierend auf Björn Jonssons exzellenten Grafiken (ich glaube Forward+Color multiplied und Transparenz in den Alphakanal gehauen).

hectic

Sieger des IS Talentwettbewerb 2006

BeitragSo, Nov 09, 2008 18:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Der UV-Koordinaten-Zugriff erfolg liniear. Ich habe noch nicht ganz verstanden warum in deinem letzten Beispiel das nicht ganz der Fall ist. Da liesst du mit 00-00-11-01 ein Dreieck aus. Es müsste auch (links/rechts) 00-00-10-10 oder (oben/unten) 00-00-01-01 auch gehen. Daher ergibt sich bereits die Frage.

Zu meinem Beispielbild. Dieses habe ich vorhin manuell erstellt und dauerte etwa 10-15 min. Für alle Bilder würde es sich also lohnen sich ein kleines Programm zu schreiben, welches das tut. Das sollte dann auf 2D-Ebene geschehen. Das auslesen der UV-Koordinaten muß dann recht genau sein, denn sonst gerät man leicht aus den Streifen und es sieht dan blöd aus.

Edit1: Ich hab mal grad was geschrieben http://www.hectic.de/data/ring.rar

Hat nun volle 1500 Pixel Breite.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Neue Antwort erstellen


Übersicht BlitzBasic Blitz3D

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group