• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

GarrickW

Members
  • Content count

    44
  • Joined

  • Last visited

Community Reputation

115 Neutral

About GarrickW

  • Rank
    Member
  1. [quote name='szecs' timestamp='1338358426' post='4944568']Are you try to avoid storing or recalculating all the triangle normals?[/quote] I'm not 100% sure about that, to be honest. The reason I was going for this approach is that the models can get quite large and complex, and I figured temporarily storing triangles as pointers to vertices, rather than as sets of new vertices, would reduce the amount of data being moved around in each model, as well as facilitate sharing of vertex normals between triangles. In the end I do store triangles as a series of floats, though, since the vertices are generated and discarded as needed, and since uploading floats to the GPU as VBOs seemed more straightforward. Honestly, though, I'm new at programing meshes like this and I'm not sure what the best approaches are. [quote name='szecs' timestamp='1338358426' post='4944568']Another thing: you should weigh your triangle normals in the vertex normal calculation. Not all triangle normals affect the vertex normal in the same amount. Consider a cube. If you want to smooth shade the cube (I know it's stupid) you know that the vertex normals should point in a 1,1,1 direction for example (I didn't normalize it, but you get the idea). A vertex in a cube is shared by 3 sides, but that means four triangles in some cases. That means a side is represented by 2 triangles at some corners. Without weighing, it will distort the desired result because you add that normal twice.[/quote] Oh gods, that does makes sense. That's surely at least a part of the problem. Hm... Could you elaborate a little on your angle-weighting? Do you mean the angle of the line defined by two vertices (or vertex locations) shared by two different triangles? [quote name='szecs' timestamp='1338358426' post='4944568']That said, your pyramid will look distorted anyway, because you smooth sharp edges too. Take a loot at a smooth shaded triangle in any 3d modelling software. It will look something like that.[/quote] Yes, I was expecting it to look weird since, as you said, it's got sharp edges. However, I was rather expecting the weirdness to be uniform along the edges of the pyramid (like the edges were highlighted or something), rather than jagged. Presumably, if the weirdness was uniform, it could be reduced by having a smoother model. In some of the more complex models I have, there are sharp edges (90° or less) that I'd rather not have smoothed, but duller edges that I would like to smooth out. I read a little about smoothing groups on Wikipedia just now, but I'd need some kind of algorithm that can efficiently calculate and modify smoothing groups on the fly, because my meshes are supposed to be not only arbitrary but also, to an extent, deformable. Ideally, an algorithm that identifies whether a neighboring triangle is at too sharp an angle to be included in the normal modification process, or something similar. I suppose I could just compare triangle normals and, if they are too different, ignore the neighboring triangle in the calculations...
  2. I'm looking to create arbitrarily-shaped meshes and calculate the proper vertex normals for each vertex. As I understand it (and I may be wrong), if you want smooth shading, you need to ensure that vertices have a normal that represents the combined normals of all the triangles that vertex is involved in. For instance, if you have a straight edge along your model where the surfaces extend down along Y starting at 0, right along X starting at 0 and infinitely into and out of the Z axis, then your vertices need to have normals that point exactly in the +Y, -X direction. I'm sure that's not the best description, but you get my gist. Otherwise, if the vertices in each triangle merely represent that triangle's normal, you'll get entirely flat shading. (EDIT: Just to be clear, I mean that given a triangle A, the vertices A1, A2 and A3 shouldn't all have identical normals - rather, their normals should be influenced by the normals of other triangles as well, such that, for example, normals A2 and A3 should have a normal also influenced by the normal of the separate triangle A2-A3-A4.) So, first question - is that indeed the way to achieve smoother-looking shading? If it is, I've got something of a problem, as the image below (which should be a pyramid) no doubt makes clear. The triangles themselves are all placed accurately, but I'm not calculating my normals properly. I should mention that the way I build my triangles internally is that I have a fixed set of vertices and, based on a number of parameters, choose some of these vertices as points in an arbitrary mesh (which are first stored as pointers, and then ultimately uploaded to a vertex buffer object as a series of floats). Since vertices store their normals as well as their position, I thought it would be easy to ensure that each time a vertex is used by a triangle, that triangle's normal influences the vertex's total normal. It appears that isn't the case. Currently, every time I make a new triangle, I calculate its normal and then add that normal to the existing normals of the three vertices involved. After making all my triangles, I reduce the length of each vertex's normal to 1. I've also tried adding them and then dividing by the number of triangles involved, but that doesn't work and it doesn't sound like it should work, either. This is my normal calculation. I run this for all triangles (which contain pointers to their Verts 1, 2, and 3). [code] float A[3] = {Vert2.x - Vert1.x, Vert2.y - Vert1.y, Vert2.z - Vert1.z}; float B[3] = {Vert3.x - Vert1.x, Vert3.y - Vert1.y, Vert3.z - Vert1.z}; float nX = A[1] * B[2] - A[2] * B[1]; float nY = A[2] * B[0] - A[0] * B[2]; float nZ = A[0] * B[1] - A[1] * B[0]; nX *= -1; nY *= -1; nZ *= -1; Vert1.nx += nX; Vert1.ny += nY; Vert1.nz += nZ; Vert2.nx += nX; Vert2.ny += nY; Vert2.nz += nZ; Vert3.nx += nX; Vert3.ny += nY; Vert3.nz += nZ; [/code] This is how I normalize the normals. I run this for all Verts after having run the above code for all triangles. [code] //Normalize! float Length = sqrt(Vert.nx * Vert.nx + Vert.ny * Vert.ny + Vert.nz * Vert.nz); Vert.nx /= Length; Vert.ny /= Length; Vert.nz /= Length; [/code] Clearly, the results aren't what I want. I was hoping somebody might be able to help me arrive at a better solution than this. Any advice?
  3. Good news! I've solved the problem. The issue was that I should have been pushing a matrix created from the [i]inverse [/i]of the Orientation (as well as reversing all the transformation data, i.e. the rotation and translation). What I do now is [CODE] //Rotate camera glMultMatrixf( m_PlayerCamera.GetInvertedMatrix() ); //Translate camera sf::Vector3<float> CameraPos = m_PlayerCamera.GetPosition(); glTranslatef(CameraPos.x, CameraPos.y, CameraPos.z); [/CODE] Where GetInvertedMatrix() looks like this: [CODE] GLfloat* Camera::GetInvertedMatrix() { //Get a new quaternion, the inverse of the Orientation Quaternion InvertedOrientation = m_Orientation; InvertedOrientation.Invert(); //Fill the matrix with the orientation InvertedOrientation.RotationMatrix(m_RotationMatrix); //Return that matrix return m_RotationMatrix; } [/CODE] Once I do this, everything works as intended. In case anybody in the future is looking for the way to Invert() a quaternion, here's my code: [CODE] void Quaternion::Invert() { float Length = 1.0 / (x*x + y*y + z*z + w*w); x *= -Length; y *= -Length; z *= -Length; w *= Length; } [/CODE]
  4. Thanks for the reply! [quote name='Matias Goldberg' timestamp='1337580247' post='4941832'] "Doing the reverse" means in this case m_TurnSpeed becomes "-m_TurnSpeed" And, when translating, m_MoveSpeed is also negated "- m_MoveSpeed" But don't change the order of the quaternion multiplcations, it's not the same. The idea behind the "camera matrix" (actually called view matrix) is that, if you can't the camera, move the whole world. This means if the camera is moved 2 units to the left, it's the same as if [i]everything else[/i] moves 2 units to the right. Same with rotations, etc. You get the idea. [/quote] See, I thought this was the case, but when I try that out (inverting m_TurnSpeed and m_MoveSpeed, leaving the order of the quaternion multiplication alone), what happens is the rotations are in the wrong direction, and they don't add up. So for example, if I turn to the right around the Y axis (by pressing the key meant to turn to the left), then try to rotate around the Z axis, I end up rotating around the global Z axis, not the camera's Z axis, i.e. I end up rotating around the camera's X axis (if it's a 90° turn). When I leave the values alone and reverse the multiplication order, rotation *appears* to work as expected (i.e. rotation around the Y axis, then around the Z axis, leads to a rotation around the new, post-Y-rotation Z axis and not the old one). It might not be, of course; if that's the case, then there's a deeper problem. [quote name='Matias Goldberg' timestamp='1337580247' post='4941832'] If you still don't get it working after negating those variables, the way you're extracting the translation part and then apply movement doesn't look quite right. Can't really tell without debugging the numbers. If I'm not mistaken, that code should make the camera spin around the origin when trying to rotate, rather than rotating around it's center. But in the models you don't see it glitch like that because you normalize the matrix, and use glTranslate to let OpenGL perform the translation for you, so it miraculous works. [/quote] Hm, that could be a problem. Here is what MultVect() looks like: [CODE] sf::Vector3<float> Quaternion::MultVect(sf::Vector3<float> Vector) { //From http://www.idevgames.com/articles/quaternions Quaternion VectorQuat = Quaternion(); VectorQuat.x = Vector.x; VectorQuat.y = Vector.y; VectorQuat.z = Vector.z; VectorQuat.w = 0.0; Quaternion Inverse = (*this); Inverse.Invert(); Quaternion Result = Inverse * VectorQuat * (*this); sf::Vector3<float> ResultVector; ResultVector.x = Result.x; ResultVector.y = Result.y; ResultVector.z = Result.z; return ResultVector; } [/CODE] I do use glTranslafef() when rendering the scene. Here is what that code looks like (it is called before anything else in the scene is rendered): [code] //Rotate camera glMultMatrixf(m_PlayerCamera.GetMatrix()); //Translate camera sf::Vector3<float> CameraPos = m_PlayerCamera.GetPosition(); glTranslatef(CameraPos.x, CameraPos.y, CameraPos.z); [/code] [quote name='Matias Goldberg' timestamp='1337580247' post='4941832'] But in the camera, you don't have that, so if I'm not mistaken, you are unable to move it, right? [/quote] It actually moves quite smoothly, just in the wrong direction. If I do the following, I get near-perfect movement so long as I don't try to rotate around the camera's Z axis. [CODE] //Create new quaternions for each axis Quaternion xOffset = Quaternion(); xOffset.FromAxisAngle(Rotation.x * m_TurnSpeed, 1.0, 0.0, 0.0); Quaternion yOffset = Quaternion(); yOffset.FromAxisAngle(Rotation.y * m_TurnSpeed, 0.0, 1.0, 0.0); Quaternion zOffset = Quaternion(); zOffset.FromAxisAngle(Rotation.z * m_TurnSpeed, 0.0, 0.0, 1.0); //Multiply the new quaternions into the orientation m_Orientation = m_Orientation * yOffset * zOffset * xOffset; //Get matrix m_Orientation.Normalize(); m_Orientation.RotationMatrix(m_RotationMatrix); ///Translate camera Translation = m_Orientation.MultVect(Translation); m_Position.x += (Translation.x * m_MoveSpeed); m_Position.y += (Translation.y * m_MoveSpeed); m_Position.z -= (Translation.z * m_MoveSpeed); [/CODE] Now, mathematically, I'm almost certain something isn't right here, since that's not what I'd expect the proper operations to look like.
  5. So a while ago I was trying to figure out how to rotate objects using quaternions, and I eventually succeeded. Now, I'm trying to adapt the same system for use in my camera. I am coding in C++, using OpenGL and SFML. Here is how I rotate and translates objects at the moment: [CODE] //Create change quaternions for each axis Quaternion xOffset = Quaternion(); xOffset.FromAxisAngle(Rotation.x * m_TurnSpeed, 1.0, 0.0, 0.0); Quaternion yOffset = Quaternion(); yOffset.FromAxisAngle(Rotation.y * m_TurnSpeed, 0.0, 1.0, 0.0); Quaternion zOffset = Quaternion(); zOffset.FromAxisAngle(Rotation.z * m_TurnSpeed, 0.0, 0.0, 1.0); //Multiply the change quats by the current quat m_Orientation = yOffset * zOffset * xOffset * m_Orientation; //Get matrix m_Orientation.Normalize(); m_Orientation.RotationMatrix(m_RotationMatrix); Translation = m_Orientation.MultVect(Translation); m_Position.x += (Translation.x * m_MoveSpeed); m_Position.y += (Translation.y * m_MoveSpeed); m_Position.z += (Translation.z * m_MoveSpeed); [/CODE] I apply m_RotationMatrix using glMultMatrix(), and m_Position using glTranslatef(). This works fine for objects rotating and translating about, but when I apply this to my camera, obviously things don't work. Now, I say obviously, because as far as I know, if I want to change the direction I'm "looking at" in OpenGL, I need to apply the [i]reverse [/i]of the changes I'd apply to an object. However, I'm not quite sure how to do this, and all my attempts have failed. Leaving everything exactly the same, I find rotations don't add up and translations are backwards or inverted. Inverting the input doesn't help. I believe that using [CODE] m_Orientation = m_Orientation * yOffset * zOffset * xOffset; [/CODE] Instead of the previous form is appropriate for the camera, and this is enough to fix all the rotation issues, but I simply can't manage to get translations to work after that. I can get close by adding the X and Y changes to the position normally and then subtracting the Z change from the position, but this still leads to wonky behavior when moving and rotating around the Z axis at the same time, and the object ends off spiraling away from the point it is supposed to be pointing towards. So, any tips on how to adapt the above behavior for proper use as a camera? Also, when applying a camera to OpenGL, to I need to use glPushMatrix() and glPopMatrix()? I ask because that helped some tests run better than others, but it doesn't seem to make sense to do so, since those are basically for pushing a new [i]local [/i]space for transformations onto the stack (I'm horribly mangling my terminology, I'm sure).
  6. Found it! It turns out my implementation of quaternions [i]wasn't[/i] correct after all. The code for quaternion multiplication I had was either wrong, or I copied it wrong. Either way, fixing it by referring to this site helped: [url="http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Quaternions.html"]http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Quaternions.html[/url] For the record, the correct quaternion multiplication code I now use is: [code]Quaternion Quaternion::operator* (Quaternion OtherQuat) { float A = (OtherQuat.a * a) - (OtherQuat.x * x) - (OtherQuat.y * y) - (OtherQuat.z * z); float X = (OtherQuat.a * x) + (OtherQuat.x * a) + (OtherQuat.y * z) - (OtherQuat.z * y); float Y = (OtherQuat.a * y) + (OtherQuat.y * a) + (OtherQuat.z * x) - (OtherQuat.x * z); float Z = (OtherQuat.a * z) + (OtherQuat.z * a) + (OtherQuat.x * y) - (OtherQuat.y * x); Quaternion NewQuat = Quaternion(); NewQuat.a = A; NewQuat.x = X; NewQuat.y = Y; NewQuat.z = Z; return NewQuat; }[/code] Many thanks to you, [b]alvaro[/b]! I otherwise would have just assumed this was beyond my capabilities. The object now rotates easily along all its local axes, no matter what previous rotations took place. Awesome!
  7. All right, I'll do some more intensive debugging and get back with the results.
  8. [quote name='alvaro' timestamp='1332426906' post='4924326'] What part of that code is initialization that you do once and what part is something you do in each iteration of the loop? Or do you do all of that every time? [/quote] The input code above is performed every time, assuming a certain flag is true. Rotation is then passed to the entity that is supposed to be rotating. Is that bad? EDIT: Just to be sure, I changed the code such that it is executed regardless of the flag, and the same problem occurs.
  9. [quote name='alvaro' timestamp='1332426277' post='4924320'] I am not sure what "the problem" is at this stage. If you still haven't solved the issues with the volume of the object changing, you need to renormalize the quaternion periodically (for instance, after each step) by dividing it by its length. Does anything else seem broken? Also, can you explain what you put in Rotation? [/quote] I checked to make sure it was normalizing, and I wasn't normalizing every frame, so I added that in. The result is that the size stays the same (thank you!), but the model only wobbles a bit along the Y and Z axes. To clarify: Holding down Left, which should make it rotate along the Y axis, instead makes it rotate a tiny bit to the left, then a tiny bit to the right, repeatedly, as though the ship were shaking its head. Rotation around the X axis works fine, though. Here is how I fill Rotation: [code] ///Rotation float TurnSpeed = 0.01; sf::Vector3<float> Rotation; Rotation.x = 0.0; Rotation.y = 0.0; Rotation.z = 0.0; //Pitch if (m_App->GetInput().IsKeyDown(sf::Key::Up) == true) { Rotation.x -= TurnSpeed; } if (m_App->GetInput().IsKeyDown(sf::Key::Down) == true) { Rotation.x += TurnSpeed; } //Yaw if (m_App->GetInput().IsKeyDown(sf::Key::Left) == true) { Rotation.y -= TurnSpeed; } if (m_App->GetInput().IsKeyDown(sf::Key::Right) == true) { Rotation.y += TurnSpeed; } //Roll if (m_App->GetInput().IsKeyDown(sf::Key::Q) == true) { Rotation.z -= TurnSpeed; } if (m_App->GetInput().IsKeyDown(sf::Key::E) == true) { Rotation.z += TurnSpeed; }[/code]
  10. [quote name='alvaro' timestamp='1332425519' post='4924313'] I think you got it. The non-conmutativeness of the quaternion product is not apparent under small angles, so I would start by just ignoring it. [/quote] Okay, so that part works; thanks for the confirm! I've interpreted that as this in my current code: [code] Quaternion xOffset = Quaternion(); Quaternion yOffset = Quaternion(); Quaternion zOffset = Quaternion(); xOffset.FromAxisAngle(Rotation.x, 1.0, 0.0, 0.0); yOffset.FromAxisAngle(Rotation.y, 0.0, 1.0, 0.0); zOffset.FromAxisAngle(Rotation.z, 0.0, 0.0, 1.0); m_Orientation = xOffset * yOffset * zOffset * m_Orientation; m_Orientation.RotationMatrix(m_RotationMatrix);[/code] To clarify: Rotation is basically a vector {x, y, z} where each value represents either a positive, negative or null change, as implied by player input. Currently that change is 0.01. Quaternions are initialized as identity quaternions (so {a, x, y, z} = {1, 0, 0, 0}), but that data is overwritten in FromAxisAngle(...), so that shouldn't be an issue. So if that part of my code is correct, what could be causing the problem? m_RotationMatrix is a GLfloat[16], stored in column-major format (I think that's what it's called - the first 4 floats represent the first column, etc.), so that should be okay. Should I be using something other than glMultMatrix()?
  11. [quote name='alvaro' timestamp='1332421825' post='4924289'] If you want to do 6DOF movement using quaternions, do *not* use roll, pitch and yaw. You want to take the user's input and apply small incremental rotations along the three axes to the existing quaternion. Does that make sense? [/quote] Hm... So say the user wants the ship to pitch down a little (relative to the ship's previous orientation, not global orientation). What confuses me is "apply rotations." I take that to mean: 1. Create a quaternion [b]qPitch [/b]from an axis-angle value where the Axis = [b]{1.0, 0.0, 0.0}[/b] and the Angle is, for example, [b]0.1[/b] 2. Multiply qPitch by m_Orientation, the current orientation of the ship, so [b]m_Orientation = qPitch * m_Orientation[/b] Does that sound right? That has been my intuition up until now, so I assume it's wrong, but I'm not quite sure in what way. Also, because quaternion multiplications are noncommutative, I've been worried about extending this approach to all three possible axes at once, since the order in which I multiply them will determine the kind of result I get - although I want all rotations to be relative to local axes. It seems that any order I put them in will shortchange one of the axes or another.
  12. Nobody? I've tried all sorts of things, and nothing has worked. I've tried adding input directly to stored Euler angles and simply creating a new quaternion each time, but that results in rotations around global axes with no regard to local axes. [code]m_Rotation.x += Rotation.x; m_Rotation.y += Rotation.y; m_Rotation.z += Rotation.z; m_Orientation.FromPYR(m_Rotation.x, m_Rotation.y, m_Rotation.z); m_Orientation.RotationMatrix(m_RotationMatrix);[/code] I've tried passing input as axis-angle and creating offset quaternions with those, multiplying them into the main orientation, but this results in extremely fast rotation around the X axis and explosive scaling or near-invisible shivering along the y and z axes. [code]xOffset.FromAxisAngle(Rotation.x, 1.0, 0.0, 0.0); yOffset.FromAxisAngle(Rotation.y, 0.0, 1.0, 0.0); zOffset.FromAxisAngle(Rotation.z, 0.0, 0.0, 1.0); m_Orientation = xOffset * yOffset * zOffset * m_Orientation; m_Orientation.RotationMatrix(m_RotationMatrix);[/code] I've tried directly making an offest quaternion from the entire PYR input, but the roll command makes the plane pitch and everything else just makes it wobble ever so slightly. [code]Quaternion Change = Quaternion(); Change.FromPYR(Rotation.x, Rotation.y, Rotation.z); m_Orientation = Change * m_Orientation; m_Orientation.RotationMatrix(m_RotationMatrix);[/code] What other ways are there to transform input into quaternions? I have to use Pitch-Yaw-Roll because that's ultimately what players will be using their input as - mouse left-right for yaw, mouse up-down for pitch, and Q and E for roll (I'm copying the flight controls from [i]Star Wars: Battlefront II[/i]). I can't get away from Euler angles, or at least not from a Pitch-Yaw-Roll scheme. How do I do this? Also, please note that the objects have to rotate [i]independently [/i]of the camera. I've tried all sorts of tutorials: [url="http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/index.htm"]http://www.euclidean...forms/index.htm[/url] [url="http://www.idevgames.com/articles/quaternions"]http://www.idevgames...les/quaternions[/url] [url="http://www.cprogramming.com/tutorial/3d/quaternions.html"]http://www.cprogramm...uaternions.html[/url] [url="http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Quaternions.html"]http://www.arcsynthe...uaternions.html[/url] But none of them cover implementation in a way I can grok. They mostly cover the mathematical operations for using quaternions, which I think I've already got. I would have thought just converting the PYR rotation to a quaternion and multiplying that with the orientation would work, but it doesn't, and I don't know where to go from here. EDIT: Just in case my quaternion math [i]is [/i]wrong, here are some parts of my Quaternion class: From [url="http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm"]http://www.euclidean...rnion/index.htm[/url]: [code]void Quaternion::FromPYR(float Pitch, float Yaw, float Roll) { //Set Pi float Pi = 4 * atan(1); //Set the values, which came in degrees, to radians float rYaw = Yaw * Pi / 180; float rPitch = Pitch * Pi / 180; float rRoll = Roll * Pi / 180; //Components float C1 = cos(rYaw / 2); float C2 = cos(rPitch / 2); float C3 = cos(rRoll / 2); float S1 = sin(rYaw / 2); float S2 = sin(rPitch / 2); float S3 = sin(rRoll / 2); //Remember to convert A to degrees again a = ((C1 * C2 * C3) - (S1 * S2 * S3)); x = (S1 * S2 * C3) + (C1 * C2 * S3); y = (S1 * C2 * C3) + (C1 * S2 * S3); z = (C1 * S2 * C3) - (S1 * C2 * S3); //Normalize Normalize(); }[/code] From [url="http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm"]http://www.euclidean...rnion/index.htm[/url]: [code]//Rebuilds this quaternion using an angle and a rotation axis void Quaternion::FromAxisAngle(float Angle, float xAxis, float yAxis, float zAxis) { //Angle should be in radians a = cos(Angle/2); //Axes x = xAxis * sin(Angle/2); y = yAxis * sin(Angle/2); z = zAxis * sin(Angle/2); //Normalize Normalize(); }[/code] From [url="http://www.idevgames.com/articles/quaternions"]http://www.idevgames...les/quaternions[/url] [code]void Quaternion::RotationMatrix(GLfloat* Matrix) { //Column 1 Matrix[0] = 1.0 - (2.0*((y*y) + (z*z))); Matrix[1] = 2.0*((x*y) + (a*z)); Matrix[2] = 2.0*((x*z) - (a*y)); Matrix[3] = 0.0; //Column 2 Matrix[4] = 2.0*((x*y) - (a*z)); Matrix[5] = 1.0 - (2.0*((x*x) + (z*z))); Matrix[6] = 2.0*((y*z) + (a*x)); Matrix[7] = 0.0; //Column 3 Matrix[8] = 2.0*((x*z) + (a*y)); Matrix[9] = 2.0*((y*z) - (a*x)); Matrix[10] = 1.0 - (2.0*((x*x) + (y*y))); Matrix[11] = 0.0; //Column 4 Matrix[12] = 0.0; Matrix[13] = 0.0; Matrix[14] = 0.0; Matrix[15] = 1.0; }[/code]
  13. Actually, I'm deriving a rotation matrix from the quaternion each time the quaternion is modified, and then multiplying the object's view matrix by that rotation matrix upon rendering. I've heard that reduces the issues you can sometimes get where some rotations continue to be around the global rather than local axes. Originlally I had reconverted them to Euler angles, and that was the problem I got. For example, for a given order, if I rotated along the X axis and then tried to rotate alone the Y axis, the Y rotation would still take place along the global axis. Which axes were a problem changed depending on the order, but there was no order that removed the problem entirely. This is how I render the VBO's transformations: [code]glPushMatrix(); //Apply transformations glTranslatef(m_Position.x, m_Position.y, m_Position.z); glMultMatrixf(m_RotationMatrix); //(...) VBO rendering code glPopMatrix();[/code]
  14. So I'm trying to code something similar to a 3D space sim, where I want six degrees of freedom. Apparently the best way to achieve 6DoF is with quaternions, so I've spent the last two days reading up about them and trying to get some code to work. I am using SFML 1.6 and OpenGL, nothing else. I have a Quaternion class that I'm fairly certain is mathematically correct, and can create a quaternion from an axis and an angle; it normalizes itself, and the multiplication operator is overloaded to perform a proper multiplication. However, don't understand how to transform the player's input into a quaternion representing a change in rotation. The player can input changes into the Pitch, Yaw and Roll, potentially all three at once. The object they are controlling is supposed to then rotate according to this input along its LOCAL axes. Suppose the player wanted to change the Pitch by 30°, the Yaw by 45° and the Roll by 10° all at the same time (I'm using that example because it's the most complex possible situation my code will have to deal with). So I have these nice little values, 30-45-10 (which I could also convert to radians), but what do I do with them? I've read dozens of tutorials, and what little I can make sense of them seems to indicate I need to make the change quaternion like this (pseudocode): [code]Qaternion xChange = Quaternion.FromAxisAngle(30, 1, 0, 0); Qaternion yChange = Quaternion.FromAxisAngle(45, 0, 1, 0); Qaternion zChange = Quaternion.FromAxisAngle(10, 0, 0, 1); Qaternion totalChange = zChange * yChange * xChange;[/code] Where FromAxisAngle takes the parameters (float Angle, float X, float Y, float Z). Then I apparently need to perform this on the object's current Orientation, also a quaternion: [code]Orientation = totalChange * Orientation;[/code] And finally derive a matrix from Orientation and pass that to glMultMatrix(). Unfortunately, my current code doesn't really work. Trying to change the yaw or roll just makes the object shiver, and trying to change the pitch makes the object spin correctly for a moment and then start to roll and grow enormously large at the same time. The thing is, deep down I know my code shouldn't work, because quaternion multiplications are non-commutative. I can't just willy-nilly multiply quaternions for three different orientations with one another - the order will end up influencing the result, right? What do I do when a particular axis isn't supposed to be rotating at the moment? I've got this not-working system in place, but I've tried half a dozen other configurations that don't work either. Rotation is the user-input rotation around the X,Y,Z axes respectively. I'n not doing any translation at the moment. [code]void Entity::Transform(sf::Vector3<float> Translation, sf::Vector3<float> Rotation) { if (Rotation.x != 0) { Quaternion Offset = Quaternion(); Offset.FromAxisAngle(Rotation.x, 1, 0, 0); m_Orientation = Offset * m_Orientation; } if (Rotation.y != 0) { Quaternion Offset = Quaternion(); Offset.FromAxisAngle(Rotation.y, 0, 1, 0); m_Orientation = Offset * m_Orientation; } if (Rotation.z != 0) { Quaternion Offset = Quaternion(); Offset.FromAxisAngle(Rotation.z, 0, 0, 1); m_Orientation = Offset * m_Orientation; } //Derive a rotation matrix m_Orientation.RotationMatrix(m_RotationMatrix); } [/code] Can somebody tell me how I'm supposed to transform my player input into the appropriate quaternion transformations? Note that I've also tried directly creating a quaternion from stored PYR variables, but this didn't work and I was told by someone reading my code that that was the wrong way to implement this sort of thing (unfortunately, his explanation of the right way to do it was extremely vague, at least to me).
  15. Well, it's in Python and it's very messy, but I've uploaded a project I did a while ago, trying to replicate the basic mechanics of an RTS (I was going for an Age of Empires clone feel). [url="http://www.mediafire.com/?2cvyc4r1n3qh84u"]http://www.mediafire...2cvyc4r1n3qh84u[/url] In it, units attack, move, gather resources and build structures, though there are no animations and there isn't much GUI feedback, so it can be hard to tell if anything's happening. Note that there is no pathing in this example, which is a very important part of unit movement in RTS games. Most of the stuff you expressed an interest in is in the Units.py file. Best get a proper Python IDE for this; reading it in a word processor is even worse. To sum up: I had the units have a task list, with each task having a name ("attack" or "move" or whatever), and coordinates, speed values, or a target of some sort. The unit would in its portion of the game cycle, execute whatever task was on its list at that time. The code might be too messy to be of any help; if you want, you can PM me to ask about details, and I'll try to help you as best I can, but I abandoned this project several months ago to move onto other things (though I have done some A* pathfinding in the meantime). There are two seemingly well-developped engines out there that could be used for RTS games that you could also check out: [url="http://en.wikipedia.org/wiki/Flexible_Isometric_Free_Engine"]http://en.wikipedia....ric_Free_Engine[/url] [url="http://en.wikipedia.org/wiki/Spring_%28game_engine%29"]http://en.wikipedia....8game_engine%29[/url] Best of luck! People say RTS games are very hard, but I've worked on a lot of the systems involved, and they're actually not that hard to wrap your head around (except AI - I haven't even gone near that yet, and I think that's the hardest part of all). Besides AI, the hardest is probably pathfinding - which, admittedly, I've not yet experimented with using large numbers of units (at most, I've tested situations with about 30 entities pathfinding at the same time - peanuts compared to a game like Age of Empires 2).