Linear Algebra – Sine & Cos (Working In Reverse)

Moving on from the last two tutorials, I’ve now moved the vectors over to the opposite side of the circle. I realised that the geometric relationships must be symmetric around the 360 degrees rotation, and so I’m now demonstrating how sine and cosine work in the reverse direction.

Ultimately, the triangular relationships remain the same, but it’s still worth watching my simple, yet beautiful animations running alongside each other – there’s nothing more revealing than a clear and concise visual explanation.

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(0.0f, 100.0f, 0.00001f); // -Z is into the screen.		
	glm::vec3 camera_target(0.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, 200.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 Y axis
		// ----------------------------------
		angle += 0.45f * direction;
		float angleB = glm::radians(angle);
 
		if (angle <= -70.0f || angle >= 70.0f)
		{
			direction = -direction;
			if (direction == 1)
				std::cout << "\n\n ******************** At Start Position... Direction changed";
			else
				std::cout << "\n\n ******************** At End Position... Direction changed";
		}		
		glm::vec2 axesXZ(glm::cos(angleB), glm::sin(angleB));
		glUniform2fv(cosine_sine_loc, 1, glm::value_ptr(axesXZ));
			
		glm::vec3 blue_vertex(-31.58f, 0.0f, -22.11f);
			
		float X = (glm::cos(angleB)) * blue_vertex.x + (glm::sin(angleB)) * blue_vertex.z;
		float Z = - (glm::sin(angleB)) * blue_vertex.x + (glm::cos(angleB)) * blue_vertex.z;
 
		std::cout << "\n\n   Manually Around Axis Y..... X: " << X << " --- Z: " << Z;
 
		// -----------------------------------------------------------		
 
		glm::mat4 rotate_Y(1.0f);
		rotate_Y = glm::rotate(rotate_YangleB, glm::vec3(0, 1, 0));
 
		blue_vertex = rotate_Y * glm::vec4(blue_vertex, 0.0f);
		std::cout << "\n   GLM Around Axis Y..... X: " << blue_vertex.x << " --- Z: " << blue_vertex.z;
 
		// -----------------------------------------------------------
 
		glClearColor(0.70f, 0.65f, 0.75f, 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.z);
	float Z = - (cosine_sine[1] * aPos.x)  +  (cosine_sine[0] * aPos.z);
	
	vec3 pos = aPos;
 
	if (mesh_number == 5 || mesh_number == 11) // 5 = Yellow vector... 11 = Blue vertex initial position.
		pos = vec3(X, aPos.y, Z);
 
	texture_coordinates = aTexCoord;	
	sampler_array_pos = aSamplerPos;
	vert_pos_transformed = pos;
	
	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;
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(-35.0, 150.0, -50.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;
 
	if (mesh_number == 17 || mesh_number == 18 || mesh_number == 19 || mesh_number == 24)
		fragment_colour = vec4(0.87, 0.92, 0.1, 1.0);
}