D3D9 | Elipse/Oval zeichnen



  • Guten Tag liebe Community,
    ich bin am verzweifeln ,ich denke seid Tagen darüber nach wie ich ein Oval/Elipse zeichnen könnte,aber mir fällt nichts ein..Ich kenne auch in Mathe keine Formel für eine Elipse ,vieleicht hab ich sie auch nur vergessen...
    Über ein klein wenig hilfe würde ich mich sehr freuen.

    Spielt zwar eigentlich keine große Rolle ,aber ich Hook DirectX9 ,und zeichne in der Endscene.



  • Vermutlich nicht effizient, aber die Punkte auf einer Ellipse mit Parametern (a,b) kannst du über Winkelfunktionen zeichnen:

    for phi in 0 to 2pi:
        x = a*cos(phi)
        y = b*sin(phi)
        phi += delPhi
    


  • Wenn du eine "exakte" Ellipse haben willst, kannst du die auch in einem Pixel-Shader zeichnen.

    Zeichne nen Quad, Texturkoordinaten von 0|0 bis 1|1, und dann einfach " if (u*u + v*v <= 1) innen else aussen; ".
    Wenn du den Quad skalierst dann skaliert der Kreis entsprechend mit. D.h. wenn der Quad kein Quadrat ist sondern flachgedrückt, dann bekommst du entsprechend nen flachgedrückten Kreis - aka. Ellipse.

    Wie man dabei noch sauberes Anti-Aliasing bekommt ohne viel Rechenzeit zu verbraten kann ich dir auf die Schnelle aber nicht sagen.



  • Habe auf Wikipedia etwas gefunden mit dem Bresenham Algorithmus.
    http://de.wikipedia.org/wiki/Bresenham-Algorithmus

    Wenn ich das richtig verstehe,erstellt es eine art Koordinatensystem ,und berechnet jeden Punkt einzeln ,allerdings kann ich damit nur die äußere Elipse zeichnen ,und es nicht ausfüllen ...Scheinbar verstehe ich das nicht ganz...Kann mir einer das weiter erklären?

    Wie der Code aktuell dafür aussieht:

    void ellipse(LPDIRECT3DDEVICE9 pDevice,int xm, int ym, int a, int b)
    {
       int dx = 0, dy = b; 
       long a2 = a*a, b2 = b*b;
       long err = b2-(2*b-1)*a2, e2; 
    
       do {
    
    		B_Menu->DrawRect(pDevice,xm+dx,ym+dy,1,1,BLACK);
    		B_Menu->DrawRect(pDevice,xm-dx,ym+dy,1,1,BLACK);
    		B_Menu->DrawRect(pDevice,xm-dx,ym-dy,1,1,BLACK);
    		B_Menu->DrawRect(pDevice,xm+dx,ym-dy,1,1,BLACK);
    
           e2 = 2*err;
           if (e2 <  (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; }
           if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; }
       } while (dy >= 0);
    
       while (dx++ < a) {
           B_Menu->DrawRect(pDevice,xm+dx,ym,1,1,BLACK);
    		B_Menu->DrawRect(pDevice,xm-dx,ym,1,1,BLACK);
    
       }
    }
    

    Meine DrawRect function ,zeichnet in diesem Fall einfach nur einen Punkt ,dafür nutze ich D3D9 Clear.

    Hier nochmal die Funktion:

    void CMenu::DrawRect(LPDIRECT3DDEVICE9 pDevice,int x,int y,int w,int h,D3DCOLOR Color)
    {
    	D3DRECT Cords = { x, y, x + w, y + h };
    	pDevice->Clear(1, &Cords, D3DCLEAR_TARGET, Color, 0,  0); 
    }
    

    Ziemlich Simple halt 😃

    Hat einer ne Idee wie ich die Ellipse ausmalen könnte ,oder ist das mit dem Algorithmus nicht möglich? 😕

    //EDIT Screenshot:
    http://i40.tinypic.com/2i7n0is.jpg

    Mein Endziel ist eigentlich das Menu oben,halt umzubauen in ovale 😃
    In der mitte ist dünn das Oval gezeichnet ,wollte es jetzt nicht extra für nen Screenshot dicker zeichnen...



  • Bresenham ist, was du verwenden würdest, wenn du Linien, Kreise etc. mit der CPU malen wollen würdest. Wenn du mit D3D arbeitest, dann willst du aber die GPU verwenden. Und dort willst du nicht mit Bresenham anfangen. Dort willst du deine Ellipse entweder z.B. als Linienzug approximieren, einfach eine Textur auf ein Quad mappen, oder das machen, was hustbaer gesagt hat...



  • Oha.
    Er will wohl nur die Outline der Ellipse malen.
    Wie/ob man das mit nem Pixel-Shader hinbekommt weiss ich nücht.

    Also nicht wenn die genau hübsch 1 Pixel dick sein soll - wie halt der Output vom Bresenham.



  • hustbaer schrieb:

    Oha.
    Er will wohl nur die Outline der Ellipse malen.
    Wie/ob man das mit nem Pixel-Shader hinbekommt weiss ich nücht.

    Also nicht wenn die genau hübsch 1 Pixel dick sein soll - wie halt der Output vom Bresenham.

    Naja, genau wie du sagst, idealerweise wird man allerdings nicht einfach ein Quad malen, sondern einen Polygonstreifen basteln, der den Rand der Ellipse einigermaßen eng umschließt. Im Pixelshader dann einfach die Ellipsengleichung auswerten und pixel discarden, deren Abstand entsprechend zu groß ist...

    Oder eben als Linienzug approximieren...



  • Habe den wohl simpelsten Weg jetzt genommen ,fragwürdig ob es auch der beste ist,aber naja ,ich mach's über ein Sprite ^^

    LPDIRECT3DTEXTURE9 pTex = NULL;
    	LPD3DXSPRITE cDraw = NULL;
    bool Do_Ellipse(LPDIRECT3DDEVICE9 pDevice,float x, float y)
    {
    
    	D3DXVECTOR3 pos;
    	pos.x = x;
    	pos.y = y;
    	pos.z = 0.0f;
    	if(cDraw == NULL)D3DXCreateSprite(pDevice, &cDraw); 
    	//if(D3DXCreateTextureFromFileInMemory(pDevice,&txt_ELLIPSE,sizeof(txt_ELLIPSE),pTex)==D3D_OK)
    	if(D3DXCreateTextureFromFile(pDevice,L"D:/test.png",&pTex)==D3D_OK)
    	{
    
        cDraw->Begin(D3DXSPRITE_ALPHABLEND);
    	cDraw->Draw(pTex,NULL,NULL,&pos,0xFFFFFFFF);
    	cDraw->End();
    	return true;
    	}
    	return false;
    }
    

    Nutze aus testzwecken noch per pfad,danach wird aus einem Byte Array geladen. Fals jemanden der Code noch interessieren sollte :'D

    Danke euch für die Hilfe.


Log in to reply