Rotacja bitmapy i artefakty

Rotacja bitmapy i artefakty
Emperor15
  • Rejestracja:prawie 20 lat
  • Ostatnio:prawie 14 lat
  • Postów:7
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:

Kopiuj
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:

Kopiuj
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.

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

U mnie zadziałało:

Kopiuj
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.


nav
  • Rejestracja:ponad 21 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
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ść.


utf-8 rlz! ٩(ಥ_ಥ)۶
Emperor15
  • Rejestracja:prawie 20 lat
  • Ostatnio:prawie 14 lat
  • Postów:7
0
Patryk27 napisał(a)

U mnie zadziałało:

Kopiuj
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.

nav
  • Rejestracja:ponad 21 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
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).


utf-8 rlz! ٩(ಥ_ಥ)۶
Emperor15
  • Rejestracja:prawie 20 lat
  • Ostatnio:prawie 14 lat
  • Postów:7
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.

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:17 minut
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).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.