[B2D] Bilder drehen (fast) in Echtzeit

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

ToeB

Betreff: [B2D] Bilder drehen (fast) in Echtzeit

BeitragMi, Jan 07, 2009 16:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Also ich hab mal drüber nachgedacht wie man ohne zeitfressende laden und drehen der Bilder vereinfachen kann, und bin zu dem schluss gekommen, das man sie EINMAL läd und dann rotiert hinzeichnet (ähnlich Draw3D). Die Brechnung dazu st noch nicht perfect und auch noch sehr ausbaufähig, aber wenn man sie braucht ist sie nützlich :

Das ganze funzt so, dass ich jeden pixel im bild so wie es ist auslese, dann den winkel und abstand zur mitte messe und dann mit Sin+Cos in den winkel+den eigenen winkel zeichne mit dem errechneten abstand.

Code: [AUSKLAPPEN]
Function DrawRotateImage(bild,x#,y#,w#=0,mask=$FF000000,ZielBuffer=0)
   If w# = 0
      DrawImage bild,x,y
   Else
      If ZielBuffer = 0 ZielBuffer = BackBuffer()
      Local Buffer_draw = ZielBuffer
      Local Buffer_get = ImageBuffer(bild)
      Local Image_w = ImageWidth(bild)
      Local Image_h = ImageHeight(bild)
      Local Image_mx# = Image_w/2.0
      Local Image_my# = Image_h/2.0
      LockBuffer Buffer_draw
      LockBuffer Buffer_get
      For xx = 0 To Image_w -1
         For yy = 0 To Image_h -1
            pix_r = ReadPixelFast(xx,yy,Buffer_Get)
            If pix_r <> mask
               rad# = Sqr( ( xx - Image_mx ) ^ 2 + ( yy - Image_my ) ^ 2 )
               winkel# = (-ATan2((xx - Image_mx),(yy - Image_my))) + w#+90
               ;DebugLog winkel
               WritePixel(x#+Cos(winkel#)*rad#,y#+Sin(winkel#)*rad#,pix_r,Buffer_draw)
            EndIf
         Next
      Next
      UnlockBuffer Buffer_get
      UnlockBuffer Buffer_draw            
   EndIf
End Function


und hier mal ein Beispiel wers gebrauchen kann :

Code: [AUSKLAPPEN]
Graphics 800,600,16,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

Global wcrate = LoadImage("smile.png") : MidHandle wcrate : MaskImage wcrate,255,0,255
If wcrate = 0 RuntimeError("Bild exestiert nicht")
Global MaskWCrate = $FFFF00FF

Global anz = 9
   Dim xp(anz)
   Dim yp(anz)
   Dim wp(anz)
   
For i = 0 To anz
   xp(i) = Rand(800)
   yp(i) = Rand(600)
Next



Repeat
   FPS_C = FPS_C + 1
   If FPS_MS <= MilliSecs() - 1000 FPS = FPS_C : FPS_C = 0 : FPS_Ms = MilliSecs()
   Cls
   For i = 0 To anz
      wp(i) = -ATan2(xp(i)-MouseX(),yp(i)-MouseY())   
      DrawRotateImage(wcrate,xp(i),yp(i),wp(i),MaskWCrate,BackBuffer())
   Next    
   ;DrawImage wcrate,100,100
   ;Rot = (Rot + 1) Mod 360
   Text 0,0,FPS
   ;Text 0,15,rot
   Flip
Until KeyHit(1)
End

Function DrawRotateImage(bild,x#,y#,w#=0,mask=$FF000000,ZielBuffer=0)
   If w# = 0
      DrawImage bild,x,y
   Else
      If ZielBuffer = 0 ZielBuffer = BackBuffer()
      Local Buffer_draw = ZielBuffer
      Local Buffer_get = ImageBuffer(bild)
      Local Image_w = ImageWidth(bild)
      Local Image_h = ImageHeight(bild)
      Local Image_mx# = Image_w/2.0
      Local Image_my# = Image_h/2.0
      LockBuffer Buffer_draw
      LockBuffer Buffer_get
      For xx = 0 To Image_w -1
         For yy = 0 To Image_h -1
            pix_r = ReadPixelFast(xx,yy,Buffer_Get)
            If pix_r <> mask
               rad# = Sqr( ( xx - Image_mx ) ^ 2 + ( yy - Image_my ) ^ 2 )
               winkel# = (-ATan2((xx - Image_mx),(yy - Image_my))) + w#+90
               ;DebugLog winkel
               WritePixel(x#+Cos(winkel#)*rad#,y#+Sin(winkel#)*rad#,pix_r,Buffer_draw)
            EndIf
         Next
      Next
      UnlockBuffer Buffer_get
      UnlockBuffer Buffer_draw            
   EndIf
End Function


Parameter :
DrawRotateImage(Handle%,xPos#,yPos#,Winkel#[,Mask%][,Buffer%])
Handle = Bild Handle (weches mit LoadImage angegeben wird)
xPos/yPos = Position des Bildes (!!Beachten!! das bild wird mittig gezeichnet !)
Winkel = Winkel des Bildes (0-360)
Mask = Maskcolor (in Hexadezimalcode, z.b. für MaskImage 255,0,255 -> $FFFF00FF)
Buffer = Der Buffer auf dem das Bild gezeichnet werden soll(somit sind z.B. das Speichern in Bildern möglich)

mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!
 

ke^kx

BeitragMi, Jan 07, 2009 16:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Äh da gibt es extra nen befehl für:

https://www.blitzforum.de/help/TFormImage

Ansonsten ist die idee mit dem vorher laden natürlich gut anwendbar aber wohl auch nicht neu Wink
http://i3u8.blogspot.com
Asus Striker II
Intel Core2Quad Q9300 @ 2,5 GHz (aber nur zwei Kerne aktiv aufgrund der Instabilität -.-)
Geforce 9800 GTX
2GB RAM

ToeB

BeitragMi, Jan 07, 2009 17:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Ja aber es ging ja auch darum mal was selber zu machen...
Von dem Befehl allerdings wusst ich nich wie ich den anwenden soll...

mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

ozzi789

BeitragMi, Jan 07, 2009 18:42
Antworten mit Zitat
Benutzer-Profile anzeigen
nice! Smile
mit kleineren bilder gehts in echtzeit Razz
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

Eingeproggt

BeitragMi, Jan 07, 2009 19:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich fand da mal was im englischen Codearchiv, um Bilder mithilfe von 3D-Beschleunigung (Nein, kein Draw3D-artiges System sondern mit 2D-Images, aber seht selbst) in Echtzeit zu skalieren.
Mir kam der Gedanke, auf dieselbe Art eine Echtzeit-Rotation hinzukriegen. Leider scheiterte ich bei der Berechnung der Abmessungen des neuen Bildes Embarassed Wer sich der Sache mal annehmen will:

Code: [AUSKLAPPEN]
; yet another QUICK SCALE
; An example on how to use 3D Hardware to speed up scaling of 2D images.
; written by jfk of csp

; results: scaling a 1024*768 image to half the size was
; 109 times faster than ResizeImage() with TFormFiter on
; 36 times faster than ResizeImage() with TFormFiter off

; There are some limits with this method:
; images may not be bigger than 1024*1024 prior scaling.
; images may not be bigger than the current Graphics Resolution after scaling.



Graphics3D 1024,768,32,2
;Graphics3D 800,600,32,2
;Graphics3D 640,480,32,2
SetBuffer BackBuffer()

ClsColor 100,100,100

Global testfile$="testbmp.bmp"


;-------------------------- Demo:-------------------------------

TFormFilter 1
;test speed of blitzs built in scaling
img=LoadImage(testfile$) ; a test image, max 1024 * 1024 !

t1=MilliSecs()
ResizeImage img,ImageWidth(img)/2,ImageHeight(img)/2
t2=MilliSecs()
Cls:DrawImage img,10,10
Text 0,580,"TFormFiler on, Blitz Scaling: "+(t2-t1)+" ms"
Flip 0
WaitKey()
FreeImage img

;---------------------------------------------------------------

TFormFilter 0
;test speed of blitzs built in scaling (now with Filter off)
img=LoadImage(testfile$)

t1=MilliSecs()
ResizeImage img,ImageWidth(img)/2,ImageHeight(img)/2
t2=MilliSecs()
Cls:DrawImage img,10,10
Text 0,580,"TFormFiler off, Blitz Scaling: "+(t2-t1)+" ms"
Flip 0
WaitKey
FreeImage img

;---------------------------------------------------------------

; now test speed of faster scaling utilizing 3D Hardware
img=LoadImage(testfile$)

t1=MilliSecs()
img=myResizeImage(img,ImageWidth(img)/2,ImageHeight(img)/2)
t2=MilliSecs()
Cls:DrawImage img,10,10
Text 0,580,"3D Image Scaling: "+(t2-t1)+" ms"
Flip 0
WaitKey()

End

Function myResizeImage(img,w#,h#,cam0=0)
; img-handle, desired width and height, optional camera handle that may be deactivated during rescaling
; note: width and height may not be bigger than current Graphics resolution, or they will be clipped!
   Local img_w#=ImageWidth(img)
   Local img_h#=ImageHeight(img)
   If img_w>1024 Then img_w=1024
   If img_h>1024 Then img_h=1024
   If img_w<1 Then img_w=1
   If img_h<1 Then img_h=1
   
   If w>1024 Then w=1024
   If h>1024 Then h=1024
   If w<1 Then w=1
   If h<1 Then h=1
   
   w_rel#=w#/img_w#
   h_rel#=h#/img_h#
   g_rel#=1024.0/GraphicsWidth()
   
   Local cam1=CreateCamera()
   CameraProjMode cam1,0
   Local Quad=CreateQuad()
   Local Tex=CreateTexture(1024,1024,256 Or 16 Or 32)
   EntityTexture Quad,Tex
   EntityFX Quad,1
   CameraRange cam1,.001,10
   TranslateEntity cam1,(1.0/1024.0),-(1.0/1024.0),-1.0
   EntityParent Quad,cam1,1
   PositionEntity cam1,32000,16000,16000
   
   CopyRect 0,0,img_w,img_h,512-(img_w/2.0),512-(img_h/2.0),ImageBuffer(img),TextureBuffer(Tex)
   ScaleEntity Quad,w_rel*g_rel,h_rel*g_rel,0.0001
   If cam0<>0 Then CameraProjMode cam0,0
   CameraProjMode cam1,1
   RenderWorld()
   CameraProjMode cam1,0
   If cam0<>0 Then CameraProjMode cam0,1
   
   Local img2=CreateImage(w,h)
   CopyRect (GraphicsWidth()/2.0)-(w/2.0),(GraphicsHeight()/2.0)-(h/2.0),w,h,0,0,BackBuffer(),ImageBuffer(img2)
   FreeImage img
   FreeTexture Tex
   FreeEntity Quad
   Return img2
End Function

Function CreateQuad()
   ;creates a quad, facing To the -Z side
   mesh=CreateMesh()
   surf=CreateSurface(mesh)
   v0=AddVertex(surf, -1.0,   1.0,0, 0,0 )
   v1=AddVertex(surf,  1.0,   1.0,0, 1,0 )
   v2=AddVertex(surf,  1.0,  -1.0,0, 1,1 )
   v3=AddVertex(surf, -1.0,  -1.0,0, 0,1 )
   AddTriangle(surf,v0,v1,v2)
   AddTriangle(surf,v0,v2,v3)
   UpdateNormals mesh
   Return mesh
End Function


(Code gepostet, da ich den Code im englischen Archiv grad nicht finden kann...)
Sollte eig nicht so schwer sein und ich versprech euch das is sauschnell Smile

Mahlzeit, Christoph.

EDIT. Ja, natürlich ist 3D immer dasselbe Prinzip, man zieht eine Textur über 2 Triangles oh Wunder Rolling Eyes
Aber das Einzeichnen erfolgt hier als 2D-image, das mein ich.
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9
  • Zuletzt bearbeitet von Eingeproggt am Mi, Jan 07, 2009 19:36, insgesamt einmal bearbeitet

tedy

BeitragMi, Jan 07, 2009 19:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Ist doch ziemlich das selbe was draw3d auch macht :O nur benutzt Draw3d meines wissens Sprites
01010100 01100101 01000100 01111001 00100000 00111010 01000100

ToeB

BeitragMi, Jan 07, 2009 19:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Also Draw3D benutz keine Sprites sondern läuft mit SimgleSurface (Sonst würde man die hohen FPS-Zahlen gar nicht hinbekommen)

Und das gleiche tut diese Function hier auch, nur das das glaub ich über den BackBuffer geregelt wird, also sowas ähnliches wie Screenshots.


mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMi, Jan 07, 2009 20:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Der gepostete Code von Eingeproggt macht folgendes. Es lädt ein 2D-Image und jagt das Handle in die Funktion myResizeImage. In dieser wird dann ungeachtet der notwendigen Größe eine Textur mit dem Ausmaß von 1024x1024 (4MB Grafikkartenspeicher) erstellt und mit CopyRect einfach der ImageBuffer auf den TextureBuffer kopiert.

Die bisher uneffizienteste Lösung die ich bisher gesehen habe.

Und wie ToeB schon eben sagte, die Draw3D benutzt keine Sprites, denn dann wäre bereits nach 500 Objekten schon eine schöne Diaschow zu bewundern.

- - -

@ToeB

Du kannst deine Funktion noch optimieren, indem du nicht für jedes Pixel Cos und Sin einzelnd errechnest, sondern den berechneten und gedrehten ''Rahmen'' als Vorlage nutzt. Denn der Winkel ändert sich innerhalb eines Images ja nicht. Somit reicht es, wenn du 3 der 4 Eckpunkte vorberechnest und das Zeichnen dann mit einer einfachen Linearrechnung ablegst. Zudem kann man dann auch selbst die X und Y -Werte auch noch zwischenspeichern, so dass wirklich nur noch mit einer doppelt verschachtelten Schleife direkt gezeichnet wird und zwar ganz ohne Zwischenrechnugen.

Tipp: Man kann im übrigen die transparente Pixelstellen wegbekommen, wenn man das Zeichnen umgekehrt macht. Also nicht die neue Position eines jeden Pixels ausrechnen, sondern den Farbwert eines Pixels anhand der Quellvorlage ausgehend zeichnen. Das heisst, man rendert eher als das man zeichnet. Im Zusammenhang mit meinem vorherigem Vorschlag allerdings kein so einfaches unterfangen, wenn man das noch nie gemacht hat. Du kannst dir aber gerne den Grundgedanken aus GetTexel3D abschauen. Da wird zwar nur ein Texel ausgelesen, aber das Grundmuster ist das selbe. Andere und eventuell bessere Beispiele kenne ich nicht.

- - -

Edit1:

In anbetracht des Beitrages unter mir von Noboody erkenne ich den Grund für so ein Vorgehen nun besser dieser komischen Funktion myResizeImage. Man sollte aber beachten, dass der 2D-Modus schon allein deshalb langsamer sein kann, indem man Graphics3D macht. Denn in diesem Modus laufen so einige Grafikkarten dann schon langsamer, auch wenn man kein 3D selbst anwendet.
  • Zuletzt bearbeitet von hectic am Mi, Jan 07, 2009 20:47, insgesamt einmal bearbeitet

Noobody

BeitragMi, Jan 07, 2009 20:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Naja, die Funktion macht nichts anderes, als das Bild per Quad einzuzeichnen und das gerenderte Bild wieder in einem Bild zu speichern.
Das ist wohl hauptsächlich für Anwendungen ausserhalb der Hauptschleife gedacht - ein System wie die Draw3D ist viel geeigneter, wenn die Bilder in Echtzeit skaliert eingezeichnet werden sollen. Die Funktion hier ist wohl eher dafür gedacht, einen Ersatz für das bisherige ResizeImage zu bieten, um beispielsweise bei einer geänderten Auflösung die Bilder kurz neu zu skalieren.

EDIT: Da war hectic wohl schneller Razz
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Eingeproggt

BeitragMi, Jan 07, 2009 22:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Na toll, dabei find ich die Funktion gar ned so übel... Sie ist jedenfalls näher an "Echtzeit" dran als die Lösung von Toeb. Klar ist die Draw3D schneller, hab ich auch nie bezweifelt, aber wer sein Spiel in 2D großgezogen hat und nicht alles umschreiben will ist damit finde ich besser bedient. (Und jetzt bitte keine Diskussion über den Aufwand des Umschreibens von B2D nach Draw3D, das wurde schon oft genug geklärt und ich weiß dass er gar nicht so groß ist wie ich es hier grad darstelle)
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

hectic

Sieger des IS Talentwettbewerb 2006

BeitragDo, Jan 08, 2009 0:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Probier es selbst. Sobald man Graphics3D macht, sollte man auch mit 3D arbeiten, denn allein schon dieser Befehl macht das echte 2D langsamer.

Code: [AUSKLAPPEN]
Graphics3D 800,600,0,1
;Graphics 800,600,0,1

SetBuffer BackBuffer()

Local Q,Image=LoadImage("e:\bild.jpg")

While Not KeyHit(1)
   For Q=1 To 1000
      DrawImage Image,Rand(20,700),Rand(0,500),0
   Next
   
   Text 0,0,fps:msc=MilliSecs()
   If msc>mts Then mts=msc+1001:fps=frm:frm=0 Else frm=frm+1
   Flip 0
   Cls
Wend
End


Bei mir z.Z. 53 FPS (2D) zu 45 FPS (3D). Daher ist der Geschwindigkeitsvorteil so einer Funktion in allen anderen Bereichen dahin. Bei meiner alten Grafikkarte war die Leistung sogar auf 80% bis 60% runter gegangen. Ich will niemanden von meiner Draw3D überzeugen, hab ja dieses Thema auch nicht in den Raum geworfen. Ich möchte nur darauf hinweisen, dass Graphics3D unter echtem 2D nichts zu suchen hat.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Eingeproggt

BeitragDo, Jan 08, 2009 19:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich wollte auch keinesfalls die Draw3D madig machen Wink
Ich wollte nur eine andere Art einer "Echtzeit"-Rotation vorstellen obwohl ich sie ja eig nicht hab, hab nur mal die Idee in den Raum geworfen. Du hast mit 3D vs 2D recht, bei mir etwa 21 zu 11. Allerdings arbeite ich ständig im Fenstermodus, wo Graphics und Graphics3D exakt gleich sind (auf nur 11FPS bei mir... äh Erklärung hab ich dafür grad keine, bin aber auch grad im Stress, sry)

mfG, Christoph.
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group