The goal is to create a torus from its parametric equation.
x(θ,φ) = (R + rcosθ) cos φ
y(θ,φ) = (R + rcosθ) sin φ
z(θ,φ) = rsinθ
"With the above equation it is straightforward to generate triangles around the surface of the torus: you will simply vary the parameters of the equation by constant intervals in order to get points in the surface and connect them forming triangles. You will build a parametric torus object based on parameters r and R, and also controlling the resolution (number of triangles) of your approximation."
"You will use the torus parametric equation to build a torus based on 3 parameters: r, R, and n, where n controls the number of triangles that are generated."
"The number of triangles does not need to be parameterized exactly. Parameter n just needs to control the resolution in a way to properly control a finer or coarser subdivision of the surface in triangles. You will typically have two nested for loops to vary the 2 parameters (r and R) of the parametric equation, and n will control how large are the increments applied to the two parameters of the for loops. As triangles are created, “push” them to an array to be sent to OpenGL. You will likely want to use a dynamically sized structure like a vector."
"Note 1: For the built-in OpenGL “back-face culling” to work properly, one has to make sure the order of the vertices in each triangle is always counter-clockwise, when seen from outside the torus. This is almost always an important thing to get right in Computer Graphics."
The following is the code I have so far.
There are two sets of double for-loops. The first set is meant to collect the points from the parametric equations. The second is meant to set them into vectors as triangles: a certain amount for every ring forming the torus.
Each vertex follows the following coordinate scheme: (x, y, z, w = 1.0f).
#include #include #include #include #include #include "shader.h" #include "shaderprogram.h" #include #include #define PI 3.14159265 /*================================================================================================= DOMAIN =================================================================================================*/ // Window dimensions const int InitWindowWidth = 800; const int InitWindowHeight = 800; int WindowWidth = InitWindowWidth; int WindowHeight = InitWindowHeight; // Last mouse cursor position int LastMousePosX = 0; int LastMousePosY = 0; // Arrays that track which keys are currently pressed bool key_states[256]; bool key_special_states[256]; bool mouse_states[8]; // Other parameters bool draw_wireframe = false; // Parameters: float X_Point, Y_Point, Z_Point; float R = 50.0f; float r = 5.0f; float entry = 5.0f; float n = 4.0f + entry; /*================================================================================================= SHADERS & TRANSFORMATIONS =================================================================================================*/ ShaderProgram PassthroughShader; ShaderProgram PerspectiveShader; glm::mat4 PerspProjectionMatrix( 1.0f ); glm::mat4 PerspViewMatrix( 1.0f ); glm::mat4 PerspModelMatrix( 1.0f ); float perspZoom = 1.0f, perspSensitivity = 0.35f; float perspRotationX = 0.0f, perspRotationY = 0.0f; /*================================================================================================= OBJECTS =================================================================================================*/ //VAO -> the object "as a whole", the collection of buffers that make up its data //VBOs -> the individual buffers/arrays with data, for ex: one for coordinates, one for color, etc. GLuint axis_VAO; GLuint axis_VBO[2]; float axis_vertices[] = { //x axis -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, //y axis 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //z axis 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; float axis_colors[] = { //x axis 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, //y axis 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //z axis 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; GLuint torus_VAO; GLuint torus_VBO[2]; std::vector torus_points_x; std::vector torus_points; std::vector torus_vertices; std::vector torus_colors; void generate_torus(void) // My custom function { for (float OuterRingAngle = 0.0f; OuterRingAngle < 2.0f * PI; OuterRingAngle += 2*PI/n) { for (float InnerRingAngle = 0.0f; InnerRingAngle < 2.0f * PI; InnerRingAngle += 2*PI/n) { // The parametric equations X_Point = (R + (r * cos(InnerRingAngle))) * cos(OuterRingAngle); Y_Point = (R + (r * cos(InnerRingAngle))) * sin(OuterRingAngle); Z_Point = r * sin(InnerRingAngle); torus_points.push_back(X_Point); torus_points.push_back(Y_Point); torus_points.push_back(Z_Point); } } // Each link of the ring is composed of two triangles (composed of 4 coordinates each). n should multiply the amount of the links: the higher n, the smoother the torus. for (float RingSegment = 0.0f; RingSegment < n; RingSegment++) { for (float RingVert = 0.0f; RingVert < 1.0f; RingVert++) { // Triangle 1 torus_vertices.push_back( torus_points[RingVert] ); torus_vertices.push_back( torus_points[RingVert + 1.0f] ); torus_vertices.push_back( torus_points[RingVert + n] ); torus_vertices.push_back(1.0f); //Triangle 2 torus_vertices.push_back( torus_points[RingVert + 1.0f] ); torus_vertices.push_back( torus_points[RingVert + 2.0f] ); torus_vertices.push_back( torus_points[RingVert + n + 1.0f] ); torus_vertices.push_back(1.0f); // Their colors (r,b,g,a) torus_colors.push_back(1.0f); torus_colors.push_back(0.5f); torus_colors.push_back(0.3f); torus_colors.push_back(1.0f); torus_colors.push_back(0.6f); torus_colors.push_back(0.3f); torus_colors.push_back(0.23f); torus_colors.push_back(1.0f); } } } /*================================================================================================= HELPER FUNCTIONS =================================================================================================*/ void window_to_scene( int wx, int wy, float& sx, float& sy ) { sx = ( 2.0f * (float)wx / WindowWidth ) - 1.0f; sy = 1.0f - ( 2.0f * (float)wy / WindowHeight ); } /*================================================================================================= SHADERS =================================================================================================*/ void CreateTransformationMatrices( void ) { // PROJECTION MATRIX PerspProjectionMatrix = glm::perspective( glm::radians( 60.0f ), (float)WindowWidth / (float)WindowHeight, 0.01f, 1000.0f ); // VIEW MATRIX glm::vec3 eye ( 0.0, 0.0, 2.0 ); glm::vec3 center( 0.0, 0.0, 0.0 ); glm::vec3 up ( 0.0, 1.0, 0.0 ); PerspViewMatrix = glm::lookAt( eye, center, up ); // MODEL MATRIX PerspModelMatrix = glm::mat4( 1.0 ); PerspModelMatrix = glm::rotate( PerspModelMatrix, glm::radians( perspRotationX ), glm::vec3( 1.0, 0.0, 0.0 ) ); PerspModelMatrix = glm::rotate( PerspModelMatrix, glm::radians( perspRotationY ), glm::vec3( 0.0, 1.0, 0.0 ) ); PerspModelMatrix = glm::scale( PerspModelMatrix, glm::vec3( perspZoom ) ); } void CreateShaders( void ) { // Renders without any transformations PassthroughShader.Create( "./shaders/simple.vert", "./shaders/simple.frag" ); // Renders using perspective projection PerspectiveShader.Create( "./shaders/persp.vert", "./shaders/persp.frag" ); } /*================================================================================================= BUFFERS =================================================================================================*/ void CreateAxisBuffers( void ) { glGenVertexArrays( 1, &axis_VAO ); //generate 1 new VAO, its ID is returned in axis_VAO glBindVertexArray( axis_VAO ); //bind the VAO so the subsequent commands modify it glGenBuffers( 2, &axis_VBO[0] ); //generate 2 buffers for data, their IDs are returned to the axis_VBO array // first buffer: vertex coordinates glBindBuffer( GL_ARRAY_BUFFER, axis_VBO[0] ); //bind the first buffer using its ID glBufferData( GL_ARRAY_BUFFER, sizeof( axis_vertices ), axis_vertices, GL_STATIC_DRAW ); //send coordinate array to the GPU glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof( float ), (void*)0 ); //let GPU know this is attribute 0, made up of 4 floats glEnableVertexAttribArray( 0 ); // second buffer: colors glBindBuffer( GL_ARRAY_BUFFER, axis_VBO[1] ); //bind the second buffer using its ID glBufferData( GL_ARRAY_BUFFER, sizeof( axis_colors ), axis_colors, GL_STATIC_DRAW ); //send color array to the GPU glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof( float ), (void*)0 ); //let GPU know this is attribute 1, made up of 4 floats glEnableVertexAttribArray( 1 ); glBindVertexArray( 0 ); //unbind when done //NOTE: You will probably not use an array for your own objects, as you will need to be // able to dynamically resize the number of vertices. Remember that the sizeof() // operator will not give an accurate answer on an entire vector. Instead, you will // have to do a calculation such as sizeof(v[0]) * v.size(). } void CreateTorusBuffers(void) { generate_torus(); // My custom function called. glGenVertexArrays(1, &torus_VAO); //generate 1 new VAO, its ID is returned in axis_VAO glBindVertexArray(torus_VAO); //bind the VAO so the subsequent commands modify it glGenBuffers(2, &torus_VBO[0]); //generate 2 buffers for data, their IDs are returned to the axis_VBO array // first buffer: vertex coordinates glBindBuffer(GL_ARRAY_BUFFER, torus_VBO[0]); //bind the first buffer using its ID glBufferData(GL_ARRAY_BUFFER, sizeof(torus_points), torus_points.data(), GL_STATIC_DRAW); //send coordinate array to the GPU glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); //let GPU know this is attribute 0, made up of 4 floats glEnableVertexAttribArray(0); // second buffer: colors glBindBuffer(GL_ARRAY_BUFFER, torus_VBO[1]); //bind the second buffer using its ID glBufferData(GL_ARRAY_BUFFER, sizeof(torus_colors), torus_colors.data(), GL_STATIC_DRAW); //send color array to the GPU glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); //let GPU know this is attribute 1, made up of 4 floats glEnableVertexAttribArray(1); glBindVertexArray(0); //unbind when done } /*================================================================================================= CALLBACKS =================================================================================================*/ //----------------------------------------------------------------------------- // CALLBACK DOCUMENTATION // https://www.opengl.org/resources/librar ... ode45.html // http://freeglut.sourceforge.net/docs/ap ... owCallback //----------------------------------------------------------------------------- void idle_func() { //uncomment below to repeatedly draw new frames glutPostRedisplay(); } void reshape_func( int width, int height ) { WindowWidth = width; WindowHeight = height; glViewport( 0, 0, width, height ); glutPostRedisplay(); } void keyboard_func( unsigned char key, int x, int y ) { key_states[ key ] = true; switch( key ) { case 'q': { entry++; break; } case 'a': { entry--; break; } case 'w': { r += 5; break; } case 's': { r -= 5; break; } case 'e': { R += 5; break; } case 'd': { R -= 5; break; } case 'x': { draw_wireframe = !draw_wireframe; if (draw_wireframe == true) std::cout WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); if( button == 3 ) { perspZoom += 0.03f; } else if( button == 4 ) { if( perspZoom - 0.03f > 0.0f ) perspZoom -= 0.03f; } mouse_states[ button ] = ( state == GLUT_DOWN ); LastMousePosX = x; LastMousePosY = y; } void passive_motion_func( int x, int y ) { if( x < 0 || x > WindowWidth || y < 0 || y > WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); LastMousePosX = x; LastMousePosY = y; } void active_motion_func( int x, int y ) { if( x < 0 || x > WindowWidth || y < 0 || y > WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); if( mouse_states[0] == true ) { perspRotationY += ( x - LastMousePosX ) * perspSensitivity; perspRotationX += ( y - LastMousePosY ) * perspSensitivity; } LastMousePosX = x; LastMousePosY = y; } /*================================================================================================= RENDERING =================================================================================================*/ void display_func( void ) { // Clear the contents of the back buffer glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Update transformation matrices CreateTransformationMatrices(); // Choose which shader to user, and send the transformation matrix information to it PerspectiveShader.Use(); PerspectiveShader.SetUniform( "projectionMatrix", glm::value_ptr( PerspProjectionMatrix ), 4, GL_FALSE, 1 ); PerspectiveShader.SetUniform( "viewMatrix", glm::value_ptr( PerspViewMatrix ), 4, GL_FALSE, 1 ); PerspectiveShader.SetUniform( "modelMatrix", glm::value_ptr( PerspModelMatrix ), 4, GL_FALSE, 1 ); // Drawing in wireframe? if( draw_wireframe == true ) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); else glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); // Bind the axis Vertex Array Object created earlier, and draw it glBindVertexArray( axis_VAO ); glDrawArrays( GL_LINES, 0, 6 ); // 6 = number of vertices in the object // The Torus Bound and Sent glBindVertexArray(torus_VAO); glDrawArrays(GL_TRIANGLES, 0, n*3); // n triangles; 3 vertices each. // Unbind when done glBindVertexArray( 0 ); // Swap the front and back buffers glutSwapBuffers(); } /*================================================================================================= INIT =================================================================================================*/ void init( void ) { // Print some info std::cout
The goal is to create a torus from its parametric equation. [list] [*] x(θ,φ) = (R + rcosθ) cos φ [*] y(θ,φ) = (R + rcosθ) sin φ [*] z(θ,φ) = rsinθ
"With the above equation it is straightforward to generate triangles around the surface of the torus: you will simply vary the parameters of the equation by constant intervals in order to get points in the surface and connect them forming triangles. You will build a parametric torus object based on parameters r and R, and also controlling the resolution (number of triangles) of your approximation."
"You will use the torus parametric equation to build a torus based on 3 parameters: r, R, and n, where n controls the number of triangles that are generated."
"The number of triangles does not need to be parameterized exactly. Parameter n just needs to control the resolution in a way to properly control a finer or coarser subdivision of the surface in triangles. You will typically have two nested for loops to vary the 2 parameters (r and R) of the parametric equation, and n will control how large are the increments applied to the two parameters of the for loops. As triangles are created, “push” them to an array to be sent to OpenGL. You will likely want to use a dynamically sized structure like a vector."
"Note 1: For the built-in OpenGL “back-face culling” to work properly, one has to make sure the order of the vertices in each triangle is always counter-clockwise, when seen from outside the torus. This is almost always an important thing to get right in Computer Graphics."
The following is the code I have so far.
There are two sets of double for-loops. The first set is meant to collect the points from the parametric equations. The second is meant to set them into vectors as triangles: a certain amount for every ring forming the torus.
Each vertex follows the following coordinate scheme: (x, y, z, w = 1.0f). [/list] #include #include #include #include #include #include "shader.h" #include "shaderprogram.h" #include #include #define PI 3.14159265 /*================================================================================================= DOMAIN =================================================================================================*/ // Window dimensions const int InitWindowWidth = 800; const int InitWindowHeight = 800; int WindowWidth = InitWindowWidth; int WindowHeight = InitWindowHeight; // Last mouse cursor position int LastMousePosX = 0; int LastMousePosY = 0; // Arrays that track which keys are currently pressed bool key_states[256]; bool key_special_states[256]; bool mouse_states[8]; // Other parameters bool draw_wireframe = false; // Parameters: float X_Point, Y_Point, Z_Point; float R = 50.0f; float r = 5.0f; float entry = 5.0f; float n = 4.0f + entry; /*================================================================================================= SHADERS & TRANSFORMATIONS =================================================================================================*/ ShaderProgram PassthroughShader; ShaderProgram PerspectiveShader; glm::mat4 PerspProjectionMatrix( 1.0f ); glm::mat4 PerspViewMatrix( 1.0f ); glm::mat4 PerspModelMatrix( 1.0f ); float perspZoom = 1.0f, perspSensitivity = 0.35f; float perspRotationX = 0.0f, perspRotationY = 0.0f; /*================================================================================================= OBJECTS =================================================================================================*/ //VAO -> the object "as a whole", the collection of buffers that make up its data //VBOs -> the individual buffers/arrays with data, for ex: one for coordinates, one for color, etc. GLuint axis_VAO; GLuint axis_VBO[2]; float axis_vertices[] = { //x axis -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, //y axis 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //z axis 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; float axis_colors[] = { //x axis 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, //y axis 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, //z axis 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; GLuint torus_VAO; GLuint torus_VBO[2]; std::vector torus_points_x; std::vector torus_points; std::vector torus_vertices; std::vector torus_colors; void generate_torus(void) // My custom function { for (float OuterRingAngle = 0.0f; OuterRingAngle < 2.0f * PI; OuterRingAngle += 2*PI/n) { for (float InnerRingAngle = 0.0f; InnerRingAngle < 2.0f * PI; InnerRingAngle += 2*PI/n) { // The parametric equations X_Point = (R + (r * cos(InnerRingAngle))) * cos(OuterRingAngle); Y_Point = (R + (r * cos(InnerRingAngle))) * sin(OuterRingAngle); Z_Point = r * sin(InnerRingAngle); torus_points.push_back(X_Point); torus_points.push_back(Y_Point); torus_points.push_back(Z_Point); } } // Each link of the ring is composed of two triangles (composed of 4 coordinates each). n should multiply the amount of the links: the higher n, the smoother the torus. for (float RingSegment = 0.0f; RingSegment < n; RingSegment++) { for (float RingVert = 0.0f; RingVert < 1.0f; RingVert++) { // Triangle 1 torus_vertices.push_back( torus_points[RingVert] ); torus_vertices.push_back( torus_points[RingVert + 1.0f] ); torus_vertices.push_back( torus_points[RingVert + n] ); torus_vertices.push_back(1.0f); //Triangle 2 torus_vertices.push_back( torus_points[RingVert + 1.0f] ); torus_vertices.push_back( torus_points[RingVert + 2.0f] ); torus_vertices.push_back( torus_points[RingVert + n + 1.0f] ); torus_vertices.push_back(1.0f); // Their colors (r,b,g,a) torus_colors.push_back(1.0f); torus_colors.push_back(0.5f); torus_colors.push_back(0.3f); torus_colors.push_back(1.0f); torus_colors.push_back(0.6f); torus_colors.push_back(0.3f); torus_colors.push_back(0.23f); torus_colors.push_back(1.0f); } } } /*================================================================================================= HELPER FUNCTIONS =================================================================================================*/ void window_to_scene( int wx, int wy, float& sx, float& sy ) { sx = ( 2.0f * (float)wx / WindowWidth ) - 1.0f; sy = 1.0f - ( 2.0f * (float)wy / WindowHeight ); } /*================================================================================================= SHADERS =================================================================================================*/ void CreateTransformationMatrices( void ) { // PROJECTION MATRIX PerspProjectionMatrix = glm::perspective( glm::radians( 60.0f ), (float)WindowWidth / (float)WindowHeight, 0.01f, 1000.0f ); // VIEW MATRIX glm::vec3 eye ( 0.0, 0.0, 2.0 ); glm::vec3 center( 0.0, 0.0, 0.0 ); glm::vec3 up ( 0.0, 1.0, 0.0 ); PerspViewMatrix = glm::lookAt( eye, center, up ); // MODEL MATRIX PerspModelMatrix = glm::mat4( 1.0 ); PerspModelMatrix = glm::rotate( PerspModelMatrix, glm::radians( perspRotationX ), glm::vec3( 1.0, 0.0, 0.0 ) ); PerspModelMatrix = glm::rotate( PerspModelMatrix, glm::radians( perspRotationY ), glm::vec3( 0.0, 1.0, 0.0 ) ); PerspModelMatrix = glm::scale( PerspModelMatrix, glm::vec3( perspZoom ) ); } void CreateShaders( void ) { // Renders without any transformations PassthroughShader.Create( "./shaders/simple.vert", "./shaders/simple.frag" ); // Renders using perspective projection PerspectiveShader.Create( "./shaders/persp.vert", "./shaders/persp.frag" ); } /*================================================================================================= BUFFERS =================================================================================================*/ void CreateAxisBuffers( void ) { glGenVertexArrays( 1, &axis_VAO ); //generate 1 new VAO, its ID is returned in axis_VAO glBindVertexArray( axis_VAO ); //bind the VAO so the subsequent commands modify it glGenBuffers( 2, &axis_VBO[0] ); //generate 2 buffers for data, their IDs are returned to the axis_VBO array // first buffer: vertex coordinates glBindBuffer( GL_ARRAY_BUFFER, axis_VBO[0] ); //bind the first buffer using its ID glBufferData( GL_ARRAY_BUFFER, sizeof( axis_vertices ), axis_vertices, GL_STATIC_DRAW ); //send coordinate array to the GPU glVertexAttribPointer( 0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof( float ), (void*)0 ); //let GPU know this is attribute 0, made up of 4 floats glEnableVertexAttribArray( 0 ); // second buffer: colors glBindBuffer( GL_ARRAY_BUFFER, axis_VBO[1] ); //bind the second buffer using its ID glBufferData( GL_ARRAY_BUFFER, sizeof( axis_colors ), axis_colors, GL_STATIC_DRAW ); //send color array to the GPU glVertexAttribPointer( 1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof( float ), (void*)0 ); //let GPU know this is attribute 1, made up of 4 floats glEnableVertexAttribArray( 1 ); glBindVertexArray( 0 ); //unbind when done //NOTE: You will probably not use an array for your own objects, as you will need to be // able to dynamically resize the number of vertices. Remember that the sizeof() // operator will not give an accurate answer on an entire vector. Instead, you will // have to do a calculation such as sizeof(v[0]) * v.size(). } void CreateTorusBuffers(void) { generate_torus(); // My custom function called. glGenVertexArrays(1, &torus_VAO); //generate 1 new VAO, its ID is returned in axis_VAO glBindVertexArray(torus_VAO); //bind the VAO so the subsequent commands modify it glGenBuffers(2, &torus_VBO[0]); //generate 2 buffers for data, their IDs are returned to the axis_VBO array // first buffer: vertex coordinates glBindBuffer(GL_ARRAY_BUFFER, torus_VBO[0]); //bind the first buffer using its ID glBufferData(GL_ARRAY_BUFFER, sizeof(torus_points), torus_points.data(), GL_STATIC_DRAW); //send coordinate array to the GPU glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); //let GPU know this is attribute 0, made up of 4 floats glEnableVertexAttribArray(0); // second buffer: colors glBindBuffer(GL_ARRAY_BUFFER, torus_VBO[1]); //bind the second buffer using its ID glBufferData(GL_ARRAY_BUFFER, sizeof(torus_colors), torus_colors.data(), GL_STATIC_DRAW); //send color array to the GPU glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); //let GPU know this is attribute 1, made up of 4 floats glEnableVertexAttribArray(1); glBindVertexArray(0); //unbind when done } /*================================================================================================= CALLBACKS =================================================================================================*/ //----------------------------------------------------------------------------- // CALLBACK DOCUMENTATION // https://www.opengl.org/resources/libraries/glut/spec3/node45.html // http://freeglut.sourceforge.net/docs/api.php#WindowCallback //----------------------------------------------------------------------------- void idle_func() { //uncomment below to repeatedly draw new frames glutPostRedisplay(); } void reshape_func( int width, int height ) { WindowWidth = width; WindowHeight = height; glViewport( 0, 0, width, height ); glutPostRedisplay(); } void keyboard_func( unsigned char key, int x, int y ) { key_states[ key ] = true; switch( key ) { case 'q': { entry++; break; } case 'a': { entry--; break; } case 'w': { r += 5; break; } case 's': { r -= 5; break; } case 'e': { R += 5; break; } case 'd': { R -= 5; break; } case 'x': { draw_wireframe = !draw_wireframe; if (draw_wireframe == true) std::cout WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); if( button == 3 ) { perspZoom += 0.03f; } else if( button == 4 ) { if( perspZoom - 0.03f > 0.0f ) perspZoom -= 0.03f; } mouse_states[ button ] = ( state == GLUT_DOWN ); LastMousePosX = x; LastMousePosY = y; } void passive_motion_func( int x, int y ) { if( x < 0 || x > WindowWidth || y < 0 || y > WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); LastMousePosX = x; LastMousePosY = y; } void active_motion_func( int x, int y ) { if( x < 0 || x > WindowWidth || y < 0 || y > WindowHeight ) return; float px, py; window_to_scene( x, y, px, py ); if( mouse_states[0] == true ) { perspRotationY += ( x - LastMousePosX ) * perspSensitivity; perspRotationX += ( y - LastMousePosY ) * perspSensitivity; } LastMousePosX = x; LastMousePosY = y; } /*================================================================================================= RENDERING =================================================================================================*/ void display_func( void ) { // Clear the contents of the back buffer glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Update transformation matrices CreateTransformationMatrices(); // Choose which shader to user, and send the transformation matrix information to it PerspectiveShader.Use(); PerspectiveShader.SetUniform( "projectionMatrix", glm::value_ptr( PerspProjectionMatrix ), 4, GL_FALSE, 1 ); PerspectiveShader.SetUniform( "viewMatrix", glm::value_ptr( PerspViewMatrix ), 4, GL_FALSE, 1 ); PerspectiveShader.SetUniform( "modelMatrix", glm::value_ptr( PerspModelMatrix ), 4, GL_FALSE, 1 ); // Drawing in wireframe? if( draw_wireframe == true ) glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); else glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); // Bind the axis Vertex Array Object created earlier, and draw it glBindVertexArray( axis_VAO ); glDrawArrays( GL_LINES, 0, 6 ); // 6 = number of vertices in the object // The Torus Bound and Sent glBindVertexArray(torus_VAO); glDrawArrays(GL_TRIANGLES, 0, n*3); // n triangles; 3 vertices each. // Unbind when done glBindVertexArray( 0 ); // Swap the front and back buffers glutSwapBuffers(); } /*================================================================================================= INIT =================================================================================================*/ void init( void ) { // Print some info std::cout