您的位置:首页 > 运维架构

OpenGL Superbible 7 02 Our First OpenGL Program

2017-05-04 01:52 501 查看
01 学习目标

(1) How to create and compile shader code

(2) How to draw with OpenGL

(3) How to use the book's application framework to initialize your programs and clean up after yourself.

02. 程序框架

To create an application, we simply include sb7, derive a class from sb7::application, and, in exactly one of our source files, include an instance of the DECLARE_MAIN macro.This defines the main entry
point of out application, which create an instance of our class
(the type of which is passed as a parameter to the macro) and calls its run() method, which implements the application's main loop.

virtual void run(sb7::application* the_app)
{
bool running = true;
app = the_app;

if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return;
}

init();

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, info.majorVersion);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, info.minorVersion);

#ifndef _DEBUG
if (info.flags.debug)
#endif /* _DEBUG */
{
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
}
if (info.flags.robust)
{
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, GLFW_LOSE_CONTEXT_ON_RESET);
}
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, info.samples);
glfwWindowHint(GLFW_STEREO, info.flags.stereo ? GL_TRUE : GL_FALSE);
//        if (info.flags.fullscreen)
//        {
//            if (info.windowWidth == 0 || info.windowHeight == 0)
//            {
//                GLFWvidmode mode;
//                glfwGetDesktopMode(&mode);
//                info.windowWidth = mode.Width;
//                info.windowHeight = mode.Height;
//            }
//
//            glfwOpenWindow(info.windowWidth, info.windowHeight, 8, 8, 8, 0, 32, 0, GLFW_FULLSCREEN);
//            glfwSwapInterval((int)info.flags.vsync);
//        }
//        else
{
window = glfwCreateWindow(info.windowWidth, info.windowHeight, info.title, info.flags.fullscreen ? glfwGetPrimaryMonitor() : NULL, NULL);
if (!window)
{
fprintf(stderr, "Failed to open window\n");
return;
}
}

glfwMakeContextCurrent(window);

glfwSetWindowSizeCallback(window, glfw_onResize);
glfwSetKeyCallback(window, glfw_onKey);
glfwSetMouseButtonCallback(window, glfw_onMouseButton);
glfwSetCursorPosCallback(window, glfw_onMouseMove);
glfwSetScrollCallback(window, glfw_onMouseWheel);
if (!info.flags.cursor)
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
}

// info.flags.stereo = (glfwGetWindowParam(GLFW_STEREO) ? 1 : 0);

gl3wInit();

#ifdef _DEBUG
fprintf(stderr, "VENDOR: %s\n", (char *)glGetString(GL_VENDOR));
fprintf(stderr, "VERSION: %s\n", (char *)glGetString(GL_VERSION));
fprintf(stderr, "RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
#endif

if (info.flags.debug)
{
if (gl3wIsSupported(4, 3))
{
glDebugMessageCallback((GLDEBUGPROC)debug_callback, this);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
else if (sb6IsExtensionSupported("GL_ARB_debug_output"))
{
glDebugMessageCallbackARB((GLDEBUGPROC)debug_callback, this);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
}
}

startup();

do
{
render(glfwGetTime());

glfwSwapBuffers(window);
glfwPollEvents();

running &= (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_RELEASE);
running &= (glfwWindowShouldClose(window) != GL_TRUE);
} while (running);

shutdown();

glfwDestroyWindow(window);
glfwTerminate();
}

In turn, this performs some initialization by first calling the startup() method and then calling the render() method in a loop.In the default implementation, both methods are defined as virtual functions with
empty bodies. We override the render() method in our derived class and write our drawing code inside it.

03 显示窗口

virtual void render(double currentTime)
{
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);
/*
const GLfloat color[] = {(float)sin(currentTime) * 0.5f + 0.5f,
(float)cos(currentTime) * 0.5f + 0.5f, 0.0f, 1.0f};
glClearNamedFramebufferfv(0, GL_COLOR, 0, color);
*/
}


The glClearBufferfv() function tells OpenGL to
f41f
clear the buffer specified by the first parameter (in this case GL_COLOR)to the value specified in its third parameter. The second parameter, drawBuffer,
is used when there are multiple output buffers that could be cleared.

The red, green, and blue terms should be self-explanatory. Alpha is a fourth component that is associated with a color and is often used to encode the opacity of a fragment.

04 shader

OpenGL works by connecting a number of mini-programs called shaders together with fixed-function glue. When you draw, the graphics processor executes your shaders and pipes their input and output along the pipeline until pixels come out the end. To draw
anything at all, you'll need to write at least a couple of shaders.

05 GLSL

OpenGL shaders are written in a language called the OpenGL Shading Language, or GLSL. This language has its origins in C, but has been modified over time to make it better suited to running on graphics processors. If you are familiar with C, then it shouldn't
be hard to pick up GLSL. The compiler for this language is build into OpenGL. The source code for your shader is placed into a shader object and compiled, and then multiple shader objects can be linked together
to form a program object. Each program object can contain shaders for one or more shader stages. The shader stages of OpenGL are vertex shaders, tessellation control and evaluation shaders, geometry shaders, fragment shaders, and compute shaders.


06 shader举例

We assign a value to gl_Position, which is part of the plumbing(管道) that connects the shader to the rest of OpenGL.

All variables that start with gl_ are part of OpenGL and connect shaders to each other or to the various parts of fixed functionality in OpenGL.

In the vertex shader, gl_Position represents the output position of the vertex.

Next, it declares color as an output variable using the out keyword. In fragment shaders, the value of output variables will be sent to the window or screen.

Now that we have both a vertex and a fragment shader, it's time to compile them and link them together into a program that can be run by OpenGL.

#include <sb7.h>

class singlepoint_app : public sb7::application
{
void init()
{
static const char title[] = "OpenGL SuperBible - Single Point";

sb7::application::init();

memcpy(info.title, title, sizeof(title));
}

virtual void startup()
{
static const char * vs_source[] =
{
"#version 420 core                             \n"
"                                              \n"
"void main(void)                               \n"
"{                                             \n"
"    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);   \n"
"}                                             \n"
};

static const char * fs_source[] =
{
"#version 420 core                             \n"
"                                              \n"
"out vec4 color;                               \n"
"                                              \n"
"void main(void)                               \n"
"{                                             \n"
"    color = vec4(0.0, 0.8, 1.0, 1.0);         \n"
"}                                             \n"
};

program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);

GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);

glAttachShader(program, vs);
glAttachShader(program, fs);

glLinkProgram(program);

glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
}

virtual void render(double currentTime)
{
static const GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, red);

glUseProgram(program);

glPointSize(40.0f);

glDrawArrays(GL_POINTS, 0, 1);
}

virtual void shutdown()
{
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
}

private:
GLuint          program;
GLuint          vao;
};

DECLARE_MAIN(singlepoint_app)

07 VAO

One final thing that we need to do before we can draw anything is to create a vertex array object(VAO),which is an object that represents the vertex fetch stage of the OpenGL pipeline and is used to supply input to the vertex shader.

We create them using a creation function (like glCreateVertexArrays()), and let OpenGL know that we want to use them by binding them to context using a binding function(like glBindVertexArray()).

生成屏幕中间点,背景颜色三角变化。

void glPositionSize(GLfloat size)

This function sets the diameter of the point in pixels to the value you specify in size.

08 gl_VertexID

Fortunately, GLSL includes a special input to the vertex shader called gl_VertexID, which is the index of the vertex that is being processed at the time.

void main(void) {
// Declare a hard-coded array of positions
const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0), vec4(-0.25, -0.25, 0.5, 1.0), vec4(0.25, 0.25, 0.5, 1.0));
// Index into our array using gl_VertexID
gl_Position = vertices[gl_VertexID];
}


Producing multiple vertices in a vertex shader

生成三角形

09 总结

This concludes the construction of our first OpenGL program. We will soon cover how to get data into your shaders from your application, how to pass your own inputs to the vertex shader, how to pass data from shader stage to shader stage, and more.

In this chapter, you have been briefly introduced to the sb7 application framework, compiled a shader, cleared the window, and drawn points and triangles. You have seen how to change the size of points using the glPointSize() function and have seen your
first drawing command -- glDrawArrays().
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: