feat(widget): draw axis widget aligned to orbit

This commit is contained in:
ktyl 2023-10-05 23:25:37 +01:00
parent 9f2c05bf6f
commit 2384028542
6 changed files with 120 additions and 0 deletions

View File

@ -30,6 +30,7 @@ add_executable(${PROJECT_NAME}
src/icosphere.cpp
src/gfx.cpp
src/orbit.cpp
src/widget.cpp
)
if(WIN32)

View File

@ -41,6 +41,7 @@
#include "gfx.hpp"
#include "icosphere.hpp"
#include "orbit.hpp"
#include "widget.hpp"
int main()
{
@ -55,6 +56,8 @@ int main()
Icosphere orbiter(0.07, 2, litProgram);
Orbit orbit(100);
Widget widget(orbit, unlitProgram);
// Main loop
while (!glfwWindowShouldClose(window))
{
@ -77,6 +80,7 @@ int main()
glUseProgram(unlitProgram);
updateModelViewProjectionMatrix(unlitProgram, time);
orbit.render();
widget.render();
glfwSwapBuffers(window);
glfwPollEvents();

View File

@ -65,6 +65,14 @@ glm::vec3 Orbit::getPosition(const float meanAnomaly)
cartesian[astro::zPositionIndex]);
}
glm::vec3 Orbit::getTangent(const float meanAnomaly)
{
float epsilon = 0.01;
glm::vec3 ahead = getPosition(meanAnomaly + epsilon);
glm::vec3 behind = getPosition(meanAnomaly - epsilon);
return glm::normalize(ahead - behind);
}
void Orbit::render()
{
glBindVertexArray(_vao);

View File

@ -12,6 +12,7 @@ public:
void render();
glm::vec3 getPosition(const float meanAnomaly);
glm::vec3 getTangent(const float meanAnomaly);
~Orbit();
private:

69
src/widget.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "widget.hpp"
#include "gfx.hpp"
#include <glm/gtc/matrix_transform.hpp>
#include <GLFW/glfw3.h>
Widget::Widget(Orbit& orbit, GLuint shaderProgram) :
_orbit(orbit),
_shaderProgram(shaderProgram)
{
const float lineLength = 0.1;
for (int i = 0; i < 3*6; i++)
{
_vertices[i] *= _lineLength;
}
glGenVertexArrays(1, &_vao);
glGenBuffers(1, &_vbo);
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
size_t v3Size = 3 * sizeof(float);
size_t lineSize = 2 * sizeof(float);
size_t vboBufferSize = v3Size * lineSize * 3;
glBufferData(GL_ARRAY_BUFFER, vboBufferSize, &_vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void Widget::render()
{
updateModelMatrix();
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glDrawArrays(GL_LINES, 0, 6);
}
void Widget::updateModelMatrix()
{
float p = glfwGetTime();
_position = _orbit.getPosition(p);
// get the tangent of the orbital ellipse
glm::vec3 tan = _orbit.getTangent(p);
// we want to point along the orbit
glm::vec3 target = _position + tan;
// 'up' is just the normalized position vector because the orbit is centred at the origin
glm::vec3 up = glm::normalize(_position);
// easy peasy lookAt matrix
glm::mat4 look = glm::lookAt(_position, target, up);
// invert the lookat matrix because it's meant for cameras, cameras work backwards and
// we are not a camera
glm::mat4 model = glm::inverse(look);
GLint modelLocation = getShaderUniformLocation(_shaderProgram, "_Model");
glUniformMatrix4fv(modelLocation, 1, GL_FALSE, &model[0][0]);
}
Widget::~Widget()
{
glDeleteVertexArrays(1, &_vao);
glDeleteBuffers(1, &_vbo);
}

37
src/widget.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include "orbit.hpp"
#include <glm/glm.hpp>
class Widget
{
public:
// A widget is renderer at a point on the orbit.
// It consists of 3 orthagonally intersecting lines.
Widget(Orbit& orbit, GLuint shaderProgram);
void render();
void setPosition(glm::vec3 position);
~Widget();
private:
Orbit& _orbit;
glm::vec3 _position;
GLuint _vao;
GLuint _vbo;
GLuint _shaderProgram;
void updateModelMatrix();
float _lineLength = 0.2;
float _vertices[3*6] =
{
-1, 0, 0,
1, 0, 0,
0, 1, 0,
0,-1, 0,
0, 0, 1,
0, 0,-1
};
};