Jump to content
• Advertisement

# OpenGL Issues with 3rd person space ship flight algorithm

This topic is 2592 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

## Recommended Posts

Hey!

After a few days of trying to figure it out on my own, I am unable to figure out what is wrong or what I am not doing right in trying to make a 3rd space flight demo.

At the moment, my ship moves properly if I turn left or right or if I go up and down but when I start turning around and mixing axes, things get messed up at some point. The ship just starts moving backwards or just drifts away in a direction.

I'm using OpenGL so I'm not sure whether this belongs to the OpenGL forum but I thought this was more theory than actual OpenGL issues.

The way I compute my movement is the following :

I start with the ship at the origin and give it a direction vector going [0,0,-1]. My world is a simple sphere spanning about 25000 in radius and I intend on making everything stay inside that.

By pressing the arrow keys, I change the Heading Angle and the Pitch Angle of the ship by a small amount. Those angles return to 0 if the keys aren't pressed anymore.

Every frame, I rotate the rest of the world opposite of those angles by a ratio of 1/30 of the value of those angles. so if the ship is tilted 30 degrees upwards on that frame, I will rotate the world by 1 degree in the opposite direction to give it a slower pace. If I keep those angle 1 to 1 the world spins so fast it's impractical.

To computer proper positioning, I take my initial vector [0,0,-1] and put it inside a 4x4 matrix homogeneous matrix. I obtain the current matrix transformation from the ModelViewMatrix and multiply them together to obtain a new unit direction vector for my ship. With this unit direction vector, I update the position by adding each successive new direction vector I obtain. So far, it seems to keep track of the position very well but my direction is often reversed and I don't know what I must do.

Do you guys have a suggestion of what could be going wrong ? I can always post some code if necessary. I thought I would ask first and see if perhaps someone would have a good lead on what I should look into and try to figure out on my own in order to learn from this.

I'm probably doing lots of things wrong so don't hesitate to tell me what I should change.

Thanks!

#### Share this post

##### Share on other sites
Advertisement
I think a good first step would be to define precisely what kind of motion control scheme you want.

It sounds like only pitch and yaw can be modified (that is, no roll). Are these rotations intended to be relative, or is there a 'fixed' up vector? In other words, do you want a 6DOF control scheme, or something more like a first-person character control scheme?

#### Share this post

##### Share on other sites
From what I understand of 6DOF vs FPS style I would tend to say more of a 6 degrees of freedom approach.

At the moment, I have Yaw and Pitch implemented. Rolling is there as well but is meant to act differently. I make the ship roll over no more than 90 degrees on each side and so the world rolls on either side but follows the angle of the ship itself. when the ship's roll angle returns to 0, so does the rolling rotation applied to the world.

I'm not entirely certain what you mean by relative rotations or fixed up vector but I'll try to answer that the best I can. Logically I would believe 6DOF to be relative and FPS to be a fixed up vector. since the ship can't really move backwards and can only go forward, and where everything around the ships moves according to its movement I think I'm looking for relative rotations and translations. A fixed vector approach would make sense for an FPS but I don't know how I would apply it to my ship.

Each frame, I start assuming the ship is at [0,0,0] in the direction [0,0,-1]. Based on the world rotation made to the scene at that frame, I calculate the matrix multiplication of that matrix state with my [0,0,-1] initial direction vector to to get the proper translation vector that I use to move the world around the ship. The ship is always at [0,0,0] the entire time.

I have two sets of rotations that are independent from each other that I use together: The ship's rotation angles and the world's rotation angle. The ship angles are only used to animate the ship and indicate how much the world should rotate around the world. If I stop animating the ship and disable the rotations, I have a fixed ship, seen from the back, and a bit from above that doesn't move on its own but I the world around it rotates. From what I understand, the ship must always face the direction it is going so this is where it bugs up depending on the coordinates.

if I change the pitch angles either up or down, I end up with the world upside down and going the right way. as Long as I don't turn left or right more than 90 degrees more or less than it's still all fine. The same goes for the Yaw angle. as long as the ship is flat on the X/Z plane more or less. turning around anyway I want works fine. if I start going up or down to around 90 degrees, the direction of the ship gets reversed as well as the yaw rotations.

*Edit*
An important information would be that the camera is also always looking at [0,0,0]. I tried to move the camera weeks ago and I am not comfortable with how it works and how to move the camera in the scene. Some information I found and discussing it with a friend made me decide moving the world around might be simpler for me than to move the camera and the ship in the world. Perhaps this was a mistake?
*Edit*

I don't know what else to add so far. I will probably be able to give more pertinent details later as the discussion goes on.

Thanks!

#### Share this post

##### Share on other sites
There's a lot of different things that can go wrong with something like this. I didn't completely follow all the details of the movement scheme you described, but here's a few general tips that might be useful:

- Generally speaking, you'll want to do all the math yourself (using your own code or a third-party math library) rather than using OpenGL convenience functions or accessing the modelview matrix directly. This will give you more control and will provide cleaner interaction with the OpenGL API.

- For 6DOF motion, the general approach is to store the object's orientation as a matrix or quaternion, apply local, incremental rotations as necessary each update, normalize the orientation to prevent numerical drift, and then build a transform matrix from the orientation and position for uploading to OpenGL (or whatever API you're using). The direction vectors for the object can then be extracted directly from the matrix for the purpose of applying linear motion.

- Unless you have a specific reason for doing so, I wouldn't think of (or implement) the ship's motion in terms of applying opposite rotations to the world. (Again, unless you're going for a specific effect or have a specific need to do it that way.) Just let the world be static and move the ship using normal methods; once you've built the ship's transform matrix, you can then invert it to yield the view transform.

#### Share this post

##### Share on other sites

There's a lot of different things that can go wrong with something like this. I didn't completely follow all the details of the movement scheme you described, but here's a few general tips that might be useful:

- Generally speaking, you'll want to do all the math yourself (using your own code or a third-party math library) rather than using OpenGL convenience functions or accessing the modelview matrix directly. This will give you more control and will provide cleaner interaction with the OpenGL API.

- For 6DOF motion, the general approach is to store the object's orientation as a matrix or quaternion, apply local, incremental rotations as necessary each update, normalize the orientation to prevent numerical drift, and then build a transform matrix from the orientation and position for uploading to OpenGL (or whatever API you're using). The direction vectors for the object can then be extracted directly from the matrix for the purpose of applying linear motion.

- Unless you have a specific reason for doing so, I wouldn't think of (or implement) the ship's motion in terms of applying opposite rotations to the world. (Again, unless you're going for a specific effect or have a specific need to do it that way.) Just let the world be static and move the ship using normal methods; once you've built the ship's transform matrix, you can then invert it to yield the view transform.

I'm sure what I wrote isn't exactly easy to follow. I already have a bit of my own matrix operations going here and there. Using the Model View Matrix of OpenGL was an idea I got based on loading an identity matrix into it and then doing operations on it to obtain the transformations I wanted and applying them to my direction vector to get another matrix from which I could extract the properly transformed vector.

I agree with you that this may not be a good idea. This was mostly to save time as I noticed it always gave me the results I expected and decided to use it. I'll try to apply my own matrix transformations. I'm just hoping I won't screw up the functions. Using a third party would probably be more powerful but as I'm trying to learn how it works from the ground up I think going the painful way might be better.

I'm just not sure about normalization. I know what it is, but I'm not sure if I need to normalize if the vector I provide my operations with a unit vector to start with. will that vector need normalizing after transformation or will it remain in unit form ?

I will also attempt moving the camera and reporting. There are other kinds of operations I am not sure how to go about it. I'll post more as I go along. I'm not entirely certain how I would go about it but I'm going to use your advice as a base for what to do.

I'll post an update as I go on.

Thanks!

#### Share this post

##### Share on other sites
Regarding the normalization I mentioned, the purpose of that is to correct for numerical error caused by multiple successive incremental rotations.

Due to the imprecision of floating-point representations, rotations in both quaternion and matrix form will generally drift over time, and at some point noticeable artifacts may appear (e.g. scaling with quaternions, or scaling and/or shear with matrices). Normalizing (in the general sense) the rotation is intended to correct this. With quaternions, this equates to a quaternion normalization, which is a simple and fairly efficient operation. With matrices it requires orthogonalization, which is a bit less simple and efficient, but is still relatively straightforward.

#### Share this post

##### Share on other sites
I had the same issue with my space simulator. My camera would use the y axis as the "up" vector, effectively locking it to a first person camera. The trick is to use Quaternions. It's been a year or so since I implemented it, but I believe I created a quaternions for the yaw, pitch and roll angles, and then concatenated them together, and then converted it to a matrix. The result is a camera similar to the old Star Wars X-Wing games. Using matrices causes issues with the gimbol lock and having to use an up vector (I'm not sure if there's a solution to this, but I never found it). But yeah, look into that.

*Edit* I reread the title and noticed the "3rd person" part. My solution was for a first person camera. Still, I believe quaternions are your best bet.

#### Share this post

##### Share on other sites

I had the same issue with my space simulator. My camera would use the y axis as the "up" vector, effectively locking it to a first person camera. The trick is to use Quaternions. It's been a year or so since I implemented it, but I believe I created a quaternions for the yaw, pitch and roll angles, and then concatenated them together.

A couple comments on the above (just to prevent confusion).

First of all, whether you use quaternions or matrices makes no difference as far as gimbal lock or anything like that goes. Generally speaking, you can get the same results regardless of whether you use quaternions or matrices. Each representation has its own advantages and disadvantages, but their fundamental behavior with respect to rotations is equivalent. (Just to be clear, I'm not talking about memory requirements, efficiency of specific operations, stability, or any of the other areas where quaternions and matrices do indeed differ; rather, I'm talking about fundamental behaviors, such as whether or not gimbal lock can occur and how rotations can be constructed and manipulated.)

Second, creating separate yaw, pitch, and roll quaternions is the same as constructing an Euler-angle rotation using any other method; the use of quaternions here makes no difference and doesn't buy you anything in particular.

Using matrices causes issues with the gimbol lock and having to use an up vector (I'm not sure if there's a solution to this, but I never found it). [/quote]
Gimbal lock and whether you have to use an 'up' vector have nothing to do with whether quaternions or matrices are used. (There's a lot of confusion about these topics already, so I think it's worth clarifying these points when they come up, which seems to be fairly often.)

#### Share this post

##### Share on other sites
This kind of topic might be a good candidate for a sticky.

My opionion is simple on this: take those Euler Angles behind the barn and put them out of their misery. Three angles can't store the information you need, which is not just three isolated summed up angles, but the _order_ in which they were applied. Yes, you can easily get away in a scenario with limited motion (1st person shooter), where there is always one "correct" order to apply them (usually y-axis, x-axis, z-axis).

Just use matrices in the first place and forget all the trigonometry you apply to those angles (and all the convoluted tricks to somehow hammer Euler Angles into working).
Matrices are neat and simple, they even tell you your ships forward axis (AND right AND up AND position) in 4 easy to read vectors. You will eventually need a matrix library anyway, so either find one you like or quickly write one yourself (even my straightforward code was automatically compiled to make heavy use of SSE).

So next time dont do
"yaw += 2", do
"transformation = Matrix::rotationMatrixY(2) * transformation;

even saves you the annoying step of converting your angles back to a matrix (or rather, one of many different possible matrices of which in a 6DOF scenarion most likely none will be the right one).

About quaternions. I got a feeling especially those that never quite got the math love to suggest it as a magic bullet for a problem they didn't fully understand. Jyk said pretty much all about that and I doubt you will find them overly useful (or better performing) until you start adding skeletal animations or other features that require a lot of concatenations. After all, you have to eventually transform them back to matrices for your API and the speed up in calculations has to make up for that overhead.

#### Share this post

##### Share on other sites
I have to admit, I am completely lost...

Moving the ship instead of the world also requires me to move the camera to keep the view the same. The only way I know how to control a camera view is through gluLookAt() but so far all attempts have failed at getting where I want to be. I have a feeling I have to control the eye and Center value manually but I have no clue how to update it properly each frame. The only thing that comes to mind is using the eye as the position and provide a direction unit vector to the center. And since the camera is backed away from the ship, I also need to translate the position opposite of the center and then raise it a bit. This is extremely confusing.

I realized I can achieve a similar outcome rotating and translating the projection view matrix so this is what I am attempting right now without much success. I can get the camera to follow the ship properly by translating it first and rotating it by the opposite rotation that I do for the ship and it works fine on a 2D plane. The ship only rotates at the origin at the moment and does not move.

The issue I have is when I attempt to rotate in 3D, the axes get all scrambled. If I turn the left 90 degrees and attempt to go up, instead of rotating in that direction, the view is tilted left or right. I understand why it happens but I'm looking for a way to make the axes "follow" along with the ship in a way.

Once I get that sorted out I will be able to try moving the ship in the space.

Also, I tried to create a matrix that I keep updating frame after frame but it goes awfully wrong when I use rotation and translation. because the matrix contains both rotation and translations into it, when I add further translations and rotations it becomes Screwed up beyond all recognition. Should I keep two separate matrices and update them each frame and put them together only when comes the time to update the view?

I think I'm going to need some step by step guidance. I get too confused with everything.

#### Share this post

##### Share on other sites

• Advertisement

### Announcements

• Advertisement

• ### Popular Now

• 23
• 10
• 19
• 15
• 14
• Advertisement
• ### Similar Content

• By mmmax3d
Hi everyone,
I would need some assistance from anyone who has a similar experience
or a nice idea!
I have created a skybox (as cube) and now I need to add a floor/ground.
The skybox is created from cubemap and initially it was infinite.
Now it is finite with a specific size. The floor is a quad in the middle
of the skybox, like a horizon.
I have two problems:
When moving the skybox upwards or downwards, I need to
sample from points even above the horizon while sampling
from the botton at the same time.  I am trying to create a seamless blending of the texture
at the points of the horizon, when the quad is connected
to the skybox. However, I get skew effects. Does anybody has done sth similar?
Is there any good practice?
Thanks everyone!
• By mmmax3d
Hi everyone,
I would need some assistance from anyone who has a similar experience
or a nice idea!
I have created a skybox (as cube) and now I need to add a floor/ground.
The skybox is created from cubemap and initially it was infinite.
Now it is finite with a specific size. The floor is a quad in the middle
of the skybox, like a horizon.
I have two problems:
When moving the skybox upwards or downwards, I need to
sample from points even above the horizon while sampling
from the botton at the same time.  I am trying to create a seamless blending of the texture
at the points of the horizon, when the quad is connected
to the skybox. However, I get skew effects. Does anybody has done sth similar?
Is there any good practice?
Thanks everyone!

• I'm trying to implement PBR into my simple OpenGL renderer and trying to use multiple lighting passes, I'm using one pass per light for rendering as follow:
1- First pass = depth
2- Second pass = ambient
3- [3 .. n] for all the lights in the scene.
I'm using the blending function glBlendFunc(GL_ONE, GL_ONE) for passes [3..n], and i'm doing a Gamma Correction at the end of each fragment shader.
But i still have a problem with the output image it just looks noisy specially when i'm using texture maps.
Is there anything wrong with those steps or is there any improvement to this process?

• Hello Everyone!
I'm learning openGL, and currently i'm making a simple 2D game engine to test what I've learn so far.  In order to not say to much, i made a video in which i'm showing you the behavior of the rendering.
Video:

What i was expecting to happen, was the player moving around. When i render only the player, he moves as i would expect. When i add a second Sprite object, instead of the Player, this new sprite object is moving and finally if i add a third Sprite object the third one is moving. And the weird think is that i'm transforming the Vertices of the Player so why the transformation is being applied somewhere else?

Take a look at my code:
Sprite Class
(You mostly need to see the Constructor, the Render Method and the Move Method)
#include "Brain.h" #include <glm/gtc/matrix_transform.hpp> #include <vector> struct Sprite::Implementation { //Position. struct pos pos; //Tag. std::string tag; //Texture. Texture *texture; //Model matrix. glm::mat4 model; //Vertex Array Object. VertexArray *vao; //Vertex Buffer Object. VertexBuffer *vbo; //Layout. VertexBufferLayout *layout; //Index Buffer Object. IndexBuffer *ibo; //Shader. Shader *program; //Brains. std::vector<Brain *> brains; //Deconstructor. ~Implementation(); }; Sprite::Sprite(std::string image_path, std::string tag, float x, float y) { //Create Pointer To Implementaion. m_Impl = new Implementation(); //Set the Position of the Sprite object. m_Impl->pos.x = x; m_Impl->pos.y = y; //Set the tag. m_Impl->tag = tag; //Create The Texture. m_Impl->texture = new Texture(image_path); //Initialize the model Matrix. m_Impl->model = glm::mat4(1.0f); //Get the Width and the Height of the Texture. int width = m_Impl->texture->GetWidth(); int height = m_Impl->texture->GetHeight(); //Create the Verticies. float verticies[] = { //Positions //Texture Coordinates. x, y, 0.0f, 0.0f, x + width, y, 1.0f, 0.0f, x + width, y + height, 1.0f, 1.0f, x, y + height, 0.0f, 1.0f }; //Create the Indicies. unsigned int indicies[] = { 0, 1, 2, 2, 3, 0 }; //Create Vertex Array. m_Impl->vao = new VertexArray(); //Create the Vertex Buffer. m_Impl->vbo = new VertexBuffer((void *)verticies, sizeof(verticies)); //Create The Layout. m_Impl->layout = new VertexBufferLayout(); m_Impl->layout->PushFloat(2); m_Impl->layout->PushFloat(2); m_Impl->vao->AddBuffer(m_Impl->vbo, m_Impl->layout); //Create the Index Buffer. m_Impl->ibo = new IndexBuffer(indicies, 6); //Create the new shader. m_Impl->program = new Shader("Shaders/SpriteShader.shader"); } //Render. void Sprite::Render(Window * window) { //Create the projection Matrix based on the current window width and height. glm::mat4 proj = glm::ortho(0.0f, (float)window->GetWidth(), 0.0f, (float)window->GetHeight(), -1.0f, 1.0f); //Set the MVP Uniform. m_Impl->program->setUniformMat4f("u_MVP", proj * m_Impl->model); //Run All The Brains (Scripts) of this game object (sprite). for (unsigned int i = 0; i < m_Impl->brains.size(); i++) { //Get Current Brain. Brain *brain = m_Impl->brains[i]; //Call the start function only once! if (brain->GetStart()) { brain->SetStart(false); brain->Start(); } //Call the update function every frame. brain->Update(); } //Render. window->GetRenderer()->Draw(m_Impl->vao, m_Impl->ibo, m_Impl->texture, m_Impl->program); } void Sprite::Move(float speed, bool left, bool right, bool up, bool down) { if (left) { m_Impl->pos.x -= speed; m_Impl->model = glm::translate(m_Impl->model, glm::vec3(-speed, 0, 0)); } if (right) { m_Impl->pos.x += speed; m_Impl->model = glm::translate(m_Impl->model, glm::vec3(speed, 0, 0)); } if (up) { m_Impl->pos.y += speed; m_Impl->model = glm::translate(m_Impl->model, glm::vec3(0, speed, 0)); } if (down) { m_Impl->pos.y -= speed; m_Impl->model = glm::translate(m_Impl->model, glm::vec3(0, -speed, 0)); } } void Sprite::AddBrain(Brain * brain) { //Push back the brain object. m_Impl->brains.push_back(brain); } pos *Sprite::GetPos() { return &m_Impl->pos; } std::string Sprite::GetTag() { return m_Impl->tag; } int Sprite::GetWidth() { return m_Impl->texture->GetWidth(); } int Sprite::GetHeight() { return m_Impl->texture->GetHeight(); } Sprite::~Sprite() { delete m_Impl; } //Implementation Deconstructor. Sprite::Implementation::~Implementation() { delete texture; delete vao; delete vbo; delete layout; delete ibo; delete program; }
Renderer Class
#include "Renderer.h" #include "Error.h" Renderer::Renderer() { } Renderer::~Renderer() { } void Renderer::Draw(VertexArray * vao, IndexBuffer * ibo, Texture *texture, Shader * program) { vao->Bind(); ibo->Bind(); program->Bind(); if (texture != NULL) texture->Bind(); GLCall(glDrawElements(GL_TRIANGLES, ibo->GetCount(), GL_UNSIGNED_INT, NULL)); } void Renderer::Clear(float r, float g, float b) { GLCall(glClearColor(r, g, b, 1.0)); GLCall(glClear(GL_COLOR_BUFFER_BIT)); } void Renderer::Update(GLFWwindow *window) { /* Swap front and back buffers */ glfwSwapBuffers(window); /* Poll for and process events */ glfwPollEvents(); }
Shader Code
#shader vertex #version 330 core layout(location = 0) in vec4 aPos; layout(location = 1) in vec2 aTexCoord; out vec2 t_TexCoord; uniform mat4 u_MVP; void main() { gl_Position = u_MVP * aPos; t_TexCoord = aTexCoord; } #shader fragment #version 330 core out vec4 aColor; in vec2 t_TexCoord; uniform sampler2D u_Texture; void main() { aColor = texture(u_Texture, t_TexCoord); } Also i'm pretty sure that every time i'm hitting the up, down, left and right arrows on the keyboard, i'm changing the model Matrix of the Player and not the others.

Window Class:
#include "Window.h" #include <GL/glew.h> #include <GLFW/glfw3.h> #include "Error.h" #include "Renderer.h" #include "Scene.h" #include "Input.h" //Global Variables. int screen_width, screen_height; //On Window Resize. void OnWindowResize(GLFWwindow *window, int width, int height); //Implementation Structure. struct Window::Implementation { //GLFW Window. GLFWwindow *GLFW_window; //Renderer. Renderer *renderer; //Delta Time. double delta_time; //Frames Per Second. int fps; //Scene. Scene *scnene; //Input. Input *input; //Deconstructor. ~Implementation(); }; //Window Constructor. Window::Window(std::string title, int width, int height) { //Initializing width and height. screen_width = width; screen_height = height; //Create Pointer To Implementation. m_Impl = new Implementation(); //Try initializing GLFW. if (!glfwInit()) { std::cout << "GLFW could not be initialized!" << std::endl; std::cout << "Press ENTER to exit..." << std::endl; std::cin.get(); exit(-1); } //Setting up OpenGL Version 3.3 Core Profile. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); /* Create a windowed mode window and its OpenGL context */ m_Impl->GLFW_window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL); if (!m_Impl->GLFW_window) { std::cout << "GLFW could not create a window!" << std::endl; std::cout << "Press ENTER to exit..." << std::endl; std::cin.get(); glfwTerminate(); exit(-1); } /* Make the window's context current */ glfwMakeContextCurrent(m_Impl->GLFW_window); //Initialize GLEW. if(glewInit() != GLEW_OK) { std::cout << "GLEW could not be initialized!" << std::endl; std::cout << "Press ENTER to exit..." << std::endl; std::cin.get(); glfwTerminate(); exit(-1); } //Enabling Blending. GLCall(glEnable(GL_BLEND)); GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); //Setting the ViewPort. GLCall(glViewport(0, 0, width, height)); //**********Initializing Implementation**********// m_Impl->renderer = new Renderer(); m_Impl->delta_time = 0.0; m_Impl->fps = 0; m_Impl->input = new Input(this); //**********Initializing Implementation**********// //Set Frame Buffer Size Callback. glfwSetFramebufferSizeCallback(m_Impl->GLFW_window, OnWindowResize); } //Window Deconstructor. Window::~Window() { delete m_Impl; } //Window Main Loop. void Window::MainLoop() { //Time Variables. double start_time = 0, end_time = 0, old_time = 0, total_time = 0; //Frames Counter. int frames = 0; /* Loop until the user closes the window */ while (!glfwWindowShouldClose(m_Impl->GLFW_window)) { old_time = start_time; //Total time of previous frame. start_time = glfwGetTime(); //Current frame start time. //Calculate the Delta Time. m_Impl->delta_time = start_time - old_time; //Get Frames Per Second. if (total_time >= 1) { m_Impl->fps = frames; total_time = 0; frames = 0; } //Clearing The Screen. m_Impl->renderer->Clear(0, 0, 0); //Render The Scene. if (m_Impl->scnene != NULL) m_Impl->scnene->Render(this); //Updating the Screen. m_Impl->renderer->Update(m_Impl->GLFW_window); //Increasing frames counter. frames++; //End Time. end_time = glfwGetTime(); //Total time after the frame completed. total_time += end_time - start_time; } //Terminate GLFW. glfwTerminate(); } //Load Scene. void Window::LoadScene(Scene * scene) { //Set the scene. m_Impl->scnene = scene; } //Get Delta Time. double Window::GetDeltaTime() { return m_Impl->delta_time; } //Get FPS. int Window::GetFPS() { return m_Impl->fps; } //Get Width. int Window::GetWidth() { return screen_width; } //Get Height. int Window::GetHeight() { return screen_height; } //Get Input. Input * Window::GetInput() { return m_Impl->input; } Renderer * Window::GetRenderer() { return m_Impl->renderer; } GLFWwindow * Window::GetGLFWindow() { return m_Impl->GLFW_window; } //Implementation Deconstructor. Window::Implementation::~Implementation() { delete renderer; delete input; } //OnWindowResize void OnWindowResize(GLFWwindow *window, int width, int height) { screen_width = width; screen_height = height; //Updating the ViewPort. GLCall(glViewport(0, 0, width, height)); }
Brain Class
#include "Brain.h" #include "Sprite.h" #include "Window.h" struct Brain::Implementation { //Just A Flag. bool started; //Window Pointer. Window *window; //Sprite Pointer. Sprite *sprite; }; Brain::Brain(Window *window, Sprite *sprite) { //Create Pointer To Implementation. m_Impl = new Implementation(); //Initialize Implementation. m_Impl->started = true; m_Impl->window = window; m_Impl->sprite = sprite; } Brain::~Brain() { //Delete Pointer To Implementation. delete m_Impl; } void Brain::Start() { } void Brain::Update() { } Window * Brain::GetWindow() { return m_Impl->window; } Sprite * Brain::GetSprite() { return m_Impl->sprite; } bool Brain::GetStart() { return m_Impl->started; } void Brain::SetStart(bool value) { m_Impl->started = value; } Script Class (Its a Brain Subclass!!!)
#include "Script.h" Script::Script(Window *window, Sprite *sprite) : Brain(window, sprite) { } Script::~Script() { } void Script::Start() { std::cout << "Game Started!" << std::endl; } void Script::Update() { Input *input = this->GetWindow()->GetInput(); Sprite *sp = this->GetSprite(); //Move this sprite. this->GetSprite()->Move(200 * this->GetWindow()->GetDeltaTime(), input->GetKeyDown("left"), input->GetKeyDown("right"), input->GetKeyDown("up"), input->GetKeyDown("down")); std::cout << sp->GetTag().c_str() << ".x = " << sp->GetPos()->x << ", " << sp->GetTag().c_str() << ".y = " << sp->GetPos()->y << std::endl; }
Main:
#include "SpaceShooterEngine.h" #include "Script.h" int main() { Window w("title", 600,600); Scene *scene = new Scene(); Sprite *player = new Sprite("Resources/Images/player.png", "Player", 100,100); Sprite *other = new Sprite("Resources/Images/cherno.png", "Other", 400, 100); Sprite *other2 = new Sprite("Resources/Images/cherno.png", "Other", 300, 400); Brain *brain = new Script(&w, player); player->AddBrain(brain); scene->AddSprite(player); scene->AddSprite(other); scene->AddSprite(other2); w.LoadScene(scene); w.MainLoop(); return 0; }

I literally can't find what is wrong. If you need more code, ask me to post it. I will also attach all the source files.
Brain.cpp
Error.cpp
IndexBuffer.cpp
Input.cpp
Renderer.cpp
Scene.cpp
Shader.cpp
Sprite.cpp
Texture.cpp
VertexArray.cpp
VertexBuffer.cpp
VertexBufferLayout.cpp
Window.cpp
Brain.h
Error.h
IndexBuffer.h
Input.h
Renderer.h
Scene.h
Shader.h
SpaceShooterEngine.h
Sprite.h
Texture.h
VertexArray.h
VertexBuffer.h
VertexBufferLayout.h
Window.h

• Hello fellow programmers,
For a couple of days now i've decided to build my own planet renderer just to see how floating point precision issues
can be tackled. As you probably imagine, i've quickly faced FPP issues when trying to render absurdly large planets.

I have used the classical quadtree LOD approach;
I've generated my grids with 33 vertices, (x: -1 to 1, y: -1 to 1, z = 0).
Each grid is managed by a TerrainNode class that, depending on the side it represents (top, bottom, left right, front, back),
creates a special rotation-translation matrix that moves and rotates the grid away from the origin so that when i finally
normalize all the vertices on my vertex shader i can get a perfect sphere.
T = glm::translate(glm::dmat4(1.0), glm::dvec3(0.0, 0.0, 1.0)); R = glm::rotate(glm::dmat4(1.0), glm::radians(180.0), glm::dvec3(1.0, 0.0, 0.0)); sides[0] = new TerrainNode(1.0, radius, T * R, glm::dvec2(0.0, 0.0), new TerrainTile(1.0, SIDE_FRONT)); T = glm::translate(glm::dmat4(1.0), glm::dvec3(0.0, 0.0, -1.0)); R = glm::rotate(glm::dmat4(1.0), glm::radians(0.0), glm::dvec3(1.0, 0.0, 0.0)); sides[1] = new TerrainNode(1.0, radius, R * T, glm::dvec2(0.0, 0.0), new TerrainTile(1.0, SIDE_BACK)); // So on and so forth for the rest of the sides As you can see, for the front side grid, i rotate it 180 degrees to make it face the camera and push it towards the eye;
the back side is handled almost the same way only that i don't need to rotate it but simply push it away from the eye.
The same technique is applied for the rest of the faces (obviously, with the proper rotations / translations).
The matrix that result from the multiplication of R and T (in that particular order) is send to my vertex shader as r_Grid'.
// spherify vec3 V = normalize((r_Grid * vec4(r_Vertex, 1.0)).xyz); gl_Position = r_ModelViewProjection * vec4(V, 1.0); The r_ModelViewProjection' matrix is generated on the CPU in this manner.
// No the most efficient way, but it works. glm::dmat4 Camera::getMatrix() { // Create the view matrix // Roll, Yaw and Pitch are all quaternions. glm::dmat4 View = glm::toMat4(Roll) * glm::toMat4(Pitch) * glm::toMat4(Yaw); // The model matrix is generated by translating in the oposite direction of the camera. glm::dmat4 Model = glm::translate(glm::dmat4(1.0), -Position); // Projection = glm::perspective(fovY, aspect, zNear, zFar); // zNear = 0.1, zFar = 1.0995116e12 return Projection * View * Model; } I managed to get rid of z-fighting by using a technique called Logarithmic Depth Buffer described in this article; it works amazingly well, no z-fighting at all, at least not visible.
Each frame i'm rendering each node by sending the generated matrices this way.
// set the r_ModelViewProjection uniform // Sneak in the mRadiusMatrix which is a matrix that contains the radius of my planet. Shader::setUniform(0, Camera::getInstance()->getMatrix() * mRadiusMatrix); // set the r_Grid matrix uniform i created earlier. Shader::setUniform(1, r_Grid); grid->render(); My planet's radius is around 6400000.0 units, absurdly large, but that's what i really want to achieve;
Everything works well, the node's split and merge as you'd expect, however whenever i get close to the surface
of the planet the rounding errors start to kick in giving me that lovely stairs effect.
I've read that if i could render each grid relative to the camera i could get better precision on the surface, effectively
getting rid of those rounding errors.

My question is how can i achieve this relative to camera rendering in my scenario here?
I know that i have to do most of the work on the CPU with double, and that's exactly what i'm doing.
I only use double on the CPU side where i also do most of the matrix multiplications.
As you can see from my vertex shader i only do the usual r_ModelViewProjection * (some vertex coords).

Thank you for your suggestions!

• Advertisement
×

## Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!