How to use versor and glm_quat_for to rotate a line #474
-
|
Hello. I try to draw a line from the // This function runs once per frame, and is the heart of the program
SDL_AppResult SDL_AppIterate(void *appState)
{
glClear(GL_COLOR_BUFFER_BIT);
vec3 start = { 0.f, 0.f, 0.f };
vec3 end = { 25.f, 25.f, 0.f };
LineDrawer_draw(lineDrawer, start, end, 1.f);
// Update the screen
SDL_GL_SwapWindow(window);
return SDL_APP_CONTINUE; // Carry on with the program
}I scale a square 1x1 to make a line. I can set a position and a scale: void LineDrawer_draw(LineDrawer *self, vec3 start, vec3 end, float thickness)
{
if (!self) return;
// Calculate direction vector and center
vec3 v, scaled_v, center;
glm_vec3_sub(end, start, v);
glm_vec3_scale(v, 0.5f, scaled_v); // v *= 0.5
glm_vec3_add(start, scaled_v, center);
// Find the length of the segment
float length = glm_vec3_norm(v); // length = glm.length(v)
// Normalize the segment vector
vec3 norm;
glm_vec3_normalize_to(v, norm); // norm = glm.normalize(v)
// Calculate rotation quaternion from (1,0,0) to norm
versor rotation;
vec3 x_axis = { 1.f, 0.f, 0.f };
// rotation = rotationTo((1,0,0), norm)
glm_quat_for(x_axis, norm, rotation);
// Build model matrix
glm_mat4_identity(self->modelMatrix);
// Translation
glm_translate(self->modelMatrix, center);
// // Rotation (convert quaternion to matrix)
// glm_mat4_identity(self->rotationMatrix);
// glm_quat_mat4(rotation, self->rotationMatrix);
// // Apply rotation (now in local space)
// glm_mat4_mul(self->modelMatrix, self->rotationMatrix, self->modelMatrix);
// Scaling
glm_scale(self->modelMatrix, (vec3) { length, thickness, thickness });
// Calculate MVP matrix: (projection * view) * model
glm_mat4_mul(self->projViewMatrix, self->modelMatrix, self->mvpMatrix);
// ...
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}But when I try to apply a rotation I do not see anything: // Rotation (convert quaternion to matrix)
glm_mat4_identity(self->rotationMatrix);
glm_quat_mat4(rotation, self->rotationMatrix);
// Apply rotation
glm_mat4_mul(self->modelMatrix, self->rotationMatrix, self->modelMatrix);Values of position, rotation, and scale: // Build model matrix
glm_mat4_identity(self->modelMatrix);
// Translation
glm_translate(self->modelMatrix, center);
// Rotation (convert quaternion to matrix)
glm_mat4_identity(self->rotationMatrix);
glm_quat_mat4(rotation, self->rotationMatrix);
// Apply rotation (now in local space)
glm_mat4_mul(self->modelMatrix, self->rotationMatrix, self->modelMatrix);
// Scaling
glm_scale(self->modelMatrix, (vec3) { length, thickness, thickness });
// Calculate MVP matrix: (projection * view) * model
glm_mat4_mul(self->projViewMatrix, self->modelMatrix, self->mvpMatrix);
if (printOnce)
{
SDL_Log("\nPosition: %f, %f, %f", center[0], center[1], center[2]);
SDL_Log("Quaternion: %f, %f, %f, %f\n", rotation[0], rotation[1], rotation[2], rotation[3]);
SDL_Log("Scale: %f, %f, %f", length, thickness, thickness);
printOnce = false;
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
|
I solved the problem. glMatrix library has the /**
* Sets a quaternion to represent the shortest rotation from one
* vector to another.
*
* Both vectors are assumed to be unit length.
*
* @param {quat} out the receiving quaternion.
* @param {ReadonlyVec3} a the initial vector
* @param {ReadonlyVec3} b the destination vector
* @returns {quat} out
*/The C++ version of GLM does not have the same function. I just have rewritten the Source code: line-drawer-cglm-opengl-sdl3-win-c.zip It was built with MinGW GCC 11.2. You can download MinGW here: Mediafire or from TeraBox (zip - 182.3 MB, unzipped - 571 MB) config
build
dist\appmath-helper.h#ifndef MATH_HELPER_H
#define MATH_HELPER_H
#include <cglm/cglm.h>
void math_helper_set_axis_angle(vec3 axis, float rad, versor out);
void math_helper_rotation_to(vec3 initial_vector, vec3 destination_vector, versor out);
#endifmath-helper.c#include "math-helper.h"
#include <math.h>
#include <cglm/cglm.h>
void math_helper_set_axis_angle(vec3 axis, float rad, versor out) {
rad = rad * 0.5f;
float s = sinf(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = cosf(rad);
}
void math_helper_rotation_to(vec3 initial_vector, vec3 destination_vector, versor out) {
vec3 x_unit_vec3 = {1.0f, 0.0f, 0.0f};
vec3 y_unit_vec3 = {0.0f, 1.0f, 0.0f};
vec3 tmpvec3;
float dot = glm_vec3_dot(destination_vector, initial_vector);
if (dot < -0.999999f) {
glm_vec3_cross(initial_vector, x_unit_vec3, tmpvec3);
if (glm_vec3_norm(tmpvec3) < 0.000001f) {
glm_vec3_cross(initial_vector, y_unit_vec3, tmpvec3);
}
glm_vec3_normalize(tmpvec3);
math_helper_set_axis_angle(tmpvec3, GLM_PIf, out);
return;
} else if (dot > 0.999999f) {
glm_quat_identity(out);
return;
} else {
glm_vec3_cross(initial_vector, destination_vector, tmpvec3);
out[0] = tmpvec3[0];
out[1] = tmpvec3[1];
out[2] = tmpvec3[2];
out[3] = 1.0f + dot;
glm_quat_normalize(out);
}
}line_drawer.h#ifndef LINE_DRAWER_H
#define LINE_DRAWER_H
#include <cglm/cglm.h>
#include <glad/glad.h>
typedef struct
{
GLuint shaderProgram;
GLuint vertPosBuffer;
GLint aPositionLocation;
GLint uColorLocation;
GLint uMvpLocation;
mat4 projViewMatrix;
mat4 modelMatrix;
mat4 mvpMatrix;
mat4 rotationMatrix;
} LineDrawer;
// Initialization (constructor-like)
void LineDrawer_init(LineDrawer* self, GLuint shaderProgram,
mat4 projViewMatrix);
// Get the line drawer instance
LineDrawer* LineDrawer_getInstance(void);
// Setters
void LineDrawer_setProjViewMatrix(LineDrawer* self, mat4 projViewMatrix);
// Draw function
void LineDrawer_draw(LineDrawer* self, vec3 start, vec3 end,
vec3 color, float thickness);
// Cleanup (destructor-lie)
void LineDrawer_cleanup(void);
#endif // LINE_DRAWER_Hline_drawer.c#include "line-drawer.h"
#include "math-helper.h"
#include <SDL3/SDL.h>
#include <math.h>
static LineDrawer *instance = NULL;
// Constructor-like initialization
void LineDrawer_init(LineDrawer *self, GLuint shaderProgram,
mat4 projViewMatrix)
{
if (self)
{
self->shaderProgram = shaderProgram;
glm_mat4_copy(projViewMatrix, self->projViewMatrix);
// Set up vertex data and buffers
float vertices[] = {
-0.5f, -0.5f, 0.f,
-0.5f, 0.5f, 0.f,
0.5f, -0.5f, 0.f,
0.5f, 0.5f, 0.f
};
glGenBuffers(1, &self->vertPosBuffer);
glBindBuffer(GL_ARRAY_BUFFER, self->vertPosBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Activate the current shader program to access shader variables
glUseProgram(shaderProgram);
// Get attribute and uniform locations
self->aPositionLocation = glGetAttribLocation(shaderProgram, "aPosition");
self->uColorLocation = glGetUniformLocation(shaderProgram, "uColor");
self->uMvpLocation = glGetUniformLocation(shaderProgram, "uMvpMatrix");
}
}
LineDrawer *LineDrawer_getInstance(void)
{
if (instance == NULL)
{
instance = malloc(sizeof(LineDrawer));
}
return instance;
}
void LineDrawer_setProjViewMatrix(LineDrawer *self, mat4 projViewMatrix)
{
glm_mat4_copy(projViewMatrix, self->projViewMatrix);
}
bool printOnce = true;
void LineDrawer_draw(LineDrawer *self, vec3 start, vec3 end,
vec3 color, float thickness)
{
if (!self)
return;
// Calculate direction vector and center
vec3 v, scaled_v, center;
glm_vec3_sub(end, start, v);
glm_vec3_scale(v, 0.5f, scaled_v); // v *= 0.5
glm_vec3_add(start, scaled_v, center);
// Find the length of the segment
float length = glm_vec3_norm(v); // length = glm.length(v)
// Normalize the segment vector
vec3 norm;
glm_vec3_normalize_to(v, norm); // norm = glm.normalize(v)
// Calculate rotation quaternion from (1,0,0) to norm
versor rotation;
vec3 x_axis = { 1.f, 0.f, 0.f };
// rotation = rotationTo((1,0,0), norm)
// glm_quat_for(x_axis, norm, rotation);
math_helper_rotation_to(x_axis, norm, rotation);
// Build model matrix
glm_mat4_identity(self->modelMatrix);
// Translation
glm_translate(self->modelMatrix, center);
// Rotation (convert quaternion to matrix)
glm_mat4_identity(self->rotationMatrix);
glm_quat_mat4(rotation, self->rotationMatrix);
// Apply rotation (now in local space)
glm_mat4_mul(self->modelMatrix, self->rotationMatrix, self->modelMatrix);
// Scaling
glm_scale(self->modelMatrix, (vec3) { length, thickness, thickness });
// Calculate MVP matrix: (projection * view) * model
glm_mat4_mul(self->projViewMatrix, self->modelMatrix, self->mvpMatrix);
// if (printOnce)
// {
// SDL_Log("\nPosition: %f, %f, %f", center[0], center[1], center[2]);
// SDL_Log("Quaternion: %f, %f, %f, %f\n", rotation[0], rotation[1], rotation[2], rotation[3]);
// SDL_Log("Scale: %f, %f, %f", length, thickness, thickness);
// printOnce = false;
// }
glBindBuffer(GL_ARRAY_BUFFER, self->vertPosBuffer);
glEnableVertexAttribArray(self->aPositionLocation);
glVertexAttribPointer(self->aPositionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glUseProgram(self->shaderProgram);
// Upload combined MVP matrix to shader
glUniformMatrix4fv(self->uMvpLocation, 1, GL_FALSE, self->mvpMatrix[0]);
// Upload color to shader
glUniform3fv(self->uColorLocation, 1, color);
// Draw the line
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void LineDrawer_cleanup(void)
{
free(instance);
instance = NULL;
}main.c#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <cglm/cglm.h>
#include <glad/glad.h>
#include "line-drawer.h"
#include "shader-program.h"
static SDL_Window *window = NULL;
SDL_GLContext glContext;
// Global matrices
mat4 projMatrix;
mat4 viewMatrix;
mat4 projViewMatrix;
GLuint shaderProgram;
LineDrawer *lineDrawer;
const char *vertexShaderSource =
"attribute vec3 aPosition;\n"
"uniform mat4 uMvpMatrix;\n"
"void main()\n"
"{\n"
" gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
"}\n";
const char *fragmentShaderSource =
"uniform vec3 uColor;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(uColor, 1.0);\n"
"}\n";
// This function runs once at startup
SDL_AppResult SDL_AppInit(void **appState, int argc, char *argv[])
{
if (!SDL_Init(SDL_INIT_VIDEO))
{
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); // can be 2, 4, 8 or 16
const char *title = "Example in C, SDL3, and OpenGL";
size_t canvasWidth = 350;
size_t canvasHeight = 350;
window = SDL_CreateWindow(title, canvasWidth, canvasHeight, SDL_WINDOW_OPENGL);
if (!window)
{
SDL_Log("Couldn't create the window: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
glContext = SDL_GL_CreateContext(window);
if (!glContext)
{
SDL_Log("Couldn't create the glContext: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_GL_SetSwapInterval(1); // Turn on vertical sync
if (!gladLoadGL())
{
SDL_Log("Failed to initialize OpenGL function pointers");
return SDL_APP_FAILURE;
}
glClearColor(50.f / 255.f, 50.f / 255.f, 50.f / 255.f, 1.f);
glViewport(0, 0, canvasWidth, canvasHeight);
GLuint shaderProgram = createShaderProgram(vertexShaderSource,
fragmentShaderSource);
if (!shaderProgram)
{
return SDL_APP_FAILURE;
}
// Set up orthographic projection
glm_ortho(-50.f, 50.f, -50.f, 50.f, -1.f, 1.f, projMatrix);
// Create the view matrix
vec3 eye = { 0.f, 0.f, 1.f }; // Camera position in world space
vec3 center = { 0.f, 0.f, 0.f }; // Point the camera is looking at
vec3 up = { 0.f, 1.f, 0.f }; // Up vector (typically world up)
glm_lookat(eye, center, up, viewMatrix);
// Create the projView matrix
glm_mat4_mul(projMatrix, viewMatrix, projViewMatrix); // proj * view
lineDrawer = LineDrawer_getInstance();
LineDrawer_init(lineDrawer, shaderProgram, projViewMatrix);
return SDL_APP_CONTINUE; // Carry on with the program
}
// This function runs when a new event (mouse input, keypresses, etc) occurs
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
{
switch (event->type)
{
case SDL_EVENT_QUIT:
{
return SDL_APP_SUCCESS;
break;
}
default:
break;
}
return SDL_APP_CONTINUE; // Carry on with the program
}
// This function runs once per frame, and is the heart of the program
SDL_AppResult SDL_AppIterate(void *appState)
{
glClear(GL_COLOR_BUFFER_BIT);
vec3 start = { -20.f, 20.f, 0.f };
vec3 end = { 25.f, 25.f, 0.f };
vec3 color = { 0.2f, 0.7f, 0.3f };
LineDrawer_draw(lineDrawer, start, end, color, 1.f);
memcpy(start, (vec3) { -30.f, -20.f, 0.f }, sizeof(vec3));
memcpy(end, (vec3) { 20.f, -30.f, 0.f }, sizeof(vec3));
memcpy(color, (vec3) { 0.9f, 0.5f, 0.5f }, sizeof(vec3));
LineDrawer_draw(lineDrawer, start, end, color, 5.f);
// Update the screen
SDL_GL_SwapWindow(window);
return SDL_APP_CONTINUE; // Carry on with the program
}
// This function runs once at shutdown
void SDL_AppQuit(void *appState, SDL_AppResult result)
{
// Cleanup OpenGL resources
glDeleteProgram(shaderProgram);
// Cleanup
LineDrawer_cleanup();
SDL_GL_DestroyContext(glContext);
// SDL will clean up the window for us
}shader-program.h#ifndef SHADER_PROGRAM_H
#define SHADER_PROGRAM_H
#include <glad/glad.h>
GLuint createShaderProgram(const char* vertexSource,
const char* fragmentSource);
#endif // SHADER_PROGRAM_Hshader-program.c#include "shader-program.h"
#include <SDL3/SDL.h>
GLuint compile_shader(const char *source, GLenum shaderType)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetShaderInfoLog(shader, 512, NULL, infoLog);
SDL_Log("Shader compilation failed:\n%s\n", infoLog);
SDL_Log("%s", source);
glDeleteShader(shader);
return 0;
}
return shader;
}
GLuint createShaderProgram(const char *vertexSource, const char *fragmentSource)
{
GLuint vertexShader = compile_shader(vertexSource, GL_VERTEX_SHADER);
if (!vertexShader)
{
return 0;
}
GLuint fragmentShader = compile_shader(fragmentSource, GL_FRAGMENT_SHADER);
if (!fragmentShader)
{
glDeleteShader(vertexShader);
return 0;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success)
{
char infoLog[512];
glGetProgramInfoLog(program, 512, NULL, infoLog);
SDL_Log("Shader program linking failed:\n%s\n", infoLog);
glDeleteProgram(program);
program = 0;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return program;
}CMakeLists.txtcmake_minimum_required(VERSION 3.21)
project(draw-line-cglm-opengl-sdl3-win-c LANGUAGES C)
add_executable(app WIN32)
target_include_directories(app PRIVATE ./libs/cglm-0.9.6/include)
target_include_directories(app PRIVATE ./libs/glad-2.0.8/include)
# Specify where the application source files are stored
target_sources(app
PRIVATE
./libs/glad-2.0.8/src/glad.c
src/line-drawer.h
src/line-drawer.c
src/main.c
src/math-helper.h
src/math-helper.c
src/shader-program.h
src/shader-program.c
)
find_package(SDL3)
target_link_libraries(app PRIVATE SDL3::SDL3)
# Copy the assets folder to the dist folder
#[===[
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets $<TARGET_FILE_DIR:app>/assets
COMMAND_EXPAND_LISTS
)
]===]
# This code copies DLL's to the dist directory
add_custom_command(TARGET app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_RUNTIME_DLLS:app> $<TARGET_FILE_DIR:app>
COMMAND_EXPAND_LISTS
)
# Block of comments
#[===[
This is a block of comments
]===]config.batcmake -G "MinGW Makefiles" -S . -B dist ^
-DSDL3_DIR=./libs/sdl-3.1.6-prefix/win/lib/cmake/SDL3 ^
-DCMAKE_BUILD_TYPE=Debugbuild.batcd dist
cmake --build .
cd .. |
Beta Was this translation helpful? Give feedback.




I solved the problem. glMatrix library has the
rotationTofunction: https://glmatrix.net/docs/quat.js.html#line652The C++ version of GLM does not have the same function. I just have rewritten the
rotationTofunction to C++ and Python. This function allow to find a quaternion betweenvec3 x_axis = { 1.f, 0.f, 0.f }and the unit line segment vector. So, I solved the problem with De…