Oscylacja wokół środka ekranu - OpenGL.

0

Pozostało mi ostatnie zadanie, z resztą się uporałem.

Mam stworzyć trójkąt równoboczny:

  • ma oscylować wokół środka ekranu
    -jednocześnie obracał się wokół własnego środka z 3 razy mniejszą częstotliwością
    -płynnie zmieniał kolor od zielonego do niebieskiego

Moglibyście w jakiś sposób pomóc, podrzucając potrzebne funkcje, opisując krok po kroku jak wykonać samą oscylację na początku?

2

Zdefiniuj zmienne typu float/double odpowiadające każdemu z podpunktów:

  1. x,y trójkąta, kąt oscylacji wokół środka ekranu
  2. kąt obrotu wokół własnego środka
  3. wartość koloru zielonego, wartość koloru niebieskiego

Domyślam się, ze korzystacie ze starego OpenGL i można wykorzystać funkcji glColor, glTranslate itd.

W pętli aplikacji piszesz:
1.

kat_oscylacji += czas_klatki * szybkosc_oscylacji;
x_trojkata = cos(kat_oscylacji w radianach) * promien_oscylacji;
y_trojkata = sin(kat_oscylacji w radianach) * promien_oscylacji;

glTranslated(x_trojkata, y_trojkata, 0.0);
kat_obrotu_wokol_srodka += (czas_klatki * szybkosc_oscylacji) / 3.0;

glRotated(kat_obrotu_wokol_srodka, 0.0, 0.0, 1.0);
niebieski += czas_klatki * szybkosc_zmiany_koloru;
if (niebieski>=1.0) niebieski = 1.0;
zielony = 1.0 - niebieski;

glColor4d(0.0, zielony, niebieski, 1.0);

Można wprowadzić jakiegoś boola. Po osiągnięciu 1.0 przez niebieski, można zmieniać kolor z powrotem do zielonego.

Dodatkowo powinieneś zabezpieczyć kąty, żeby nie zwiększały się w nieskończoność np. if (kat > 360.0) kat -= 360.0;

Pisane z palca, ale powinno dobrze pokazać jak dojść do oczekiwanego rezultatu.

0
Spine napisał(a):

...

@Edit

Tak to wygląda ostatecznie, nie wiem dlaczego kolor nie zmienia się płynnie, tylko zielony->seledyn->niebieski->seledyn->zielony

int licznik=0;
float a = 255, b = 0;

/* Figura przesuwa się od jednej krawędzi do drugiej w ciągu 10s, obraca się 3 razy dłużej, kolor zmienia się z równą częstotliwością co przesunięcie*/
static void timerCallback(int value)
{
    	
	if (x <= 1 && x>=0)
	{
		
		licznik++;

		if (licznik<100)

		{
			glRotatef(1.21, 1.0f,0.0f, 0.0f);
			glColor3f(0, a, b);
			x += 0.5 / 50;
			a -= 255/85;
			b += 255/85;
			glutPostRedisplay();
			glutTimerFunc(100, timerCallback, value);
			
			
			
			
		}
		if (licznik>=100)
		{
			glRotatef(1.21, 1.0f, 0.0f, 0.0f);
			glColor3f(0, a, b);
			a += 255 / 85;
			b -= 255 / 85;
			x -= 0.5 / 50;
			glutPostRedisplay();
			glutTimerFunc(100, timerCallback, value);

			if (licznik==198) licznik = 0;
		}

		
	}
	
}

Ja samemu doszedłem do takiego czegoś, jutro spróbuje skorzystać z twojego 'cos' i 'sin'.

0

Właściwie po chwili namysłu to sin, cos możesz olać. Możesz skorzystać ze składania przekształceń. Czyli odpowiednio:

glRotated(kat_oscylacji, 0.0, 0.0, 1.0);
glTranslated(promien_oscylacji, 0.0, 0.0);

Ważne, że robisz to na samej górze, przed innymi przekształceniami (rotacją wokół środka trójkąta).

A twój kod jest niestety daleki od koncepcji aplikacji graficznej.
Zrób sobie po ludzku co klatkę na początku glLoadIdentity() i trzymaj wszystkie parametry w zmiennych. Niepotrzebny Ci jest ten licznik, można się spokojnie bez niego obejść. Po wszystkich przekształceniach, wywołaj procedurę rysowania trójkąta.

Co do koloru, to używasz złych wartości. Maksymalna wartość koloru to w Twoim przypadku 1.0f (a nie 255), minimalna to 0.0f. Także musisz przyjąć inną skalę przy inkrementacji i dekrementacji ;)

0
Spine napisał(a):

Co do koloru, to używasz złych wartości. Maksymalna wartość koloru to w Twoim przypadku 1.0f (a nie 255), minimalna to 0.0f. Także musisz przyjąć inną skalę przy inkrementacji i dekrementacji ;)

Ustalmy coś to wszystko to co piszesz, nie jest dla mnie zbytnio zrozumiałe, nie mam pojęcia o jaki sposób Ci chodzi (jak pozbyć się licznika), nie miałem nigdy styczności z Open GL, my sami mamy z tego tylko dwa ćwiki, bez wykładów, i lecimy dalej do programowania obiektowego, gdzie będzie na zaliczenie gra.

Czyli mam ustawić zmienną a=1.0; b=0.0; i zwiększać ją o mniejsze wartości wtedy płynnie będzie przechodziła, od zielonego do niebieskiego.

Co do twojego sposobu to jak masz ochotę to przedstaw chociaż sam szkielet kodu, a ja może wtedy załapię o co Ci chodzi.

To znaczy np. podałeś takie coś:

kat_oscylacji += czas_klatki * szybkosc_oscylacji;

I te czas klatki i szybkość oscylacji to mają być normalne zmienne? I jak mam zrobić żeby bez licznika, w ogóle to wszystko jakoś animowało się klatka po klatce, jakąś funkcję trzeba użyć, najlepiej jakbyś zaprezentował kawałek kodu, to bym wiedział o co chodzi, a tak nie mam pojęcia.

0

Używasz glut. Zobacz więc jak wygląda prawidłowy szablon dla gluta ;)

http://www.cprogramming.com/snippets/source-code/a-code-template-for-opengl-divide-glut

Całe rysowanie sobie zapisz w wyznaczonym miejscu w funkcji draw().

SPOJowiecaa napisał(a):
kat_oscylacji += czas_klatki * szybkosc_oscylacji;

I te czas klatki i szybkość oscylacji to mają być normalne zmienne? I jak mam zrobić żeby bez licznika, w ogóle to wszystko jakoś animowało się klatka po klatce, jakąś funkcję trzeba użyć, najlepiej jakbyś zaprezentował kawałek kodu, to bym wiedział o co chodzi, a tak nie mam pojęcia.

Szybkość oscylacji możesz sobie wpisać z palca, a czas klatki we współczesnych aplikacjach się oblicza pisze, żeby program tak samo działał na 50FPS, jak i na 200FPS. Przy 200 klatkach na sekundę czas klatki jest krótszy. Jak szybkość oscylacji jest równa 20.0 i przemnożysz ją przez czas klatki i o wynik tego działania zwiększysz kąt oscylacji, to w ciągu jednej sekundy kąt oscylacji zwiększy się o 20.0. Jeśli nie chcesz stosować takich obliczeń, to możesz w funkcji draw użyć Sleep(1000/pożądana_ilość_klatek_na_sekundę); tylko, że to jest mniej dokładna metoda, bo nie wiemy ile tak naprawdę trwa klatka (jednak w przypadku tej aplikacji ma to niewielkie znaczenie). Wtedy możesz pominąć czas_klatki w podanym przeze mnie wzorze. Zostanie sama szybkość oscylacji, uzależniona od Sleepa. Najlepiej, żeby pożądana ilość klatek na sekundę nie była większa niż 60, bo przy włączonym vsync i tak aplikacja się ogranicza do tylu klatek i możesz mieć zaskakujące wyniki na różnych konfiguracjach sprzętowo-programowych.

0

<quote="1122627">Używasz glut. Zobacz więc jak wygląda prawidłowy szablon dla gluta ;)

http://www.cprogramming.com/snippets/source-code/a-code-template-for-opengl-divide-glut

Całe rysowanie sobie zapisz w wyznaczonym miejscu w funkcji draw().

SPOJowiecaa napisał(a):
kat_oscylacji += czas_klatki * szybkosc_oscylacji;

Więc tak:

  • szablon tworzył wykładowca
  • dodam sobie te rysowanie do funkcji, nieważne to najmniej istotne

Skupmy się na tym jak mam obliczyć ten czas klatki? Jak już obliczę ten czas klatki, to mam ten kąt_oscylacji wrzucić do cosinusa i sinusa?
A zaś ten fragment:

 
kat_oscylacji += czas_trwania_klatki * szybkosc_oscylacji;

x = (float)sin(kat_oscylacji) * promien_oscylacji;
		y = (float)sin(kat_oscylacji * promien_oscylacji;
		glTranslatef(x, y, 0);

Ma być w pętli for?

Zajrzyj do tego tematu (oczywiście jeśli możesz): http://4programmers.net/Forum/C_i_C++/248986-opengl_-_jak_wygenerowac_animacje_klatka_po_klatce

i napisz dlaczego pomimo dobrego kąta w radianach, trójkąt idzie tylko w górę, a nie oscyluje wokół środka tak jak miało być?

0

Użyłeś 2 razy funkcji sinus. w x ma być cosinus, w y ma być sinus.

Jeśli kąt oscylacji chcesz od razu podawać w radianach (bez potrzeby konwersji), to pamiętaj by go zwiększać o mniejsze wartości niż w przypadku kąta w stopniach.

Czas klatki liczysz w głównej pętli aplikacji (np. gdzieś w draw?). Policzyć różnicę czasu pomiędzy klatkami (bieżąca_klatka - poprzednia_klatka). Szukaj trochę w Internecie.... http://gamedev.stackexchange.com/questions/13008/how-to-get-and-use-delta-time

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