天天看點

shader 着色器shader 着色器

shader 着色器

着色器是運作在GPU上面的小程式,這些小程式為圖形渲染的某個特定部份而運作,從基本意義上來說,着色器隻一種把輸入轉換為輸出的程式。

着色器的開頭聲明版本,接着輸入和輸出變量,uniform和main函數。

一個典型的着色器有下面的結構

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
  // 處理輸入并進行一些圖形操作
  ...
  // 輸出處理過的結果到輸出變量
  out_variable_name = weird_stuff_we_processed;
}
           

頂點着色器的輸入變量也叫頂點屬性(Vertex Attribute),它由硬體來決定,OpenGL確定至少有16個包含4分量的頂點屬性可以用,可以用GL_MAX_VERTEX_ATTRIBS來查詢

GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
           

資料類型

GLSL中包含C等其它語言大部份的預設的資料類型,如

int

,

float

,

double

,

uint

,

bool

.GLSL也有兩種容器類型,矩陣(Matrix),向量(Vector)

向量

類型 說明
vecn 包含n個float分量的的預設向量
bvecn 包含n個bool分量的向量
ivecn 包含n個int分量的向量
uvecn 包含n個unsigned int 分量的向量
dvecn 包含n個double分量的向量

輸入與輸出

頂點着色器接收的是一種特殊行式的輸入,頂點着色器的輸入特殊在,它從頂點資料中直接接收輸入。為了定義頂點資料該如何管理,我們使用location這一進制資料指定輸入變量,這樣我們才可以在CPU上配置頂點屬性。我們已經在前面的教程看過這個了,layout (location = 0)。頂點着色器需要為它的輸入提供一個額外的layout辨別,這樣我們才能把它連結到頂點資料。

另一個例外是片段着色器,它需要一個vec4顔色輸出變量,因為片段着色器需要生成一個最終輸出的顔色。如果你在片段着色器沒有定義輸出顔色,OpenGL會把你的物體渲染為黑色(或白色)。

是以,如果我們打算從一個着色器向另一個着色器發送資料,我們必須在發送方着色器中聲明一個輸出,在接收方着色器中聲明一個類似的輸入。當類型和名字都一樣的時候,OpenGL就會把兩個變量連結到一起,它們之間就能發送資料了(這是在連結程式對象時完成的)。

//
//  main.cpp
//  shaders0
//
//  Created by xufan on 2017/5/16.
//  Copyright © 2017年 xufan. All rights reserved.
//

#include <iostream>
#include <math.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void display();

// Shaders


const GLchar *vertexShaderSource = " \n \
    #version 330 core \n \
    layout (location = 0) in vec3 position; // position變量的屬性位置值為0 \n \
    layout (location = 1) in vec3 color;    // 顔色變量的屬性位置值為1 \n \
\n \
    out vec3 ourColor; // 為片段着色器輸出一個顔色輸出\n \
\n \
    void main() \n \
    { \n \
        gl_Position = vec4(position, 1.0); // 注意我們如何把一個vec3作為vec4的構造器的參數\n \
        ourColor = color; //将ourColor設定為我們從頂點資料那裡得到的輸入顔色\n \
    }\n";

const GLchar* fragmentShaderSource = "\n \
    #version 330 core \n \
    in vec3 ourColor; // 從頂點着色器傳來的輸入變量(名稱相同、類型相同)\n \
\n \
    out vec4 color; // 片段着色器輸出的變量名可以任意命名,類型必須是vec4\n \
    //uniform vec4 ourColor; //在OpenGL程式代碼中設定這個變量\n \
\n \
    void main() \n \
    { \n \
        color = vec4(ourColor, 1.0f); \n \
        //color = ourColor; \n \
    }\n";

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, );
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, );
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

    GLFWwindow *window = glfwCreateWindow(, , "learnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);

    glfwSetKeyCallback(window, key_callback);

    glewExperimental = GL_TRUE;
    glewInit();

    printf("%s\n",vertexShaderSource);
    printf("%s\n",fragmentShaderSource);
    GLint nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;

    int width,height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(, , width, height);

    //vertex shader
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, , &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    //check
    GLint success;
    GLchar infoLog[];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, , NULL, infoLog);
        std::cout<<"vertex shader compilation failed"<<std::endl;
    }

    //fragmeng shader
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, , &fragmentShaderSource,NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader,GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, , NULL, infoLog);
        std::cout<<"fragment shader compilation failed"<<std::endl;
    }

    //create a program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    //check
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, , NULL, infoLog);
        std::cout<<"shaderPorgram failed"<<std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


//    GLfloat vertices[] = {
//        -0.5f, -0.5f, 0.0f, // Left
//        0.5f, -0.5f, 0.0f, // Right
//        0.0f,  0.5f, 0.0f  // Top
//    };
//    GLfloat vertices[] = {
//        
//
//        
//        // 第一個三角形
//        0.5f, 0.5f, 0.0f,   // 右上角
//        0.5f, -0.5f, 0.0f,  // 右下角
//        -0.5f, 0.5f, 0.0f,  // 左上角
//        // 第二個三角形
//        0.5f, -0.5f, 0.0f,  // 右下角
//        -0.5f, -0.5f, 0.0f, // 左下角
//        -0.5f, 0.5f, 0.0f   // 左上角
//        
//    };

    GLfloat vertices[] = {
        // 位置              // 顔色
        , -, ,  , , ,   // 右下
        -, -, ,  , , ,  // 左下
        ,  , ,  , ,     // 頂部

    };

    GLuint VBO; // vertex buffer object,頂點緩沖對象
    GLuint VAO; // vertex array object ,頂點數組對象

    glGenVertexArrays(, &VAO);
    glGenBuffers(, &VBO);

    //綁定
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    //複制
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //設定頂點屬性指針,位置屬性
    glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * , (GLvoid*)());
    //啟動頂點屬性,位置是0
    glEnableVertexAttribArray();

    //設定顔色屬性,啟動
    glVertexAttribPointer(, , GL_FLOAT, GL_FALSE, sizeof(GLfloat) * , (GLvoid *)( * sizeof(GLfloat)));
    glEnableVertexAttribArray();

    //解綁
    glBindBuffer(GL_ARRAY_BUFFER, );
    glBindVertexArray();

    //線框
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //GL_FILL 填充

    while (!glfwWindowShouldClose(window)) {

        glfwPollEvents();

        display();

        //激活着色器
        glUseProgram(shaderProgram);

//        GLfloat timeValue = glfwGetTime();
//        GLfloat greenValue = (sin(timeValue) / 2) + 0.5;
//        GLint vertextColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
//        glUniform4f(vertextColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
//        
        //繪制這個三角形
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, , sizeof(vertices)/ ( * sizeof(vertices[])));
        glBindVertexArray();

        glfwSwapBuffers(window);
    }

    glDeleteVertexArrays(,&VAO);
    glDeleteBuffers(, &VBO);

    glfwTerminate();

    return ;
}

void display()
{
    //緩沖顔色
    glClearColor(, , , );
    //清空顔色緩沖
    glClear(GL_COLOR_BUFFER_BIT);
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {

        std::cout<<"enter escape";
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}
           

繼續閱讀