Linear Algebra - Rotating around the Z-Axis (Points | Vertices)

Quickly learn how to transform points is space. The visual illustrations provide you with a clear and precise appreciation of the geometric relationships involved in the calculations. Right-angled triangle trigonometry, accompanied with vector representations, help to provide an enjoyable learning process and intuitive understanding.

The code presented on this page is mostly intended for graphics programming enthusiasts, that would like to examine the code further, or even compile and run the program for themselves.

Source code: C++ from... main.cpp

#include <glad/glad.h>
#include <GLFW/glfw3.h>
 
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
 
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
 
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
 
#include <vector>
#include <iostream>
#include <fstream>
 
#include "shader_configure.h"
#include "load_meshes_binary.h"
 
int main()
{
	// (1) GLFW: Initialise & Configure
	// -----------------------------------------
	if (!glfwInit())
		exit(EXIT_FAILURE);
 
	glfwWindowHint(GLFW_SAMPLES, 4); // Anti-aliasing.
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_PROFILEGLFW_OPENGL_CORE_PROFILE);
	
	const GLFWvidmodemode = glfwGetVideoMode(glfwGetPrimaryMonitor());
 
	int monitor_width = mode->width;
	int monitor_height = mode->height;
 
	int window_width = (int)(monitor_width * 0.75f);
	int window_height = (int)(monitor_height * 0.75f);
 
	GLFWwindowwindow = glfwCreateWindow(window_widthwindow_height"Linear Algebra - Transformations Calculations"NULLNULL);
	// GLFWwindow* window = glfwCreateWindow(window_width, window_height, "Linear Algebra - Transformations Calculations", glfwGetPrimaryMonitor(), NULL); // Full Screen Mode ("Alt" + "F4" to Exit!)
 
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glfwMakeContextCurrent(window);
	glfwSetWindowPos(window, (monitor_width - window_width) / 2, (monitor_height - window_height) / 2);
 
	glfwSwapInterval(1); // Set VSync rate 1:1 with monitor's refresh rate.
 
	// (2) GLAD: Load OpenGL Function Pointers
	// -------------------------------------------------------
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_MULTISAMPLE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHAGL_ONE_MINUS_SRC_ALPHA);	
 
	// (3) Compile Shaders Read from Text Files
	// ------------------------------------------------------
	const charvert_shader = "../../Shaders/shader_glsl.vert";
	const charfrag_shader = "../../Shaders/shader_glsl.frag";
 
	Shader main_shader(vert_shaderfrag_shader);
	main_shader.use();	
	
	unsigned int view_matrix_loc = glGetUniformLocation(main_shader.ID, "view");
	unsigned int projection_matrix_loc = glGetUniformLocation(main_shader.ID, "projection");
	unsigned int camera_position_loc = glGetUniformLocation(main_shader.ID, "camera_position");
	
	glm::vec3 camera_position(35.0f, 0.0f, 100.0f); // -Z is into the screen.		
	glm::vec3 camera_target(35.0f, 0.0f, 0.0f);
	glm::vec3 camera_up(0.0f, 1.0f, 0.0f);
 
	glUniform3f(camera_position_loccamera_position.x, camera_position.y, camera_position.z);
 
	glm::mat4 view = glm::lookAt(camera_positioncamera_targetcamera_up);
	glUniformMatrix4fv(view_matrix_loc, 1, GL_FALSE, glm::value_ptr(view));
 
	glm::mat4 projection = glm::perspective(glm::radians(55.0f), (float)window_width / (float)window_height, 1.0f, 500.0f);
	glUniformMatrix4fv(projection_matrix_loc, 1, GL_FALSE, glm::value_ptr(projection));
	
	Model transformations_axes("Object & Material Files\\transformations_axes.obj"main_shader, 0);
	unsigned int cosine_sine_loc = glGetUniformLocation(main_shader.ID, "cosine_sine");
 
	float angle = 0.0f;
	int direction = 1;
 
	while (!glfwWindowShouldClose(window)) // Main-Loop
	{			
		// Rotating around the Z axis
		// ----------------------------------
		angle += 0.25f * direction;
		float angleC = glm::radians(angle);
 
		if (angle <= 0.0f || angle >= 47.0f)
		{
			direction = -direction;
			std::cout << "\n\n ********************   Direction changed";
		}		
		glm::vec2 axesXY(glm::cos(angleC), glm::sin(angleC));
		glUniform2fv(cosine_sine_loc, 1, glm::value_ptr(axesXY));
 
		glm::vec3 orange_vertex(-13.44f, 36.87f, 0.0f);
 
		float X = (glm::cos(angleC)) * orange_vertex.x - (glm::sin(angleC)) * orange_vertex.y;
		float Y = (glm::sin(angleC)) * orange_vertex.x + (glm::cos(angleC)) * orange_vertex.y;
		std::cout << "\n\n   Manually Around Axis Z..... X: " << X << " --- Y: " << Y;
 
		// -----------------------------------------------------------
 
		glm::vec3 orange_vertex_copy = orange_vertex;
 
		glm::mat4 rotate_Z(1.0f);
		rotate_Z = glm::rotate(rotate_ZangleC, glm::vec3(0, 0, 1));
 
		orange_vertex_copy = rotate_Z * glm::vec4(orange_vertex_copy, 0.0f);
		std::cout << "\n   GLM..... orange_vertex_copy.x: " << orange_vertex_copy.x << " --- orange_vertex_copy.y: " << orange_vertex_copy.y;
 
		// -----------------------------------------------------------
 
		glClearColor(0.30f, 0.55f, 0.65f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		transformations_axes.process_draw_calls();
		
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glDeleteProgram(main_shader.ID);	
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

Source code: C++ from... shader_configure.h & load_meshes_binary.h

These two source-code header files are quite long, and therefore will further distract attention away from the relevant key few lines of code required as highlighted in the video. click here to acquire the shader configure file & load meshes file if you're interested in seeing/compiling the complete source code.


Source code: GLSL from... shader_glsl.vert (Vertex shader)

#version 420 core
			
layout (location = 0) in vec3 aPos;	
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
layout (location = 3) in unsigned int aMeshNum;
layout (location = 4) in unsigned int aSamplerPos;
 
out vec3 vert_pos_transformed; // Transformed vertex position coordinates also passed as interpolated.
out vec2 texture_coordinates;
out vec3 vertex_normal;
flat out unsigned int mesh_number; // Can be used to identify and transform meshes independently of one another.
flat out unsigned int sampler_array_pos;
 
uniform int rendering_multiple_meshes;
 
uniform mat4 view;
uniform mat4 projection;
 
uniform vec2 cosine_sine;
 
void main()
{
	if (rendering_multiple_meshes == -1)
		mesh_number = aMeshNum; // Receive mesh number via input attribute.
	else
		mesh_number = rendering_multiple_meshes; // For draw method option 0... Receive mesh number via uniform.
		
	float X = (cosine_sine[0] * aPos.x)  -  (cosine_sine[1] * aPos.y);
	float Y = (cosine_sine[1] * aPos.x)  +  (cosine_sine[0] * aPos.y);
	
	vec3 pos = aPos;
 
	if (mesh_number == 3 || mesh_number == 13) // 3 = Yellow vector... 13 = Orange vertex initial position.
		pos = vec3(X, Y, aPos.z);
 
	texture_coordinates = aTexCoord;	
	sampler_array_pos = aSamplerPos;
	vert_pos_transformed = aPos;
	
	vertex_normal = normalize(aNormal); // Not bothering to rotate the normals of the animated vector. 
 
	gl_Position = projection * view * vec4(pos, 1.0);
}

Source code: GLSL from... shader_glsl.frag (Fragment shader)

#version 420 core
			
out vec4 fragment_colour;
 
in vec3 vert_pos_transformed; // Transformed vertex position coordinates received as interpolated.
in vec2 texture_coordinates;
in vec3 vertex_normal;
flat in unsigned int mesh_number; // Not being used.
flat in unsigned int sampler_array_pos; // Used to select the correct image from the images[] array.
 
uniform bool meshes_combined;
uniform sampler2D images[32]; // Array of sampler images.
 
uniform vec3 camera_position; // -Z is into the screen... camera_position is set in main() on CPU side.
 
void main()
{	
	unsigned int index = 0;
	// --------------------------
	if (meshes_combined)
		index = sampler_array_pos;
 
	vec3 view_direction = normalize(camera_position - vert_pos_transformed);
 
	vec3 light_position = vec3(-40.0, 45.0, 120.0);
	vec3 light_direction = normalize(vec3(light_position - vert_pos_transformed));	
	
	vec4 image_colour = texture(images[index], texture_coordinates);
 
	float ambient_factor = 0.35;
	vec4 ambient_result = vec4(ambient_factor * image_colour.rgb, 1.0);
 
	float diffuse_factor = 0.65;
	float diffuse_angle = max(dot(light_direction, vertex_normal), -0.0); // [-1.0 to 0] down to -1 results in darker lighting past 90 degrees.
	vec4 diffuse_result =  vec4(diffuse_factor * diffuse_angle * image_colour.rgb, 1.0);	
		
	vec3 specular_colour = vec3(0.35, 0.35, 0.35);
	vec3 reflect_direction = normalize(reflect(-light_direction, vertex_normal)); // Light direction is negated here.
	float specular_strength = pow(max(dot(view_direction, reflect_direction), 0), 16);
	vec4 specular_result = vec4(specular_colour * specular_strength, 1.0);
 
	fragment_colour = ambient_result + diffuse_result + specular_result;	
}