AlgebraMaster

Modern C++ 创造非凡 . 改变世界

导航

OpenGL Tessellation

阶段:

 

 

1,TCS: Tessellation Control Shader,细分控制材质

2,PG:Primitive Generator,图元生成器

3,TES:Tessellation Evalution Shader,细分执行材质

4,CP:Control Points,The TCS works on a group of vertices called Control Points (CP),TCS工作在一组控制点上,CP点得移动会影响 被控制的表面。

 

 

TCS阶段是输入一个patch 输出一个 patch,TCS还要计算一个重要的功能: Tessllation levels:TL,Tessellation level of detai - how many triangles to generate for the patch(在一个patch上生成多少个三角形)

如果rasterized triangle覆盖了100个像素,可以决定TL的值是3,如果覆盖了101-500 可以为7。

另外也可以根据摄像机距离来决定TL值。

 

TCS完成之后,PG就是执行细分。PG阶段并不是真正的细分,你可能连访问他的权限都没有。但是TL & subdives 来定义了一个新的概念:Domain,domain是一个2D 0-1区间square,或者3d的barycentric coordinates

如右边的三角形,Barycentric coordinates坐标为:<1/3,1/3,1/3>,所以满足这个坐标,他的x+y+z = 1.0

For simplicity let's focus on the triangle domain from now on.

 

In general, the TLs tell the PG the number of segments on the outer edge of the triangle and the number rings towards the center

At any rate, remember that the PG ignores both the input and output patch of the TCS. All it cares about are the per patch TLs.

 

在TES中,和vertex shader相似。我们要执行矩阵变换。变换到摄像机空间。

TES不能生成点或者删除点在一个调用。

The main purpose of the TES that the architects of Tessellation in OpenGL envisioned is to evaluate the surface equation at the given domain location

 

1,测试1:细分一个三角形

 vs:

#version 450 core
layout(location =0 ) in vec3 vs_p;
layout(location =1 ) in vec3 vs_cd;
out vec3 vs_color;
void main(){
    gl_Position = vec4(vs_p,1.0);
    vs_color = vs_cd;
}

tcs:

注意下面

gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;实际上把vert shader的材质传入

#version 450 core
layout (vertices = 3) out;
void main(){
    //inner
    gl_TessLevelInner[0] = 5;
    // outer
    gl_TessLevelOuter[0] = 5;
    gl_TessLevelOuter[1] = 5;
    gl_TessLevelOuter[2] = 5;
    
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

}

tes:

#version 450 core
layout(triangles , equal_spacing,ccw) in;
void main(){

    vec4 upos= gl_TessCoord.x * gl_in[0].gl_Position;
    vec4 vpos= gl_TessCoord.y * gl_in[1].gl_Position;
    vec4 wpos= gl_TessCoord.z * gl_in[2].gl_Position;
    gl_Position = upos + vpos + wpos;

}

frag:

#version 450 core
out vec4 color;
void main(){
    color = vec4(1,1,1,1);
}
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <chrono>
#undef GLFW_DLL
// GLFW
#include <GLFW/glfw3.h>
#include "utils.h"
#include "errorCheck.h"
#include "geoPtrs.h"


using namespace std;
using namespace AlgebraMaster;

const int width = 800;
const int height = 800;


static GLuint shaderProgram;
static GLuint UBO;


void init_geo(const GeoPtr & geoPtr, GLfloat *data, int numVertdata){
    glBindBuffer(GL_ARRAY_BUFFER, geoPtr->VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * numVertdata, data, GL_STREAM_DRAW);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
    //glNamedBufferData(VBO,sizeof(data),data,GL_STREAM_DRAW);
    //glNamedBufferStorage(VBO,sizeof(data),data, 0);

    // Position
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*) 0);
    glEnableVertexAttribArray(0);
    // Cd
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glPatchParameteri(GL_PATCH_VERTICES,3);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}



void initShader(){
    string vert_code =  readFile("shaders/tessellation/CP_01/vert.glsl");
    string frag_code =  readFile("shaders/tessellation/CP_01/frag.glsl");
    string tcs_code =  readFile("shaders/tessellation/CP_01/tcs.glsl");
    string tes_code =  readFile("shaders/tessellation/CP_01/tes.glsl");

    const char * vertexShaderSrc = vert_code.c_str();
    const char * fragShaderSrc = frag_code.c_str();
    const char * tcsShaderSrc = tcs_code.c_str();
    const char * tesShaderSrc = tes_code.c_str();
    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);
    CHECK_SHADER(vertexShader,"VERTEX");

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragShaderSrc, nullptr);
    glCompileShader(fragmentShader);
    CHECK_SHADER(vertexShader,"FRAGMENT");

    // create tessellation control shader
    GLuint tcsShader =glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(tcsShader,1, &tcsShaderSrc, nullptr);
    glCompileShader(tcsShader);
    CHECK_SHADER(tcsShader,"Tessellation Control Shader");

    // create tessellation evaluation shader
    GLuint tesShader =glCreateShader(GL_TESS_EVALUATION_SHADER);
    glShaderSource(tesShader,1, &tesShaderSrc, nullptr);
    glCompileShader(tesShader);
    CHECK_SHADER(tesShader,"Tessellation Evaluation Shader");


    // Create shaderProgram and specify transform feedback variables
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glAttachShader(shaderProgram, tcsShader);
    glAttachShader(shaderProgram, tesShader);


    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);
    CHECK_PROGRAM(shaderProgram);

    // no more need
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteShader(tcsShader);
    glDeleteShader(tesShader);
}


void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawArrays(GL_PATCHES,0,3);
}

void cursor_pos_callback(GLFWwindow *w, double x, double y);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);


int main(){


    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_VISIBLE,GL_FALSE);
    GLFWwindow * window = glfwCreateWindow(width,height,"Hello",NULL,NULL);
    glfwSetCursorPosCallback(window, cursor_pos_callback);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwMakeContextCurrent(window);
    glewInit();


    cout << ">>initialize shaders\n";
    initShader();

    // Triangle
    float vertices[] = {
            // positions          // colors
            -0.5f,  -0.5f, 0.0f,   1.0f, 0.0f, 0.0f,
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,
            0.0f, 0.5f, 0.0f,   0.0f, 0.0f, 1.0f,

    };


    cout << ">>initialize geometry\n";
    GeoPtr geoPtr = MakeGeo();
    init_geo(geoPtr, vertices, sizeof(vertices) / sizeof(float) );


    cout << ">>rendering\n";
    auto t_prev = std::chrono::high_resolution_clock::now();
    while( !glfwWindowShouldClose( window ) ) {
        // Clear the screen to black
        glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Calculate delta time
        auto t_now = std::chrono::high_resolution_clock::now();
        float time = std::chrono::duration_cast<std::chrono::duration<float>>(t_now - t_prev).count();
        t_prev = t_now;

        // Render content
        display();

        // then swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwTerminate();
    glfwDestroyWindow(window);

    return 0;
}

void cursor_pos_callback(GLFWwindow *w, double x, double y){

}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);

}
main.cpp

CPP中要设置:

glPatchParameteri(GL_PATCH_VERTICES,3);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

render时候:

void display(){
    // render
    // ------
    glUseProgram(shaderProgram);
    glDrawArrays(GL_PATCHES,0,3);
}

 

2,修改材质,支持我们的vert shading里面的变量。比如我们输入了vs_cd;

vert保持不变:

#version 450 core
layout(location =0 ) in vec3 vs_p;
layout(location =1 ) in vec3 vs_cd;
out vec3 vs_color;
out vec4 vs_pos;
void main(){
    gl_Position = vec4(vs_p,1.0);
    vs_pos = vec4(vs_p,1.0);  // same as up
    vs_color = vs_cd;
}

tcs修改:可以不用gl_out[gl_InvocationID].gl_Position。

#version 450 core
layout (vertices = 3) out;
// ----------- from vert shader ---------------
in vec4 vs_pos[];
in vec3 vs_color[];
// ---------- out put -------------------------
out vec4 tcs_pos[];
out vec3 tcs_color[];

void main(){
    //inner
    gl_TessLevelInner[0] = 5;
    // outer
    gl_TessLevelOuter[0] = 5;
    gl_TessLevelOuter[1] = 5;
    gl_TessLevelOuter[2] = 5;

    tcs_pos[gl_InvocationID]   = vs_pos[gl_InvocationID];
    tcs_color[gl_InvocationID] = vs_color[gl_InvocationID];
}

TES 重心坐标插值。

#version 450 core
layout(triangles , equal_spacing,ccw) in;

vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2)
{
    return vec2(gl_TessCoord.x) * v0 + vec2(gl_TessCoord.y) * v1 + vec2(gl_TessCoord.z) * v2;
}
vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2)
{
    return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}

// ----------------------- in variables from TCS -------------------
in vec4 tcs_pos[];
in vec3 tcs_color[];
// ----------------------- Out variables from TES ------------------
out vec4 P;   // it can transfer to fragment or geometry shader
out vec3 Cd;  // transfer to fragment shader

void main(){
    vec3 iterP = interpolate3D(tcs_pos[0].xyz,tcs_pos[1].xyz,tcs_pos[2].xyz);
    vec3 iterCd = interpolate3D(tcs_color[0],tcs_color[1],tcs_color[2]);
    P = vec4(iterP , 1);
    Cd = iterCd;
    gl_Position = P;  // may be need to MVP matrix here
}

frag材质可以看到拿到细分后的颜色完全正确。

#version 450 core
out vec4 color;
in vec3 Cd;
void main(){
    color = vec4(Cd , 1.0);
}

 

 

 

 

 

REF:

http://ogldev.atspace.co.uk/www/tutorial30/tutorial30.html

https://www.youtube.com/watch?v=A96elMGacqI

posted on 2020-06-16 15:07  gearslogy  阅读(1040)  评论(0编辑  收藏  举报