Zeitversetzte Berechnung

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

 

Krischan

Betreff: Zeitversetzte Berechnung

BeitragSa, Jan 31, 2009 11:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Eigentlich ein Ding fürs Codearchiv, allerdings bin ich mit meiner Lösung noch nicht so ganz glücklich, vielleicht können wir das gemeinsam noch verbessern. Worum geht es?

user posted image

Es gibt viele Wege, eine Heightmap für einen zufälligen Planeten zu erstellen, mir waren aber alle bisherigen Lösungen zu langsam oder zu speicherintensiv. Die Idee hinter meinen Script ist es, einen halbwegs realistischen Planeten "on the fly" schrittweise zu generieren, und zwar in der Zeit, in der man auf ihn zufliegt (idealerweise unter 10 Sekunden). Der Code macht folgendes:

- erstelle ein Farbverlaufsarray
- erstelle ein Array mit der Grösse 512x256 (Heightmapgrösse)
- würfele dieses Array zufällig durcheinander
- suche 4 Heightmaps aus 10 vorberechneten Heightmaps heraus
- finde heraus, wie viele Pixel pro Durchlauf berechnet werden können
- berechne die Pixelpositionen anhand des Arrays
- blende sie mit drei verschiedenen Filtern ineinander
- berechne die Pixelfarben anhand des Farbverlaufs
- schreibe die Pixel auf die Planetentextur

Ich habe dazu eine Demo vorbereitet: Delayed Demo

Ablauf wie folgt: anfangs ist man 20 Units vom Planeten entfernt. Mit LMB könnt ihr wahnsinnig nah heranzoomen, am Anfang besteht der Planet nur aus Wasser. Drückt man nun die SPACE-Taste beginnt die Funktion, einen zufälligen Planeten schrittweise zu berechnen. Der Effekt ist fast nicht sichtbar, wenn man ohne Zoom mit der Pfeil-hoch-Taste losfliegt und kurz danach die SPACE-Taste drückt. Ist man am Planeten angelangt sieht dieser völlig anders aus und als Spieler hat man von der Generierung idealerweise gar nichts mitbekommen. Das mit dem zufälligen Array deshalb, weil man eine zeilenweise Berechnung auch aus grosser Distanz bemerken würde, so fällt das gar nicht auf Very Happy

Mit dieser Methode kann man aus nur 10 vorberechneten Heightmaps tausende verschiedene Planeten berechnen, je nach Filterkombination.

Mein Problem ist nur: auf manchen Geräten, auf denen ich es getestet habe brechen die FPS sehr stark ein und ich muss die Variable pixelstep% reduzieren (manche schaffen 8192, andere nur 512, alles Core2Duo), dann dauert es aber länger, den Planeten zu erstellen.

Frage an Euch: kann man das irgendwie verbessern?

Hier der Code, aber ohne Media nicht lauffähig:

Code: [AUSKLAPPEN]
Graphics3D 800,600,32,2

; Deklarationen
Dim GradientR%(0),GradientG%(0),GradientB%(0),Prozent%(0),Rot%(0),Gruen%(0),Blau%(0)
Dim images%(9)
Dim Array%(0)
Global maxx%=512
Global maxy%=256
Global max%=maxx*maxy
Global pixelstep%=512

; alles total zufällig
SeedRnd MilliSecs()

; Farbverlauf erstellen
Restore ClassMT : CreateGradient(9,255)

; Quellbilder einlesen
: For i%=0 To 9 : images(i)=LoadImage("512/planet"+i+".jpg") : Next

; Zufallsarray erstellen
CreateRandomArray(max)

; Zieltextur erstellen
output=CreateTexture(maxx,maxy,16+32)
buff5=TextureBuffer(output)
survey=CreateImage(maxx,maxy)
width=ImageWidth(survey)
buff6=ImageBuffer(survey)

; Grundfarbe der Textur festlegen
SetBuffer buff5
Color 17, 82,112
Rect 0,0,maxx,maxy,1
Color 255,255,255
SetBuffer BackBuffer()

; Planet
planet=CreateSphere(32)
ScaleEntity planet,10,10,10
PositionEntity planet,0,0,1000
EntityFX planet,2
EntityTexture planet,output,0,1
TextureBlend output,2
EntityShininess planet,0.25

; Wolkentextur
Clouds=CreateSphere(32,planet)
ctex=LoadTexture("clouds.png",2)
EntityTexture Clouds,ctex,0,1
ScaleTexture ctex,0.5,1
RotateTexture ctex,90
TextureBlend ctex,2
EntityBlend clouds,1
EntityOrder clouds,-1

; Licht
light=CreateLight(1)
AmbientLight 8,8,8

; Kamera
camera=CreateCamera()
PositionEntity camera,20,0,0
CameraRange camera,0.1,1000

; Maus in die Mitte, Kamera zielt auf Planet
MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
HidePointer()
PointEntity camera,planet

; anfangs keine Welt erstellen
newworld=False

; Zeit messen
time=MilliSecs()

; Hauptschleife
While Not KeyHit(1)
   
   ; FPS messung
    FPS_C=FPS_C+1 : If fms<MilliSecs() Then fms=MilliSecs()+1000 : FPS=FPS_C : FPS_C=0
   
   ; Frame tweening
   Tween#=Float(MilliSecs()-FrameTime)/10.0 : FrameTime=MilliSecs()
   
   ; einfache Steuerung
   mxs#=MouseXSpeed()
   mys#=MouseYSpeed()
   ;RotateEntity camera,EntityPitch(camera)+(mys#/5),EntityYaw(camera)-(mxs#/5),0
   If KeyDown(200) Then MoveEntity camera,0,0, 1*Tween
   If KeyDown(208) Then MoveEntity camera,0,0,-1*Tween
   
   ; aktuelle Zeit messen
   ms=MilliSecs()
   
   ; SPACE und Newworld-Flag False? dann neue Karte erstellen
   If KeyHit(57) Then
      
      ; Startzeit messen
      starttime=ms
      
      ; Pixelcounter rücksetzen
      i=0
      water%=0
      land%=0
      
      ; vier Planeten als Basis wählen
      map$=ZERO(Rand(0,9999),4)
      
      ; Planetencodes extrahieren
      i1=Int(Left(map,1))
      i2=Int(Mid(map,1,1))
      i2=Int(Mid(map,2,1))
      i4=Int(Right(map,1))
      
      ; neue Bildpuffer setzen
      buff1=ImageBuffer(images(i1))
      buff2=ImageBuffer(images(i2))
      buff3=ImageBuffer(images(i3))
      buff4=ImageBuffer(images(i4))
      
      ; Newworld-Flag auf True setzen
      newworld=True
      
   EndIf
   
   ; LMB = Kamerazoom erhöhen, um die Veränderung zu sehen
   If MouseDown(1) Then CameraZoom camera,50 Else CameraZoom camera,1
   
   ; Planet und Wolken ein wenig drehen
   TurnEntity planet,0,-0.1*Tween,0
   
   ; SPACE gedrückt, 30ms vergangen und Berechnungsflag wahr? Dann weiter
   If ms>time And newworld Then
      
      roundstart=ms
      
      ; Vergleichszeit = aktuelle Zeit + 60ms
      time=ms+30
      
      ; Anzahl Pixel pro Durchgang berechnen
      adder%=(pixelstep/Tween)
      
      ; Start/Ende für aktuellen Schleifendurchlauf setzen
      start=i
      ende=i+adder
      
      ; Ende grösser als Pixelanzahl? Dann Ende=Pixelanzahl
      If ende>max-1 Then ende=max-1
      
      ; Puffer sperren
      LockBuffer buff1
      LockBuffer buff2
      LockBuffer buff3
      LockBuffer buff4
      LockBuffer buff5
      LockBuffer buff6
      
      ; aktueller Schleifendurchlauf
      For j=start To ende
         
         ; Pixelinkrement
         i=i+1
         
         ; Pixel grösser als Pixelanzahl? Ende
         If i>max-1 Then
            newworld=False
            Goto skip
         EndIf
            
         ; X/Y-Position des Pixels aus dem Zufallsarray berechnen
         y=Int(Array(i)/maxx)
         x=Array(i)-(y*maxx)
         
         ; Quellfarben einlesen
         rgb1=ReadPixelFast(x,y,buff1)
         rgb2=ReadPixelFast(x,y,buff2)
         rgb3=ReadPixelFast(x,y,buff3)
         rgb4=ReadPixelFast(x,y,buff4)
         
         ; aufsplitten
         r1=255-(rgb1 And $ff0000)/$10000
         r2=(rgb2 And $ff0000)/$10000
         r3=255-(rgb3 And $ff0000)/$10000
         r4=(rgb4 And $ff0000)/$10000
         
         ; mit Filter mischen
         r=Average(r1,r2)
         r=Lighten(r,r3)
         r=HardLight(r,r4)
         
         ; Legende brauchbarer Filterkombinationen:
         ;
         ; S = Softlight
         ; M = Multiply
         ; L = Lighten
         ; A = Average
         ; H = Hardlight
         ; O = Overlay
         ; E = exclusion
         ; D = Difference
         ; N = Negation
         ;
         ; SSM = um 99% Land
         ; SSS = 25-75% Land
         ; SSL = 75-25% Land, flacher
         ; ALH = 35-65% Land, kontinental
         ; AMM =   100% Land, gebirgig
         ; OLS = 25-75% Land
         ; OLC =   <10% Land, ozeanisch
         ; MMM =   100% Land, verschneites Gebirge
         ; EDN = verschieden, erdähnlich, Archipelagos
         ; MNS = verschieden, erdännlich, Archipelagos
         
         ; über 128: unter Wasser, sonst Land
         If r>=128 Then water=water+1 Else land=land+1
         
         ; Zielfarbe aus Farbverlauf bestimmen
         rgb5=GradientR(r)*$10000+GradientG(r)*$100+GradientB(r)
         
         ; in Textur schreiben
         WritePixelFast x,y,rgb5,buff5
         WritePixelFast x,y,rgb5,buff6
         
      Next
      
      .skip
      
      endtime=MilliSecs()
      
      ; Puffer entsperren
      UnlockBuffer buff6
      UnlockBuffer buff5
      UnlockBuffer buff4
      UnlockBuffer buff3
      UnlockBuffer buff2
      UnlockBuffer buff1
      
      ; verbrauchte Millisekunden pro Durchgang berechnen
      midtime=(midtime+(endtime-roundstart))/2.0
      
   EndIf
   
   RenderWorld
   
   ; Ausgabe
   Text 0,  0,"Planet Source Maps: "+map
   Text 0, 15,"Pixels blended....: "+(i*100)/max+"%"
   Text 0, 30,"Transition Time...: "+(endtime-starttime)+"ms"
   Text 0, 45,"Used ms per cycle.: "+midtime+"ms"
   Text 0, 60,"Pixels per cycle..: "+adder
   Text 0, 75,"Water coverage....: "+(water*100.0)/max+"%"
   Text 0, 90,"Land coverage.....: "+(land*100.0)/max+"%"
   Text 0,105,"FPS...............: "+FPS
   Text 0,120,"Tris rendered.....: "+TrisRendered()
   
   DrawImage survey,GraphicsWidth()-width,0
   
   Flip 0
   
Wend

End

; Soft Light Filter
Function SoftLight(a%,b%)
   Local c%
   c=a*b Shr 8
   Return (c+a*(255-((255-a)*(255-b) Shr 8)-c) Shr 8)
End Function

; Hard Light Filter
Function HardLight(a%,b%)
   If b<128 Then Return (a*b) Shr 7 Else Return 255-((255-b)*(255-a) Shr 7)
End Function

; Differenz Filter
Function Difference(a%,b%)
   Return Abs(a-b)
End Function

; Multiply Filter
Function Multiply(a%,b%)
   Return (a*b) Shr 8
End Function

; Durchschnittsfilter
Function Average(a%,b%)
   Return (a+b) Shr 1
End Function

; Screenfilter
Function Screen(a%,b%)
   Return 255-((255-a)*(255-b) Shr 8)
End Function

; Aufhellfilter
Function Lighten(a%,b%)
   If a>b Then Return a Else Return b
End Function

; Abdunkelfilter
Function Darken(a%,b%)
   If a<b Then Return a Else Return b
End Function

; Negativfilter
Function Negation(a%,b%)
   Return 255-Abs(255-a-b)
End Function

; Ausschlussfilter
Function Exclusion(a%,b%)
   Return a+b-(a*b Shr 7)
End Function

; Overlayfilter
Function Overlay(a%,b%)
   If a<128 Then Return (a*b) Shr 7 Else Return 255-((255-a)*(255-b) Shr 7)
End Function

; Farbbrandfilter
Function ColorDodge(a%,b%)
   If b=255 Then
      Return 255
   Else
      Local c%=Floor((a Shl 8)/(255-b))
      If c>255 Then Return 255 Else Return c
   EndIf
End Function

; Farbverlauf erstellen
Function CreateGradient(colors%,steps%)
   
   Dim GradientR%(steps),GradientG%(steps),GradientB%(steps),Prozent%(colors),Rot%(colors),Gruen%(colors),Blau%(colors)
   
   Local i%,pos1%,pos2%,pdiff%
   Local rdiff%,gdiff%,bdiff%
   Local rstep#,gstep#,bstep#
   Local counter%=1
   
   ; Farbcodes einlesen
   For i=1 To colors : Read Prozent(i),Rot(i),Gruen(i),Blau(i) : Next
   
   ; Gradient berechnen
   While counter<colors
      
      ; Prozent in Step-Position umrechnen
      pos1=Prozent(counter)*steps/100
      pos2=Prozent(counter+1)*steps/100
      
      ; Abstand berechnen
      pdiff=pos2-pos1
      
      ; Differenz zwischen den Farben berechnen
      rdiff%=Rot(counter)-Rot(counter+1)
      gdiff%=Gruen(counter)-Gruen(counter+1)
      bdiff%=Blau(counter)-Blau(counter+1)
      
      ; Schrittweite zwischen den Farben berechnen
      rstep#=rdiff*1.0/pdiff
      gstep#=gdiff*1.0/pdiff
      bstep#=bdiff*1.0/pdiff
      
      ; Zwischenfarbcodes berechnen
      For i=0 To pdiff
         
         GradientR(pos1+i)=Int(Rot(counter)-(rstep*i))
         GradientG(pos1+i)=Int(Gruen(counter)-(gstep*i))
         GradientB(pos1+i)=Int(Blau(counter)-(bstep*i))
         
      Next
      
      ; Zähler erhöhen
      counter=counter+1
      
   Wend
   
End Function

; Zufallsarray erstellen. Es werden alle Werte zufällig durcheinandergewürfelt, so dass jeder Wert nur 1x vorkommt
Function CreateRandomArray(size%)
   
   ; Array neu dimensionieren
   Dim Array(size)
   
   ; Array mit allen Zahlen von 1...size füllen
   For i = 0 To size-1 : Array(i) = i : Next
   
   ; Würfeln
   For N% = 0 To size-2
      
      M% = Rand( N%, size - 1)
      Z% = Array(N%)
      
      Array(N%) = Array(M%)
      Array(M%) = Z%
      
   Next
   
End Function

; Zahl mit immer gleicher Anzahl an Stellen rückgeben, mit vorangestellen Nullen
Function ZERO$(number%,lenght%=2)
   
   Local r$=""
   
   For i=1 To lenght-Len(Str(number))
      
      r$=r$+"0"
      
   Next
   
   Return r$+Str(number)
   
End Function

; Farbverlaufcodes für einen Klasse-M-Planeten
.ClassMT
Data   0,255,255,255
Data   5,179,179,179
Data  10,153,143, 92
Data  25,115,128, 77
Data  48, 42,102, 41
Data  50, 69,108,118
Data  52, 17, 82,112
Data  75,  9, 62, 92
Data 100,  2, 43, 68


EDIT: wenn ihr auch ein wenig herumfliegen wollt, einfach die Zeile mit "Rotateentity camera" entkommentieren.

aMul

Sieger des Minimalist Compo 01/13

BeitragSa, Jan 31, 2009 12:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Du könntest deine viermal ReadPixelFast weglassen, wenn du deine Vorlagen vorher in Arrays/Banks lädst, das sollte schon mal einen ordentlichen Schub geben.

Weiterhin könntest du überlegen, ob du die Größe der Textur vielleicht der Entfernung zum Planeten anpassen möchtest. Ich weiß nicht inwiefern man hier Leistung sparen kann, aber wenn man zum Beispiel zuerst nur eine 64*64 große Textur füllt und sobald man näher kommt diese durch immer größere ersetzt kriegt man vielleicht auch noch ein paar FPS(wenn man sich schlau anstellt). Zudem spart man so Speicher wenn die Planeten weit entfernt sind und man kann sich sollte man an einem Planeten nur in einiger Entfernung vorbeifliegen(sollte die Möglichkeit vorgesehen sein) die Berechnung einer größeren Textur ganz sparen.

Ansonsten ist das was du da hast eine sehr interessante Idee und die Ergebnisse sehen sehr überzeugend aus. Weiter so!

EDIT:

Achja, du könntest auch mal versuchen den VRAM-Parameter(256) von CreateTexture zu benutzen.
Panic Pong - ultimate action mashup of Pong and Breakout <= aktives Spiele-Projekt, Downloads mit vielen bunten Farben!
advASCIIdraw - the advanced ASCII art program <= aktives nicht-Spiele-Projekt, must-have für ASCII/roguelike/dungeon-crawler fans!
Alter BB-Kram: ThroughTheAsteroidBelt - mit Quelltext! | RGB-Palette in 32²-Textur / Farbige Beleuchtung mit Dot3 | Stereoskopie in Blitz3D | Teleport-Animation Screensaver
 

Krischan

BeitragMo, Feb 02, 2009 17:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für den Tip mit den Banks, ich habe meinen eigenen Code noch nicht umgeschrieben, aber mein Testbed spricht schon Bände: im Vergleich zu einer normalen Readpixelfast/Writepixelfastcombo ist das Auslesen aus einer Bank etwa 50x schneller, hier eine Demo (waynes interessiert - die Grafik "planet0.jpg" befindet sich in meiner oben verlinkten Demo):

Code: [AUSKLAPPEN]
sizex%=512
sizey%=256
gfx$="planet0.jpg"

Graphics sizex,sizey*2,32,2

bank=LoadImageBank(gfx$)
;SaveBankImage(bank,"test.img")
;bank=LoadBankImage("test.img",sizex,sizey)

vergleich=LoadImage(gfx$)

While Not KeyHit(1)
   
   ms1=MilliSecs()
   DrawImageBank bank,sizex,sizey
   zeit1=MilliSecs()-ms1
   
   ms2=MilliSecs()
   DrawVergleichImage(vergleich,sizey)
   zeit2=MilliSecs()-ms2
   
   Text 0,0,"Bank: "+zeit1+"ms"
   Text 0,sizey,"Readpixelfast: "+zeit2+"ms"
   
   Flip
   
Wend

End

Function LoadImageBank(filename$)
   
   Local x%,y%,rgb%,h%,offset%
   
   Local image%=LoadImage(filename$)
   Local width%=ImageWidth(image)
   Local height%=ImageHeight(image)
   
   Local bank%=CreateBank(width*height)
   
   Local buffer%=ImageBuffer(image)
   
   LockBuffer buffer
   
   For x=0 To width-1
      
      For y=0 To height-1
         
         rgb=ReadPixelFast(x,y,buffer)
         h=(rgb And $ff0000)/$10000
         
         offset=(y*width)+x
         PokeByte bank,offset,h
         
      Next
      
   Next
   
   UnlockBuffer buffer
   
   FreeImage image
   
   Return bank
   
End Function

Function SaveBankImage(bank%,filename$)
   
   Local f%=WriteFile(filename$)
   
   WriteBytes (bank,f,0,BankSize(bank))
   
   CloseFile f
   
End Function

Function LoadBankImage(filename$,width%,height%)
   
   Local f%=OpenFile(filename$)
   
   Local bank%=CreateBank(width*height)
   
   ReadBytes(bank,f,0,BankSize(bank))
   
   CloseFile f
   
   Return bank
   
End Function

Function DrawImageBank(bank%,width%,height%)
   
   Local x%,y%,h%,offset%,rgb%
   
   Local buffer%=FrontBuffer()
   
   LockBuffer buffer
   
   For x=0 To width-1
      
      For y=0 To height-1
         
         offset=(y*width)+x
         h=PeekByte(bank,offset)
         
         rgb=h*$10000+h*$100+h
         WritePixel x,y,rgb,buffer
         
      Next
      
   Next
   
   UnlockBuffer buffer
   
End Function

Function DrawVergleichImage(image,offsety)
   
   Local x%,y%,rgb%,h%
   
   Local width%=ImageWidth(image)
   Local height%=ImageHeight(image)
   
   Local buffer1%=FrontBuffer
   Local buffer2%=ImageBuffer(image)
   
   LockBuffer buffer1
   LockBuffer buffer2
   
   For x=0 To width-1
      
      For y=0 To height-1
         
         rgb=ReadPixelFast(x,y,buffer2)
         h=(rgb And $ff0000)/$10000
         
         rgb=h*$10000+h*$100+h
         WritePixelFast x,y+offsety,rgb,buffer1
         
      Next
      
   Next
   
   UnlockBuffer buffer2
   UnlockBuffer buffer1
   
End Function
 

Omenaton_2

BeitragDi, Feb 03, 2009 11:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bin ein weniger technisch denkender Mensch. Ich würde nicht so aufwendig einen Zufallsplaneten berechnen lassen, sondern gleich über "Faken" des Ganzen nachdenken. Ich bevorzuge eine Lösung die schnell zu machen ist und dann auch im Porgrammverlauf möglichst schnell läuft.

Ich würde eigenlich so vorgehen, als ob ich eine Zufallskarte für ein Spiel wie Civilisation errechnen würde. Also erst alles mit Wasser füllen, dann aus einigen vorberechneten Quadraten mit Land darauf paar Kontinente zusammenfügen. Das alles zusammen als 1 Textur abspeichern und dem Planeten zuweisen.
Es mag sein, daß das letztendlich genauso aufwendig wäre, wie deine jetztige Pixelberechnung, aber ich denke das Ergebnis wäre natürlicher und die Berechnung eine Frage von Millisekunden.
 

Krischan

BeitragDi, Feb 03, 2009 13:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Glaub mir, ich habe schon alle Möglichkeiten durch und das Thema beschäftigt mich seit Jahren (!). Ich habe die Bank-Lösung nun in meinen Code eingebaut und ich muss sagen: ich bin extremst begeistert und hätte nicht gedacht, dass es so einen Performancegewinn dadurch gibt. Ich kann z.B. nun einen Planeten in 250ms berechnen und habe dafür einen Aufwand von etwa 5ms pro Durchgang bei einem Pixelstep von 16384 bei einer Texturgrösse von 1024x512! In FPS ausgedrückt ein Drop von nur noch 4 FPS bei 375 FPS! Ich kann nun ein ganzes Sonnensystem in 1-2 Sekunden "nebenher" beim Anflug berechnen lassen und dabei zehntausende verschieden aussehende Planeten generieren (es sind ja nicht nur die Kombinationen der 10 verschiedenen Vorlagen oder der Blendfilter, nein ich kann die ja auch noch verschieden einfärben und mal ein Klasse M Planet, mal einen Lavaplaneten, mal einen Mond generieren).

Hast Du eine Demo für Deinen Ansatz? Ich bin natürlich immer offen für Verbesserungen, wobei die Welt, die ich im Moment erzeuge für meine Zwecke voll und ganz ausreicht. Code für das o.g. reiche ich noch nach, hab im Moment keine Zeit das ein wenig aufzubereiten.
 

Matthias

BeitragDi, Feb 03, 2009 16:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Hay ich habe mich auch mal daran versucht. Nunja ich arbeite mit Dim felder, weil diese noch ein Tick schneller sind.

Texture 1024x512 wird auf meinen Rechner im Durchnitt mit 40-50ms berechnet.

Wenn die Pixelpositionen nicht getauscht werden (Area()). Wenn sie aber getauscht werden dauerts 160-180ms. Seltsamm.

Ich weiß nicht an was es liegt. Egal.

Auf jedenfall gehts schon sehr schnell.

Code: [AUSKLAPPEN]

Graphics 1024,512,32,2
Dim GPTexturen(0),GPGradient(256),GPRandMap(0)
Global GPTexSizeX,GPTexSizeY
Global GPMapNumber,GPlanetCount
Global TImg=CreateImage(1024,512)
Timer=CreateTimer(60)


InitPlanetGenerator()
UpdPlanetTextur()


SetBuffer BackBuffer()
Repeat

   If KeyHit(57)=1 Then
      GPMapNumber=MilliSecs():GPlanetCount=0
   End If

   If GPlanetCount>-1 Then UpdPlanetTextur(10)


   DrawBlock TImg,0,0


Flip 0:WaitTimer(Timer)
Until KeyDown(1)=1
End







Function UpdPlanetTextur(MaxMS=1000)



   Zeit=MilliSecs()
   Tween=MilliSecs()+MaxMS
   MNumber$=Right("0000"+GPMapNumber,4)

   
   TexSize=(GPTexSizeX*GPTexSizeY)
   PTDataOfset0=(Asc(Mid(MNumber,1,1))-48)*TexSize
   PTDataOfset1=(Asc(Mid(MNumber,2,1))-48)*TexSize
   PTDataOfset2=(Asc(Mid(MNumber,3,1))-48)*TexSize
   PTDataOfset3=(Asc(Mid(MNumber,4,1))-48)*TexSize
   

   IBuff=ImageBuffer(TImg):LockBuffer IBuff
   Repeat:Pos=GPRandMap(GPlanetCount)
   
      X=Int(Pos/GPTexSizeY):Y=Pos-X*GPTexSizeY
     
      R1=GPTexturen(PTDataOfset0+Pos)
      R2=255-GPTexturen(PTDataOfset1+Pos)
      R3=GPTexturen(PTDataOfset2+Pos)
      R4=255-GPTexturen(PTDataOfset3+Pos)     
 

      r=Average(r1,r2)
      r=Lighten(r,r3)
      r=HardLight(r,r4)
     
      GPlanetCount=GPlanetCount+1:Count=Count+1
      WritePixelFast(X,Y,GPGradient(R),IBuff)
      If GPlanetCount=TexSize Then GPlanetCount=-1 Exit
      If Count>65536 Then Count=0:If MilliSecs()>Tween Then Exit
     
   Forever:UnlockBuffer IBuff
   If MaxMS=1000 Then AppTitle (MilliSecs()-Zeit)
End Function


Function HardLight(a%,b%)
   If b<128 Then Return (a*b) Shr 7 Else Return 255-((255-b)*(255-a) Shr 7)
End Function

Function Average(a%,b%)
   Return (a+b) Shr 1
End Function

Function Lighten(a%,b%)
   If a>b Then Return a Else Return b
End Function

Function InitPlanetGenerator()
   CreateGradient()

   For TexCount=0 To 9:TexName$="1024\Planet"+TexCount+".jpg"
      Image=LoadImage(TexName):GPTexSizeX=ImageWidth(Image)
      GPTexSizeY=ImageHeight(Image):IBuff=ImageBuffer(Image)

      If TexCount=0 Then TexSize=GPTexSizeX*GPTexSizeY
      If TexCount=0 Then Dim GPTexturen(TexSize*10)
     

      LockBuffer IBuff:Count=TexCount*TexSize
      For X=0 To GPTexSizeX-1:For Y=0 To GPTexSizeY-1
         RGB=(ReadPixelFast(X,Y,IBuff) Shl 8) Shr 24
         GPTexturen(Count)=RGB:Count=Count+1
      Next:Next:UnlockBuffer IBuff:FreeImage Image
   Next:TexSize=TexSize-1
   
 
   Dim GPRandMap(TexSize+1)
   For I=0 To TexSize:GPRandMap(i)=i:Next
 

   ;Return
   

   
   For N=0 To TexSize
      M=Rand(N,TexSize-2):Z=GPRandMap(N)
      GPRandMap(N)=GPRandMap(M)
      GPRandMap(M)=Z
   Next

   
End Function






Function CreateGradient()

   Repeat:LevA=LevB
      RedA=RedB:GreenA=GreenB:BlueA=BlueB

      Read LevB,RedB,GreenB,BlueB
      M#=(LevB-LevA):C=0:R#=(RedB-RedA)/M
      G#=(GreenB-GreenA)/M:B#=(BlueB-BlueA)/M

      For I=LevA To LevB
         RR=R*C+RedA GG=G*C+GreenA BB=B*C+BlueA               
         GPGradient(I)=RR*65536+GG*256+BB:C=C+1
      Next
   Until LevB=255   
End Function

Data   0,255,255,255
Data  12,179,179,179
Data  25,153,143, 92
Data  64,115,128, 77
Data 122, 42,102, 41
Data 128, 69,108,118
Data 133, 17, 82,112
Data 191,  9, 62, 92
Data 255,  2, 43, 68


PS: Wird bestimmt ein Hammerspiel mit sooooooooooooooo viele Planeten. Laughing
 

Krischan

BeitragDi, Feb 03, 2009 18:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Dein Code braucht bei mir 38ms, allerdings dafür Ewigkeiten bis mal was kommt... ich habe jetzt mal schnell was zusammengeschnürt. Mit dabei: der original Planetengenerator, der aus einer 3D Perlin Noise Cloud diese Karten "herausschält", so dass sie nahtlos auf eine Sphere mappen (auch an den Polen). Speichern tut dieser gleich im Bank-Format, welches von der delayed.bb eingelesen wird (ich habe die "original" 10 Planeten in diesem Format beigelegt).

Selbst wenn Arrays ein wenig schneller sind: meine Bank benutzt nur ein Byte pro Höheninfo (Array dann wohl volles Int, also zwei Bytes?), also ist der Speicherverbrauch geringer. Andererseits sind es nur 10 Planeten, die als Basis ausreichen sollten. Im Moment bin ich ja noch in Techdemos und Machbarkeitsstudien, aber wenn ich das alles einmal zu einen Spiel zusammenfüge, möchte ich schon bis zu 1000 Sterne besuchen können, die dann bis zu 10.000 Planeten haben (realistisch sind wohl eher 100 Sterne mit 500 Planeten, sonst dauert das ja ewig bis man alle besucht hat - mal sehen...). Die Planeten werden dann aber realtime aus einem Seed berechnet.

Download: Delayed Planet Generator

Zum Vergleich: ich bekomme hier 538FPS und wenn ich ständig auf der SPACE-Taste herumhämmere nicht weniger als 430FPS (die FPS droppen hier mehr, da ich die Cam nun viel näher am Planeten positioniert habe - später im Spiel wird der Planet ja schon erstellt, bevor man auch nur einen Pixel von ihm sieht).

Nicdel

BeitragDi, Feb 03, 2009 18:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Selbst bei meiner Onboard-Karte mit 64 MB schafft das Programm beim Erzeugen des Planeten 20 FPS . Gar nicht mal so schlecht... Very Happy

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group