Permalänk
Medlem

Rotera 3d-kub i C++

Jag experimenterar lite i C++ och har gjort en kub som jag vill rotera med hjälp utav piltangenterna.
Jag använder mig inte utav något 3d-bibliotek utan har bara 8 punkter som jag ritar ut med hjälp av ett 2d-bibliotek (allegro).
Det jag inte lyckas få att fungera är att rotera kuben runt två axlar samtidigt, jag kan t.ex. rotera den runt X-axeln utan problem, men försöker jag samtidigt göra en rotation runt Y-axeln så ger det en konflikt som gör att kuben förlorar sin form och allt blir fel.

Problemet ligger i denna koden (x, y och z är definierade som 0,1,2 för lättare läslighet)

for(int i = 0; i<8; i++) { cube[i][x] = (sin(cubeA[y]) * cube_orig[i][z])+(cos(cubeA[y]) * cube_orig[i][x]); cube[i][y] = (cos(cubeA[x]) * cube_orig[i][y])-(sin(cubeA[x]) * cube_orig[i][z]); cube[i][z] = (-sin(cubeA[x]) * cube_orig[i][x]) + ((sin(cubeA[x])* cos(cubeA[y])) * cube_orig[i][y]) + ((cos(cubeA[x]) * cos(cubeA[y])) * cube_orig[i][z]); }

X- och Y-variablerna tror jag ändras rätt, men Z-variabeln ändras olika beroende på om man vill rotera runt X- elelr Y-axeln.
T.ex. om jag bara vill rotera runt X-axeln använder jag denna koden:

cube[i][y] = (cos(cubeA[x]) * cube_orig[i][y])-(sin(cubeA[x]) * cube_orig[i][z]); cube[i][z] = (sin(cubeA[x]) * cube_orig[i][y])+(cos(cubeA[x]) * cube_orig[i][z]);

och runt Y-axeln denna koden:

cube[i][x] = (sin(cubeA[y]) * cube_orig[i][z])+(cos(cubeA[y]) * cube_orig[i][x]); cube[i][z] = -(sin(cubeA[y]) * cube_orig[i][x])+(cos(cubeA[y]) * cube_orig[i][z]);

Alltså vill de båda ändra Z-axeln olika, och jag lyckas inte lista ut hur jag ska kombinera de två för att det ska bli rätt.
Har googlat runt en hel del utan att hitta nåt som hjälpt. Tänkte att nån här kanske sysslat med sånt här tidigare och vet hur man ska göra.

Bifogar en länk till programfilen ifall ni vill se hur koden fungerar just nu (jag använder det översta kodexemplet i den)
Raderad eftersom jag glömde inkludera en fil i rar-arkivet
Den gröna punkten är kubens mittpunkt och AX/AY är kubens rotation runt X/Y-axlarna i radianform.
Använd piltangenterna för att se hur rotationen funkar just nu.

Permalänk
Medlem

nu har jag inte testat din kod, men vanligen när man roterar något så gör man det från centerpunkten, ev flyttar så den kommer till origo, gör du det?
du kan testa att rotera en axel i taget (i tre steg), först x, sedan y och z, ev ordningen baklänges.

det går ju att rotera punkterna som du gör, men har man en modell med många punkter så blir det mycket att flytta...

Permalänk

Om du postar all din kod så blir det mycket mycket enklare att hjälpa dig. Gärna med projektfiler så att det går att kompilera direkt också.

Permalänk
Medlem
Skrivet av Dalton Sleeper:

nu har jag inte testat din kod, men vanligen när man roterar något så gör man det från centerpunkten, ev flyttar så den kommer till origo, gör du det?
du kan testa att rotera en axel i taget (i tre steg), först x, sedan y och z, ev ordningen baklänges.

det går ju att rotera punkterna som du gör, men har man en modell med många punkter så blir det mycket att flytta...

Såvitt jag vet snurrar allt kring origo, eftersom när jag snurrar i bara en axel så fungerar det rätt, det är bara när jag vill göra flera rotationer samtidigt som det blir fel.
Jag har försökt snurra i flera olika steg men det har inte blivit rätt de gångerna jag försökt.

Skrivet av VirtualIntent:

Om du postar all din kod så blir det mycket mycket enklare att hjälpa dig. Gärna med projektfiler så att det går att kompilera direkt också.

Koden var väldigt lång och ostädad så jag tänkte att det skulle bli jobbigt att läsa. Men här är en pastebin iaf.
http://pastebin.com/KED75TUF
(Det är dev-cpp med allegro, inget visual studio-mojs)

Permalänk
Medlem

Använd matriser and matris multiplikation. Det finns inbyggt i Allegro, http://www.allegro.cc/manual/4/api/3d-math-routines/ (Jag har inte hunnit prova 5:an än, men det borde finnas någon motsvarighet där också)

Men för att svara på din fråga, ditt problem heter "concatenation of transformations", och om jag kommer ihåg rätt så ska matematiken för rotationen istället vara:

a = rotation runt z-axel
g = rotation runt y axeln
b = runt x-axeln
x', y', z' = ny position
x, y, z = punktens position

x' = x*[cos(a) * cos(g)] +
x*[cos(a) * sin(g) * sin(b) - sin(a) * cos(b)] +
z*[cos(a) * sin(g) * sin(b) - sin(a) * cos(b)]

y' = x*[sin(a) * cos(g)] +
y*[sin(a) * sin(g) * sin(b) - cos(a) * cos(b)] +
z*[sin(a) * sin(g) * cos(b) - cos(a) * sin(b)]

z' = -x*(sin(a)) + z*[cos(g) * sin(b)]

Den roterar kring origo, men det är ju bara att köra translation om du vill rotera den kring en annan punkt. Tänk dock på att inte ändra x eller y förrän du har räknat klart.

Jag skulle dock rekommendera dig varmt att använda matriser och matrismultiplikation för detta. Allt blir så mycket enklare då, Speciellt om du ska lägga på perspektiv.

EDIT:
PS. Kör med NetBeans om du inte tycker om Visual Studio, speciellt om man inte sitter på ett winskit system.
_När_ du implementerar matriserna, så ta en titt på hur OpenGL har löst med med stackar, det är väldigt praktiskt och inte alls svårt att implementera själv.
Säg bara till om du behöver mer hjälp.

Visa signatur

citera!

Permalänk
Medlem

Tack så jättemycket, har inte gjort någon 3d-programmering innan så förstod mig inte på matrismultiplikationer och sådant. Ska kolla upp netbeans och matriser lite noggrannare

Permalänk

Vad skulle du föredra,

1. en kort enkel förklaring som bara säger vad du ska ändra för att ditt exempel ska fungera
eller
2. en längre förklaring som förklarar hur saker hänger ihop på en djupare nivå, men som kräver mera av dig i form av att lära dig saker?

Jag antar att det beror på hur mycket du vill lära dig det här och hur mycket tid du är beredd att lägga på det? Ifall du bara vill göra en snabb grej så kanske det mest är jobbigt att lära dig en massa nya saker.

Vad har du läst för matte? Vet du någonting om matriser och vektorer? Annars skulle du nästan behöva börja med en enkel genomgång av hur man räknar med dem.

Permalänk
Medlem

Sådant leder fort till matematik på högskolenivå, dvs algebra, dock om man kör med färdig matris samt vektorklass kanske man kan klara sig undan mycket, iaf till enklare program.

Du kan definiera matriser själv (står ofta i grafikböcker) som utför vissa visuella effekter eller transformationer (för kamera eller objekt), de är 4x4 matriser, dvs 16 element. Gör man detta rätt kan man ladda in matriserna direkt i opengl väldigt enkelt. När du flyttar objekt så flyttar du i princip inte alla punkter som du nu gör, du skapar en translateringsmatris (med x, y, z parametrar) som du laddar in i opengl som i princip flyttar koordinatsystemet. Det finns också inbyggda funktioner för att manipulera opengl's laddade matriser om man vill det, gltranslate och glrotate osv, kan vara att föredra som nybörjare. Annars kanske vore något om du kunde hitta en matris samt vektorklass som är kompatibla med ogl på nätet, skriva dessa själv är riktig huvudvärk tyvärr, har själv gjort det till mitt framework.

Permalänk
Medlem

Jag kom fram till en lösning efter lite funderande.
Såhär såg den allra första koden ut:

cube[i][x] = (sin(cubeA[y]) * cube_orig[i][z])+(cos(cubeA[y]) * cube_orig[i][x]); cube[i][z] = -(sin(cubeA[y]) * cube_orig[i][x])+(cos(cubeA[y]) * cube_orig[i][z]); cube[i][y] = (cos(cubeA[x]) * cube_orig[i][y])-(sin(cubeA[x]) * cube_orig[i][z]); cube[i][z] = (sin(cubeA[x]) * cube_orig[i][y])+(cos(cubeA[x]) * cube_orig[i][z]);

Som ni ser skriver den sista raden över ändringen som gjordes på rad 2, eftersom båda vill ändra Z-variabeln.
Jag försökte kombinera de två Z-raderna utan något vidare resultat, men efter massor av funderande så gjorde jag detta:

cube[i][x] = (sin(cubeA[y]) * cube_orig[i][z])+(cos(cubeA[y]) * cube_orig[i][x]); cube[i][z] = -(sin(cubeA[y]) * cube_orig[i][x])+(cos(cubeA[y]) * cube_orig[i][z]); cube[i][y] = (cos(cubeA[x]) * cube_orig[i][y])-(sin(cubeA[x]) * cube[i][z]); cube[i][z] = (sin(cubeA[x]) * cube_orig[i][y])+(cos(cubeA[x]) * cube[i][z]);

Så fungerade det precis som jag vill

Och för er som frågade så är detta inget seriöst 3D-projekt, utan bara ett experiment för att försöka förstå hur det fungerar lite bättre.