Här kan jag fortsätta med förevisningen av mina katastrofala matematikkunskaper...
/Lupson
Får tacka alla så mycket för hjälpen. Nu fungerar höjdfinnaren perfekt! Inga "hopp" i skarvarna etc. Kanske inte så intressant men lösningen blev enl. följande.
float GTH3(float x, float z, BYTE pHeightMap[]){
int helX, helZ = 0; // Snap-to-grid values
float a, b, c, d, ret, vsum = 0;
Vector3 p1, p2 ,p3, p4;
for(int e = 0;e<x;e+=STEP_SIZE)
helX = e;
for(int f = 0;f<z;f+=STEP_SIZE)
helZ = f;
float start_y = Height(pHeightMap, helX,helZ); // bottom left, "anchorpoint"
float end_y_1 = Height(pHeightMap, helX,helZ + STEP_SIZE); // top left
float end_y_2 = Height(pHeightMap, helX + STEP_SIZE, helZ); // bottom right
float end_y_3 = Height(pHeightMap, helX + STEP_SIZE, helZ + STEP_SIZE); // top right
p1.x = helX;
p1.y = start_y;
p1.z = helZ;
p2.x = helX;
p2.y = end_y_1;
p2.z = helZ+STEP_SIZE;
p3.x = helX+STEP_SIZE;
p3.y = end_y_2;
p3.z = helZ;
p4.x = helX+STEP_SIZE;
p4.y = end_y_3;
p4.z = helZ+STEP_SIZE;
vsum += p1.CalcAngle(p1, p2, x, z); /* Lägger ihop de tre vinklarna */
vsum += p1.CalcAngle(p1, p3, x, z);
vsum += p1.CalcAngle(p2, p3, x, z);
if(vsum > 6.284f || vsum < 6.283f){ /* Ifall vinkelsumman avvike från 2 Pi */
p1.x = p4.x;
p1.y = p4.y;
p1.z = p4.z;
}
a = p1.y*(p2.z-p3.z)+p2.y*(p3.z-p1.z)+p3.y*(p1.z-p2.z);
b = p1.z*(p2.x-p3.x)+p2.z*(p3.x-p1.x)+p3.z*(p1.x-p2.x);
c = p1.x*(p2.y-p3.y)+p2.x*(p3.y-p1.y)+p3.x*(p1.y-p2.y);
d = -p1.x*(p2.y*p3.z-p3.y*p2.z)-p2.x*(p3.y*p1.z-p1.y*p3.z)-p3.x*(p1.y*p2.z-p2.y*p1.z);
ret = -(a*x+c*z+d)/b;
return ret;
}
där CalcAngle som kollar beräknar en godtycklig vinkel i en godtycklig triangel ser ut:
float Vector3::CalcAngle(Vector3 vp1, Vector3 vp2, float x, float z){
float a, b, c, cosangle;
a = (float) sqrt(((vp1.x-vp2.x) * (vp1.x-vp2.x)) + ((vp1.z-vp2.z) * (vp1.z-vp2.z)));
b = (float) sqrt(((vp1.x - x) * (vp1.x - x)) + ((vp1.z - z) * (vp1.z - z)));
c = (float) sqrt(((vp2.x - x) * (vp2.x - x)) + ((vp2.z - z) * (vp2.z - z)));
cosangle = -( ((a*a) - (b*b) - (c*c))/(2*b*c));
return acos(cosangle);
}
Om någon ser några felaktigheter eller möjliga förbättringar får ni gärna meddela det. :)
Nästa post == nästa problem!
Nu till nästa tankenöt - att få mina stridsvagnar att ligga jämnt och fint mot terrängen!
Dels vill jag att dom ska ligga jämnt mot den triangel den ligger mot, men jag vill också att ifall objektet ligger över flera trianglar skall positioneras så att det ser verkligt ut, dvs att stridsvagnen även vid backkrön renderas korrekt, dvs att de främre banden är i luften när nästan halva vagnen är över krönet. Vi utgår från att tyngdpunkten ligger mitt i fordonet. Knivigt.
Min tanke är att ta stridsvagnens fyra yttre bandhörn och plocka höjden för dessa fyra punkter. Sedan tar jag dessa 4 punkter (har xyz) och bildar ett plan av dem. Nu är problemet hur jag matematiskt kommer från dessa fyra punkter till de transformeringar som skall göras i OpenGL. OpenGL är så snällt att man inte behöver beräkna matrisomvandlingar själv (ifall man inte vill) utan man använder en funktion:
glRotatef( [grader att rotera] ,0,1,0);
Där ettan är vilken axel man roterar runt. Vill jag rotera kring x-axeln istället flyttar jag ettan en parameter inåt.
Någon som har några bra tips på hur jag kan gå tillväga här? Funderar på om man kanske skulle försöka med att definiera "planet" i en matris för att sedan ta reda på skillnaden mot "världen" (som inte är roterad alls) - sedan tar man och motroterar världen lika mycket som skiljer.
(I opengl renderar man alltid utifrån ett oroterat origo. Vill man att det ska se ut som att ett objekt roteras eller flyttas, då flyttar man världen och roterar den istället för tvärtom...) Men matrisberäkningar fattar jag lite för lite av. Känns förvisso lite B att knappt försöka själv men någon kanske tycker det är lite roligt med sånt här.. :)
Tacksam på förhand!
/Lupson
Hmmm... intressant!
*Funderar*... se om jag kommer på nån bra algoritm...
Griffin
Vet inte riktigt hur man ska göra.. Men borde väl bli nåt åt de här hållet:
1. Räkna ut planet/normalen som objektet står på
2. Räkna ut vinklar mellan objektets "upp vektor" och normal vektorn (borde väl bli två, roll & pitch)
3. Rotera objektet
De var iaf lätt att skriva. :)
Är det verkligen så enkelt?
Jag var inne på att bedöma om fordonet stod på en konvex eller konkav yta och räkna vidare på det, men har man osis kan ju fordonet stå på massor med polygoner och då blir det lite mer att ta hänsyn till....
Om man får anta att fordonet kan stå på t.ex. max en konkav/konvex skarv så blir det lite enklare... tror jag. Då handlar det om att bedöma om ytan det står på är konvex eller konkav. Det senare ger ju att man bara plockar fordonets markpunkter (hjul) där de intersectar markpolygonerna och får fram planet fordonet står på. I det första fallet handar det om att ta fram var fordonets centrumpunkt (för gravitation) befinner sig och projicera ned den på markpolygonen. Träffad triangel ger lutningen på fordonet.
Men detta är ju enkla fall. Det blir värre om marken består av massor med "kullar" och "dalar" (dvs flera konkava/konvexa skarvar) under fordonet. Jag håller på att skissa på en mer generell algoritm på det. Får se om jag kommer på nåt innan nån annan kläcker en smart lösning. Jag tenderar till att krångla till saker så oddsen är väl stor :)
Griff
Jovisst.. Ju mer realistiskt man vill ha det desto krångligare.
Med metoden som jag beskrev så står man hela tiden på en jämn yta.. eftersom man räknar ut ett plan från 3-4 punkter, fordonets/objektets hörn (projjicerade rakt ner mot marken). Man kommer ju att missa "gupp/gropar" som är mindre än fordonet.. Och fordonet kommer hela tiden vara "slickat" jäms med marken (eller det uträknade planet). Och de kommer bara att fungera på heightmaps. Har man grottor eller dylikt så blir de lite knepigare.
Håller på med att gå igenom den här tutorialen:
http://www.d6.com/users/checker/dynamics.htm
Den kan kanske vara till hjälp, men rätt mycke krånglig matematik. Tycker jag iaf. :)
Tack för era svar. Jag tror att jag ska börja med att strunta i den konvexa (? de "svåra" vinklarna) problematiken och försöka med normalmetoden baserat på ett plan som utgår från fyra "hjulpunkter". Jag tror jag vet hur man implementerar den metoden.
Kvällen fick dessvärre ägnas åt att åtgärda en generalbugg i 3ds-laddaren så det blev inget matematikpulande ikväll. Men på den positiva sidan så fick jag texturerat några modeller (och texturerna ritade på rätt plats!) så några nya screenshots finns att betitta på: http://w3.adb.gu.se/~s99luppe/openGL/screenshots
Är extra nöjd med heli_gfxfel.jpg - ganska snygg Hind och grafikfel i samma bild!
/Lupson
Se upp Flashpoint här komemr en konkurrent!! ;) :)
Lägesrapport ang. problemet som till slut löste sig någorlunda
Plockade ut 4 hörnpunkter, definierar en normal mha 3 av dem. Den funktion jag använder för att beräkna normalen till en yta tar bara 3 Vektorer men jag skulle tro att det inte spelar någon större roll i sammanhanget.
Sedan definierar jag en uppåtnormal (0,1,0). Sedan skickar jag in planets normal tillsammans med uppåtnormalen i en funktion som räknar fram vinkelskillnaden i x-led mellan normalerna, sedan gör jag samma sak för z-ledet.
Därefter kom problematiken att funktionen som returnerar vinkelskillnaden alltid returnerar absolutvärdet vilket inte fungerar i praktiken eftersom man måste ge openGL negativa vinklar ifall man vill ha en negativ rotation. Jag ordnade dock till en liten fusklösning som kanske är den enda metoden. Den tar iaf och kollar ifall en av de främre x-koordinaterna ligger ovan eller nedan motsvarande bakre x-koordinat. Ifall vi i är "i nedförsbacke" så byter vi helt enkelt tecken på det inskickade värdet.
Kod: (Ger en enkel bild av hur koordinatsystemstranformateringarna i OpenGL fungerar f.ö., Intresseklubben antecknar kanske... :) )
Vector3 v1, v2, v3, v4, object, normal, normal2, stdnormal, rot; //Vektorer
object.x = obj[n]->getXpos();
object.y = obj[n]->getYpos();
object.z = obj[n]->getZpos();
/* Hämtar de fyra punkterna */
v1.x = object.x+(float)sin((obj[n]->getDirection()+60)*piover180)*3.0f;
v1.z = object.z+(float)cos((obj[n]->getDirection()+60)*piover180)*3.0f;
v1.y = GTH3(v1.x, v1.z, g_HeightMap);
v2.x = object.x+(float)sin((obj[n]->getDirection()-60)*piover180)*3.0f;
v2.z = object.z+(float)cos((obj[n]->getDirection()-60)*piover180)*3.0f;
v2.y = GTH3(v2.x, v2.z, g_HeightMap);
v3.x = object.x-(float)sin((obj[n]->getDirection()+60)*piover180)*4.0f;
v3.z = object.z-(float)cos((obj[n]->getDirection()+60)*piover180)*4.0f;
v3.y = GTH3(v3.x, v3.z, g_HeightMap);
v4.x = object.x-(float)sin((obj[n]->getDirection()-60)*piover180)*4.0f;
v4.z = object.z-(float)cos((obj[n]->getDirection()-60)*piover180)*4.0f;
v4.y = GTH3(v4.x, v4.z, g_HeightMap);
normal = CalcFaceNormal(v1,v2,v3); // Beräknar normalen till triangeln(v1,v2,v3)
stdnormal.x = 0.0f; // Definierar standardnormal.
stdnormal.y = -1.0f; // Vet inte varför den måste vara negativ, blir fel annars
stdnormal.z = 0.0f;
float a = v1.CalcAngle2D(normal, stdnormal); // Beräkna z-vinkeln
float b = v1.CalcAngle2D_2(normal, stdnormal); // Beräkna x-vinkeln
// Sätter in värderna i objektets attribut, piover180 är koefficient, radianer->grader
if(normal.z<0) obj[n]->setPitch(a/piover180); // Positiv vinkel
if(normal.z>0) obj[n]->setPitch(-(a/piover180)); // Negativ vinkel...
if(normal.x>0) obj[n]->setYaw(b/piover180);
if(normal.x<0) obj[n]->setYaw(-(b/piover180));
glPushMatrix(); // Lagrar nuvarande koordinatsystem i stacken
//Förflyttar origo till objektets medelpunkt
gllTranslatef(obj[n]->getXpos(), obj[n]->getYpos(), obj[n]->getZpos());
glRotatef(obj[n]->getPitch(), 1.0f, 0.0f, 0.0f); // Roterar i x-led
glRotatef(obj[n]->getYaw(), 0.0f, 0.0f, 1.0f); // Roterar i z-led
glRotatef(obj[n]->getDirection(), 0.0f, 1.0f, 0.0f); // Roterar i y-led
glCallList(obj[n]->getModel()); //
glPopMatrix(); // Hämtar senaste koordinatsystem från stacken
}
Så - en liten snabblektion i openGL! Formeln som används i CalcAngle2D är:
cos A = -( ((a*a) - (b*b) - (c*c))
______________________
(2*b*c)
Nu vet jag inte riktigt vad jag ska göra som nästa steg, men antagligen gör jag om objektsystemet så man har ett huvudobjekt som man hänger på komponenter på, ex.
Helikopter -> Rotor
|
-> Automatkanon
|
-> Missiler
eller
Stridvagn -> Torn -> Kanon
Har någon skojiga förslag på objektstrukturer eller ideér om vad nästa steg kan vara så är jag tacksam för all möjlig input. Just nu tror jag helst att jag slipper matematiken ett tag!
Mvh Lupson