how to draw a 3d right triangle
- The VAO
- Screen Coordinates
- Drawing our triangle
- Shaders
- Shader Compilation
- Our Vertex Shader
- Our Fragment Shader
- Putting it all together
This will be another long tutorial.
OpenGL 3 makes it easy to write complicated stuff, but at the expense that drawing a simple triangle is actually quite difficult.
Don't forget to cut'n paste the code on a regular basis.
If the program crashes at startup, you're probably running from the incorrect directory. Read Carefully the first tutorial and the FAQ on how to configure Visual Studio !
The VAO
I won't dig into details now, but you need to create a Vertex Array Object and set up it as the current ane :
GLuint VertexArrayID ; glGenVertexArrays ( one , & VertexArrayID ); glBindVertexArray ( VertexArrayID );
Practise this once your window is created (= afterwards the OpenGL Context cosmos) and before whatever other OpenGL call.
If you really desire to know more well-nigh VAOs, there are a few other tutorials out at that place, but this is non very important.
Screen Coordinates
A triangle is defined by iii points. When talking most "points" in 3D graphics, we usually utilize the word "vertex" ( "vertices" on the plural ). A vertex has iii coordinates : X, Y and Z. You can think about these three coordinates in the following style :
- X in on your correct
- Y is up
- Z is towards your back (yes, behind, not in front of y'all)
But hither is a better way to visualize this : use the Right Paw Rule
- X is your thumb
- Y is your index
- Z is your eye finger. If you put your pollex to the right and your index to the heaven, it will point to your back, too.
Having the Z in this direction is weird, so why is it so ? Short answer : because 100 years of Correct Mitt Rule Math will give you lots of useful tools. The just downside is an unintuitive Z.
On a side note, notice that you can move your mitt freely : your Ten, Y and Z will be moving, too. More on this later.
So we demand three 3D points in guild to brand a triangle ; allow's go :
// An array of 3 vectors which represents 3 vertices static const GLfloat g_vertex_buffer_data [] = { - 1.0 f , - 1.0 f , 0.0 f , 1.0 f , - ane.0 f , 0.0 f , 0.0 f , one.0 f , 0.0 f , };
The beginning vertex is (-i,-i,0). This means that unless we transform it in some way, information technology volition exist displayed at (-1,-1) on the screen. What does this hateful ? The screen origin is in the middle, X is on the correct, as usual, and Y is up. This is what it gives on a broad screen :
This is something you can't modify, information technology'due south built in your graphics card. So (-1,-1) is the bottom left corner of your screen. (i,-1) is the lesser right, and (0,one) is the heart meridian. So this triangle should have almost of the screen.
Drawing our triangle
The next step is to give this triangle to OpenGL. We practise this by creating a buffer:
// This volition place our vertex buffer GLuint vertexbuffer ; // Generate i buffer, put the resulting identifier in vertexbuffer glGenBuffers ( 1 , & vertexbuffer ); // The following commands will talk virtually our 'vertexbuffer' buffer glBindBuffer ( GL_ARRAY_BUFFER , vertexbuffer ); // Give our vertices to OpenGL. glBufferData ( GL_ARRAY_BUFFER , sizeof ( g_vertex_buffer_data ), g_vertex_buffer_data , GL_STATIC_DRAW );
This needs to be done only once.
At present, in our main loop, where nosotros used to draw "zip", we can draw our magnificent triangle :
// 1st aspect buffer : vertices glEnableVertexAttribArray ( 0 ); glBindBuffer ( GL_ARRAY_BUFFER , vertexbuffer ); glVertexAttribPointer ( 0 , // attribute 0. No item reason for 0, but must match the layout in the shader. 3 , // size GL_FLOAT , // type GL_FALSE , // normalized? 0 , // stride ( void * ) 0 // assortment buffer commencement ); // Draw the triangle ! glDrawArrays ( GL_TRIANGLES , 0 , 3 ); // Starting from vertex 0; 3 vertices full -> 1 triangle glDisableVertexAttribArray ( 0 );
If you're lucky, yous tin can run into the outcome in white. ( Don't panic if you don't some systems crave a shader to evidence anything) :
Now this is some wearisome white. Permit's see how nosotros tin amend it past painting information technology in red. This is done by using something called shaders.
Shaders
Shader Compilation
In the simplest possible configuration, you will demand 2 shaders : one called Vertex Shader, which volition be executed for each vertex, and i called Fragment Shader, which will be executed for each sample. And since we use 4x antialising, we have 4 samples in each pixel.
Shaders are programmed in a language chosen GLSL : GL Shader Language, which is part of OpenGL. Unlike C or Java, GLSL has to exist compiled at run time, which ways that each and every time y'all launch your application, all your shaders are recompiled.
The two shaders are unremarkably in separate files. In this example, nosotros have SimpleFragmentShader.fragmentshader and SimpleVertexShader.vertexshader . The extension is irrelevant, it could exist .txt or .glsl .
So here'southward the code. It's non very important to fully understand it, since you often do this but once in a program, and so comments should exist enough. Since this function volition be used by all other tutorials, it is placed in a carve up file : mutual/loadShader.cpp . Observe that just as buffers, shaders are not straight accessible : we but have an ID. The actual implementation is subconscious within the driver.
GLuint LoadShaders ( const char * vertex_file_path , const char * fragment_file_path ){ // Create the shaders GLuint VertexShaderID = glCreateShader ( GL_VERTEX_SHADER ); GLuint FragmentShaderID = glCreateShader ( GL_FRAGMENT_SHADER ); // Read the Vertex Shader code from the file std :: string VertexShaderCode ; std :: ifstream VertexShaderStream ( vertex_file_path , std :: ios :: in ); if ( VertexShaderStream . is_open ()){ std :: stringstream sstr ; sstr << VertexShaderStream . rdbuf (); VertexShaderCode = sstr . str (); VertexShaderStream . close (); } else { printf ( "Impossible to open up %s. Are you in the right directory ? Don't forget to read the FAQ ! \n " , vertex_file_path ); getchar (); render 0 ; } // Read the Fragment Shader code from the file std :: string FragmentShaderCode ; std :: ifstream FragmentShaderStream ( fragment_file_path , std :: ios :: in ); if ( FragmentShaderStream . is_open ()){ std :: stringstream sstr ; sstr << FragmentShaderStream . rdbuf (); FragmentShaderCode = sstr . str (); FragmentShaderStream . close (); } GLint Consequence = GL_FALSE ; int InfoLogLength ; // Compile Vertex Shader printf ( "Compiling shader : %s \due north " , vertex_file_path ); char const * VertexSourcePointer = VertexShaderCode . c_str (); glShaderSource ( VertexShaderID , 1 , & VertexSourcePointer , Cypher ); glCompileShader ( VertexShaderID ); // Cheque Vertex Shader glGetShaderiv ( VertexShaderID , GL_COMPILE_STATUS , & Result ); glGetShaderiv ( VertexShaderID , GL_INFO_LOG_LENGTH , & InfoLogLength ); if ( InfoLogLength > 0 ){ std :: vector < char > VertexShaderErrorMessage ( InfoLogLength + ane ); glGetShaderInfoLog ( VertexShaderID , InfoLogLength , NULL , & VertexShaderErrorMessage [ 0 ]); printf ( "%s \n " , & VertexShaderErrorMessage [ 0 ]); } // Compile Fragment Shader printf ( "Compiling shader : %s \n " , fragment_file_path ); char const * FragmentSourcePointer = FragmentShaderCode . c_str (); glShaderSource ( FragmentShaderID , 1 , & FragmentSourcePointer , Nada ); glCompileShader ( FragmentShaderID ); // Check Fragment Shader glGetShaderiv ( FragmentShaderID , GL_COMPILE_STATUS , & Result ); glGetShaderiv ( FragmentShaderID , GL_INFO_LOG_LENGTH , & InfoLogLength ); if ( InfoLogLength > 0 ){ std :: vector < char > FragmentShaderErrorMessage ( InfoLogLength + one ); glGetShaderInfoLog ( FragmentShaderID , InfoLogLength , NULL , & FragmentShaderErrorMessage [ 0 ]); printf ( "%s \n " , & FragmentShaderErrorMessage [ 0 ]); } // Link the program printf ( "Linking program \n " ); GLuint ProgramID = glCreateProgram (); glAttachShader ( ProgramID , VertexShaderID ); glAttachShader ( ProgramID , FragmentShaderID ); glLinkProgram ( ProgramID ); // Check the program glGetProgramiv ( ProgramID , GL_LINK_STATUS , & Result ); glGetProgramiv ( ProgramID , GL_INFO_LOG_LENGTH , & InfoLogLength ); if ( InfoLogLength > 0 ){ std :: vector < char > ProgramErrorMessage ( InfoLogLength + 1 ); glGetProgramInfoLog ( ProgramID , InfoLogLength , NULL , & ProgramErrorMessage [ 0 ]); printf ( "%s \n " , & ProgramErrorMessage [ 0 ]); } glDetachShader ( ProgramID , VertexShaderID ); glDetachShader ( ProgramID , FragmentShaderID ); glDeleteShader ( VertexShaderID ); glDeleteShader ( FragmentShaderID ); return ProgramID ; }
Our Vertex Shader
Allow'southward write our vertex shader kickoff. The first line tells the compiler that we will use OpenGL iii's syntax.
The second line declares the input data :
layout ( location = 0 ) in vec3 vertexPosition_modelspace ;
Let's explain this line in particular :
- "vec3" is a vector of 3 components in GLSL. Information technology is similar (but different) to the glm::vec3 nosotros used to declare our triangle. The important matter is that if we use three components in C++, we use 3 components in GLSL too.
- "layout(location = 0)" refers to the buffer we employ to feed the vertexPosition_modelspace attribute. Each vertex tin can take numerous attributes : A position, i or several colours, 1 or several texture coordinates, lots of other things. OpenGL doesn't know what a colour is : information technology just sees a vec3. Then nosotros have to tell him which buffer corresponds to which input. Nosotros do that by setting the layout to the same value as the first parameter to glVertexAttribPointer. The value "0" is not important, information technology could be 12 (but no more than than glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &v) ), the important thing is that information technology's the same number on both sides.
- "vertexPosition_modelspace" could have whatever other proper noun. Information technology will comprise the position of the vertex for each run of the vertex shader.
- "in" means that this is some input information. Soon we'll come across the "out" keyword.
The function that is called for each vertex is called master, just every bit in C :
Our chief part volition merely set the vertex' position to whatsoever was in the buffer. Then if we gave (1,one), the triangle would take one of its vertices at the top right corner of the screen. Nosotros'll come across in the adjacent tutorial how to exercise some more interesting computations on the input position.
gl_Position . xyz = vertexPosition_modelspace ; gl_Position . w = 1 . 0 ; }
gl_Position is one of the few born variables : y'all *accept *to assign some value to it. Everything else is optional; we'll see what "everything else" ways in Tutorial 4.
Our Fragment Shader
For our first fragment shader, nosotros will do something really unproblematic : gear up the color of each fragment to red. (Remember, in that location are 4 fragment in a pixel because we use 4x AA)
#version 330 core out vec3 color ; void primary (){ color = vec3 ( 1 , 0 , 0 ); }
And then yeah, vec3(1,0,0) means red. This is because on figurer screens, color is represented by a Red, Green, and Blue triplet, in this order. So (1,0,0) means Full Carmine, no greenish and no blue.
Putting information technology all together
Import our LoadShaders function every bit the terminal include:
#include <mutual/shader.hpp>
Before the principal loop, call our LoadShaders function:
// Create and compile our GLSL program from the shaders GLuint programID = LoadShaders ( "SimpleVertexShader.vertexshader" , "SimpleFragmentShader.fragmentshader" );
Now inside the main loop, beginning articulate the screen. This volition alter the background color to dark blue considering of the previous glClearColor(0.0f, 0.0f, 0.4f, 0.0f) call:
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
and then tell OpenGL that you desire to employ your shader:
// Utilize our shader glUseProgram ( programID ); // Describe triangle...
… and presto, hither'due south your red triangle !
In the adjacent tutorial nosotros'll learn transformations : How to setup your camera, move your objects, etc.
Source: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
0 Response to "how to draw a 3d right triangle"
Post a Comment