Rotacja bitmapy i artefakty

0

Witam,
Piszę sobie pewną aplikację graficzną w której chciałbym mieć możliwość obracania bitmapy.
Tutaj jest frgment kodu odpowiadającego za obrót:

void DrawSprite(Texture2D* inTexture2D, const Vector2 inPosition, float inRadianAngle)
{
	float sina = (sin(inRadianAngle));
	float cosa = (cos(inRadianAngle));

	int32 px;
	int32 py;
	
	float xp ;
	float yp ;
	int32 x = 0;	
	int32 y = 0;
	
	uint32 cw = (inTexture2D->Width/2 + inPosition.X);
	uint32 ch = (inTexture2D->Height/2 + inPosition.Y);

           const Color* ptr = inTexture2D->GetData();

	for( x = 0; x <(inTexture2D->Width); ++x)
	{
		xp = ((inPosition.X + x) - cw );	
		
		for( y = 0; y < (inTexture2D->Height); ++y)
		{									
			yp = ((inPosition.Y + y) - ch );

			px = round((xp * cosa) - (yp * sina) + cw);
			py = round((yp * cosa) + (xp * sina) + ch);		

			PutPixel(px, py, (ptr[y*inTexture2D->Width+x]));			
		}
	}
}

Reszta ważnych funkcji:

int round(float inFloat)
{
	return (int) (inFloat + 0.5f);
}

void PutPixel(uint32 inX, uint32 inY, const Color &inColor)
{	
	GetBackBuffer()->SetData( inColor, ( inY *  m_Width) + inX );
}

Powyższy kod działa prawie poprawnie tzn. obraca bitmapę, ale w czasie obrotu pojawiają się artefakty (przebicia z tła) co można zobaczyć na poniższym obrazku:
user image

Czy ktoś ma jakiś pomysł jak można się tych artefaktów pozbyć?
By uprzedzić wasze propozycje zmieniałem już typy zmiennych na float oraz double co dawało taki sam rezultat jak na powyższym obrazku.

0

U mnie zadziałało:

PutPixel(px, py, (ptr[y*inTexture2D->Width+x]));
PutPixel(px+1, py+1, (ptr[y*inTexture2D->Width+x]));  

Chodzi o to, aby narysować za jednym razem oba piksele, tyle, że jeden przesunięty o 1 px.

0

Jak chcesz bez tych dziur, to rób "odwrotnie". A mianowicie dla każdego punktu wynikowego obrazu obliczaj punkt źródłówy i o ile mieści się w zakresie, kopiuj jego zawartość.

0
Patryk27 napisał(a)

U mnie zadziałało:

PutPixel(px, py, (ptr[y*inTexture2D->Width+x]));
PutPixel(px+1, py+1, (ptr[y*inTexture2D->Width+x]));  

Chodzi o to, aby narysować za jednym razem oba piksele, tyle, że jeden przesunięty o 1 px.

W teorii zadziała, ale w praktyce powoduje to rozmycie bitmapy, a dla niektórych kątów problem dalej się pojawia.

nav napisał(a)

Jak chcesz bez tych dziur, to rób "odwrotnie". A mianowicie dla każdego punktu wynikowego obrazu obliczaj punkt źródłówy i o ile mieści się w zakresie, kopiuj jego zawartość.

Problem w tym, że dziury są właśnie w punktach wynikowych. Niektóre punkty wynikowe są przesunięte na jednej z osi o ułamkową wartość np: 0.07 co powoduje, że przy całkowitoliczbowych współrzędnych piksela jesteśmy w następnym pikselu przez co pojawiają się dziury. Problem w tym, że zwiększenie dokładności obliczeń na double nie pomaga a problem pozostaje.

0

Chyba nie do końca zrozumiałeś. Zamiast iść pętlą po x/y obrazu źródłowego, zrób to dla obrazu wynikowego. Dla każdego punktu robisz transformację odwrotną, wyliczając współrzędne obrazu oryginalnego. W ten sposób NIGDY nie zostanie dziura, bo masz kolor dla każdego pikselu obrazu wynikowego. Co najwyżej kilka punktów obrazu wynikowego zostanie odwzorowane na obraz źródłowy.
Kiedyś robiłem obracanie bitmapy w asm i ten sposób działał znakomicie. (Oczywiście bez żadnego uśredniania itd, co może dać dokładniejszy, ale rozmyty obraz).

0
nav napisał(a)

Chyba nie do końca zrozumiałeś. Zamiast iść pętlą po x/y obrazu źródłowego, zrób to dla obrazu wynikowego. Dla każdego punktu robisz transformację odwrotną, wyliczając współrzędne obrazu oryginalnego. W ten sposób NIGDY nie zostanie dziura, bo masz kolor dla każdego pikselu obrazu wynikowego. Co najwyżej kilka punktów obrazu wynikowego zostanie odwzorowane na obraz źródłowy.
Kiedyś robiłem obracanie bitmapy w asm i ten sposób działał znakomicie. (Oczywiście bez żadnego uśredniania itd, co może dać dokładniejszy, ale rozmyty obraz).

Sęk w tym, że u mnie obraz docelowy to backbuffer z obrazem całej klatki (piszę renderera). A po drugie ten sposób nie zadziała jeżeli nie będę miał obrazu źródłowego tylko będę chciał obracać prostokąt wypełniony jednolitym kolorem.

0

szukasz dziury w całym.

  1. Liczysz jak obraca się prostokąt by liczyć piksele tylko tam gdzie warto (dla optymalizacji).
  2. potem iterujesz po współrzędnych docelowych w wyliczonym zakresie
  3. odszukujesz piksel do narysowania na bitmapie źródłowej (możesz sprawdzać dla pewności czy piksel trafia do wnętrza bitmapy).
    Gdzie ty tu widzisz jakiś problem?

Ja bym zrobił to na macierzy odwrotnej wtedy wiele pozornie różnych rzeczy załatwisz hurtem (nie tylko obroty).

1 użytkowników online, w tym zalogowanych: 0, gości: 1