Image Bank Funktionen
Übersicht

KrischanBetreff: Image Bank Funktionen |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Da ich mich gerade mit Heightmaps beschäftige möchte ich Euch gerne diese schnellen Bankfunktionen vorstellen, die sich mit (Graustufen-)Heightmaps basierend auf Banks beschäftigen. Es ist viel schneller und effektiver, die Heightmaps als Banks zu laden oder als Bank vorgespeicherte Bilder einzulesen wenn man diese später manipulieren möchte, z.B. bilineares resampling für Vergrösserung / Verkleinerung oder Blending mit anderen Heightmaps. Für Realtime-Bildmanipulationen sind diese Funktionen sehr geeignet und ständigem Readpixel/Writepixel vorzuziehen.
Schaut Euch die Demo an, dann seht ihr, was gemeint ist und spielt ein wenig mit dem Scale-Wert herum. Bei Scale=2.0 steht es noch 1:1 zwischen Bank und Image. Aber geht mal höher... Es gibt hier folgende Funktionen (nicht alle werden in der Demo verwendet): LoadImageToBank(filename$) Lädt ein "normales" Bild in eine Bank, es wird aber nur der Rot-Kanal verwendet. LoadBank(filename$,width%,height%) Lädt ein Bankimage aus einer Datei, es müssen aber Breite/Höhe des Bildes angegeben werden. SaveBank(bank%,filename$) Speichert ein Bankimage als Datei. ScaleBank(bank%,width%,height%,ratio#) Skaliert ein Bankimage mit der aktuellen Breite/Höhe um den Ratio-Faktor (auch Float möglich) mit einem bilinearem Filter, also nahtlose Ränder möglich. CreateImageFromBank(bank%,width%,height%) Erstellt aus der Bank wieder ein zeichenfähiges Bild, z.B. für die Ausgabe. Breite/Höhe müssen hier mit der tatsächlichen Grösse übereinstimmen. GetBankPixel(bank%,px%,py%,width%) Holt einen Wert an der Stelle px/py aus der Bank heraus, also quasi ein ReadPixelUltraFast. SetBankPixel(value%,bank%,px%,py%,width%) Schreibt einen Wert an die Stelle px/py in der Bank, also quasi ein WritePixelUltraFast. CopyBankRect(bank%,sx%,sy%,width%,height%,bankwidth%) Ähnlich dem Copyrect-Befehl. SX/SY bestimmen die Startposition, width/height die Breite/Höhe des Ausschnitts und bankwidth die Breite des Gesamtbildes. Achtung: keine Abfrage, ob der Bereich ausserhalb der Bank ist! GetR(c%) / GetG(c%) / GetB(c%) / CombineRGB(r%,g%,b%) Hilfsfunktionen für die Umrechnung von RGB-Farbanteilen für Readpixel(fast)/Writepixel(fast) Die beiden weiteren Funktionen LinearInterpolate und Bilinear werden von der ScaleBank Funktion verwendet und erlauben lineare/bilineare Interpolation und sind somit universell verwendbar. Hier noch die Grafik, die für die Demo verwendet wird: Code: [AUSKLAPPEN] ms=MilliSecs()
hmap$="planet.png" ; Heightmap scale#=2.0 ; Skalierungsfaktor width=128 ; Breite der Heightmap height=64 ; Höhe der Heightmap swidth=width*scale ; Skalierte Breite sheight=height*scale ; Skalierte Höhe Graphics swidth,sheight+height,32,2 ; Bild in Bank einlesen image=LoadImageToBank(hmap$) ; Bild aus Bank erstellen output1=CreateImageFromBank(image,width,height) ; Skalieren und Bild erstellen image=ScaleBank(image,width,height,scale) output2=CreateImageFromBank(image,swidth,sheight) ; Bilder ausgeben DrawImage output1,0,0 DrawImage output2,0,height ; Zeitmessung AppTitle "Bank: "+(MilliSecs()-ms)+"ms" ; Tastendruck abwarten WaitKey ms=MilliSecs() ; zum Vergleich: Bild normal laden (mit Tformfilter) image=LoadImage(hmap$) TFormFilter 1 ; Originalbild zeichnen DrawImage image,0,0 ; skaliertes Bild zeichnen ResizeImage image,swidth,sheight DrawImage image,0,height ; Zeitmessung AppTitle "Image: "+(MilliSecs()-ms)+"ms" ; Tastendruck abwarten WaitKey End Function Bilinear#(bank%,width%,height%,x#,y#) Local x0#=Floor(x) Local y0#=Floor(y) Local x1#=Floor(x+1) Local y1#=Floor(y+1) Local dx#=x-x0 Local dy#=y-y0 Local x02x%=1 Local x03x%=1 Local y02x%=1 Local y03x=1 If x0<0 Then x02x=0 If x1>width-1 Then x03x=0 If y0<0 Then y02x=0 If y1>height-1 Then y03x=0 If x02x=0 Then x0=0 If y02x=0 Then y0=0 If x03x=0 Then x1=0 If y03x=0 Then y1=0 Local r0=GetBankPixel(bank,x0,y0,width)*x02x*y02x Local r1=GetBankPixel(bank,x1,y0,width)*x03x*y02x Local r2=GetBankPixel(bank,x1,y1,width)*x03x*y03x Local r3=GetBankPixel(bank,x0,y1,width)*x02x*y03x Return LinearInterpolate(LinearInterpolate(r0,r1,dx),LinearInterpolate(r3,r2,dx),dy) End Function Function LinearInterpolate#(x1#,x2#,mu#=0.5) Return (x1*(1.0-mu)+x2*mu) End Function Function GetBankPixel(bank%,px%,py%,width%) Return PeekByte(bank,(py*width)+px) End Function Function SetBankPixel(value%,bank%,px%,py%,width%) PokeByte bank,(py*width)+px,value End Function Function CopyBankRect(bank%,sx%,sy%,width%,height%,bankwidth%) Local x%,y%,h% Local output%=CreateBank(width*height) For y=sy To sy+height-1 For x=sx To sx+width-1 h=GetBankPixel(bank,x,y,bankwidth) SetBankPixel(h,output,x-sx,y-sy,width) Next Next Return output End Function Function ScaleBank(bank%,width%,height%,ratio#) Local x%,y%,c% Local ratio2w#=(ratio#*width-1)/(width-1.0) Local ratio2h#=(ratio#*height-1)/(height-1.0) Local newbank%=CreateBank((width*ratio)*(height*ratio)) For y=0 To (height*ratio)-1 For x=0 To (width*ratio)-1 Local u# = x*1.0/ratio2w# Local v# = y*1.0/ratio2h# c%=Bilinear(bank,width,height,u,v) SetBankPixel(c,newbank,x,y,width*ratio) Next Next Return newbank End Function Function LoadBank(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 SaveBank(bank%,filename$) Local f%=WriteFile(filename$) WriteBytes (bank,f,0,BankSize(bank)) CloseFile f End Function Function LoadImageToBank(filename$) Local x%,y%,rgb%,h% 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 h=GetR(ReadPixelFast(x,y,buffer)) SetBankPixel(h,bank,x,y,width) Next Next UnlockBuffer buffer FreeImage image Return bank End Function Function GetR(c%) Local r=(c And $ff0000)/$10000: Return r End Function Function GetG(c%) Local g=(c And $ff00)/$100: Return g End Function Function GetB(c%) Local b=c And $ff: Return b End Function Function CombineRGB(r%,g%,b%) Return r*$10000+g*$100+b End Function Function CreateImageFromBank(bank%,width%,height%) Local x%,y%,h%,r%,g%,b% Local image%=CreateImage(width,height) Local buffer%=ImageBuffer(image) LockBuffer buffer For x=0 To width-1 For y=0 To height-1 h=GetBankPixel(bank,x,y,width) WritePixelFast x,y,CombineRGB(h,h,h),buffer Next Next UnlockBuffer buffer Return image End Function Und für die, die sich fragen, wozu man das praktisch verwenden kann: im Moment versuche ich, einen Planeten mit 1024x512 Pixeln mittels dieser Funktionen, einer Fraktalmap und einer Shadowmap in eine hochauflösende 8192x4096 Colormap zu verwandeln, so dass aber die Grundstruktur (Kontinente, Berge, Wasser) erhalten bleibt. Dazu schneide ich 64x64 grosse Blöcke aus der Heightmap heraus, skaliere diese auf 512x512, blende sie mit einer fraktalen Heightmap und erzeuge daraus eine Colormap, die mit einer vorberechneten Shadowmap gemischt wird. Und der ganze Vorgang dauert nur etwa 200ms. Die Blöcke blenden übrigens nahtlos ineinander über, danke dem bilinearem resampling. Hier das Ergebnis: oben links das Ausgangsbild aus zwei nebeneinanderliegenden 64x64er Blöcken und der Rest wurde komplett nur daraus berechnet: |
||
![]() |
Chrise |
![]() Antworten mit Zitat ![]() |
---|---|---|
flottes Teil und das Ergebnis kann sich sehen lassen ![]() Schade nur, dass das Bild skaliert wird, wenn es zu groß ist. |
||
Krischan |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Chrise hat Folgendes geschrieben: Schade nur, dass das Bild skaliert wird, wenn es zu groß ist.
?!? Verstehe ich nicht, was meinst Du damit? |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group