我一直在研究地形 LOD 算法,但主要逻辑在 CPU 上:
我尝试将大部分逻辑转换为 opengl 管道的细分控制和评估阶段,但没有显示任何内容:
我将代码简化为一个基本的“hello quad”程序
#define GLEW_STATIC
#include <glew.h>
#include <glfw3.h>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
/* Shader Source */
// vertex shader
const GLchar * VS_src[] = {
"#version 430\n"
"layout(location = 0) in vec3 position;\n"
"out vec4 vposition;\n"
"void main()\n"
"{\n"
" vposition = vec4(position, 1.0);\n"
"}\n"
};
// tesselation control shader
const GLchar * TCS_src[] = {
"#version 430\n"
"layout(vertices = 4) out;\n"
"in vec4 vposition[];\n"
"out vec4 tposition[];\n"
"void main()\n"
"{\n"
" tposition[gl_InvocationID] = vposition[gl_InvocationID];\n"
" if (gl_InvocationID == 0)\n"
" {\n"
" float tessLevel = 1.0;\n"
" gl_TessLevelInner[0] = tessLevel;\n"
" gl_TessLevelInner[1] = tessLevel;\n"
" gl_TessLevelOuter[0] = tessLevel;\n"
" gl_TessLevelOuter[1] = tessLevel;\n"
" gl_TessLevelOuter[2] = tessLevel;\n"
" gl_TessLevelOuter[3] = tessLevel;\n"
" }\n"
"}\n"
};
// tesselation evaluation shader
const GLchar * TES_src[] = {
"#version 430\n"
"uniform mat4 mvp;\n"
"layout(quads) in;\n"
"in vec4 tposition[];\n"
"void main()\n"
"{\n"
" float x = gl_TessCoord[0] * (tposition[1].x - tposition[0].x) + tposition[0].x;\n"
" float z = gl_TessCoord[2] * (tposition[1].z - tposition[2].z) + tposition[2].z;\n"
" float y = 0.0;\n"
" gl_Position = mvp * vec4(x, y, z, 1.0);\n"
"}\n"
};
// fragment shader
const GLchar * FS_src[] = {
"#version 430\n"
"out vec3 color;\n"
"void main()\n"
"{\n"
"color = vec3(0.0);\n"
"}\n"
};
/* Link Shaders to Program */
GLuint LoadShaders(const GLchar ** VS, const GLchar ** TCS, const GLchar ** TES, const GLchar ** FS)
{
// Create the shaders
GLuint VS_ID = glCreateShader(GL_VERTEX_SHADER);
GLuint TCS_ID = glCreateShader(GL_TESS_CONTROL_SHADER);
GLuint TES_ID = glCreateShader(GL_TESS_EVALUATION_SHADER);
GLuint FS_ID = glCreateShader(GL_FRAGMENT_SHADER);
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("compiling vertex shader\n");
glShaderSource(VS_ID, 1, VS, NULL);
glCompileShader(VS_ID);
// Check Vertex Shader
glGetShaderiv(VS_ID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VS_ID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(VS_ID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Tess Control Shader
printf("compiling tesselation control shader\n");
glShaderSource(TCS_ID, 1, TCS, NULL);
glCompileShader(TCS_ID);
// Check Tess Control Shader
glGetShaderiv(TCS_ID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(TCS_ID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> TessControlShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(TCS_ID, InfoLogLength, NULL, &TessControlShaderErrorMessage[0]);
printf("%s\n", &TessControlShaderErrorMessage[0]);
}
// Compile Tess Evaluation Shader
printf("compiling tesselation evaluation shader\n");
glShaderSource(TES_ID, 1, TES, NULL);
glCompileShader(TES_ID);
// Check Tess Evaluation Shader
glGetShaderiv(TES_ID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(TES_ID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> TessEvaluationShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(TES_ID, InfoLogLength, NULL, &TessEvaluationShaderErrorMessage[0]);
printf("%s\n", &TessEvaluationShaderErrorMessage[0]);
}
// Compile Fragment Shader
printf("compiling fragment shader\n");
glShaderSource(FS_ID, 1, FS, NULL);
glCompileShader(FS_ID);
// Check Fragment Shader
glGetShaderiv(FS_ID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FS_ID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(FS_ID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
printf("linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VS_ID);
glAttachShader(ProgramID, TCS_ID);
glAttachShader(ProgramID, TES_ID);
glAttachShader(ProgramID, FS_ID);
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, VS_ID);
glDetachShader(ProgramID, TCS_ID);
glDetachShader(ProgramID, TES_ID);
glDetachShader(ProgramID, FS_ID);
glDeleteShader(VS_ID);
glDeleteShader(TCS_ID);
glDeleteShader(TES_ID);
glDeleteShader(FS_ID);
return ProgramID;
}
/* MAIN */
int main()
{
GLFWwindow * window;
if (!glfwInit()) return 0;
glfwWindowHint(GLFW_SAMPLES, 0);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(1600, 900, "Test", NULL, NULL);
if (!window) return 0;
glfwMakeContextCurrent(window);
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glewExperimental=true;
if (glewInit() != GLEW_OK) return 0;
// Init
glm::mat4 p = glm::perspective(glm::radians(45.0f), 1600.0f / 900.0f, 0.1f, 1000.0f);
// look at <0,0,0> from <20,20,20>
glm::mat4 v = glm::lookAt(glm::vec3(20.0f), glm::vec3(0.0f), glm::vec3(0,1,0));
glm::mat4 m = glm::mat4(1.0f);
glm::mat4 mvp = p * v * m;
// draw 1 quad
std::vector<unsigned int> indices;
std::vector<glm::vec3> vertices;
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
indices.push_back(3);
vertices.push_back(glm::vec3(-10.0f, 0.0f, -10.0f));
vertices.push_back(glm::vec3( 10.0f, 0.0f, -10.0f));
vertices.push_back(glm::vec3( 10.0f, 0.0f, 10.0f));
vertices.push_back(glm::vec3(-10.0f, 0.0f, 10.0f));
// VAO
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// program
GLuint ProgramID = LoadShaders(VS_src, TCS_src, TES_src, FS_src);
// mvp uniform
GLuint MatrixID = glGetUniformLocation(ProgramID, "mvp");
// Vertex Buffer
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
// Element Buffer
GLuint elementbuffer;
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
// loop
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 )
{
glViewport(0, 0, 1600, 900);
glClearColor(0.478f, 0.702f, 0.816f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glUseProgram(ProgramID);
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glPatchParameteri(GL_PATCH_VERTICES, 4);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glDrawElements(GL_PATCHES, indices.size(), GL_UNSIGNED_INT, (void*)0);
glDisableVertexAttribArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// cleanup
glDeleteVertexArrays(1, &VertexArrayID);
glDeleteProgram(ProgramID);
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &elementbuffer);
glfwTerminate();
return 0;
}
但仍然没有显示(除了蓝色 clearcolor 背景)。所有着色器编译时都没有错误,程序链接也没有错误。