1
\$\begingroup\$

I tried asking this on reddit but I didn't get any answers so I might as well try here

So I'm making a program to generate some terrain and it's not giving me the results I expected. It's drawing black pillars. Lots of code coming up btw.

This is the article that I'm using https://learnopengl.com/Guest-Articles/2021/Tessellation/Tessellation

Even though it's written in C++ I rewrote it in C, the language I'm using.

This is the vertex shader

#version 410 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tex;

out vec2 tex_coord;

void main()
{
    // set position and sets texture (uv) coordinates
    gl_Position = vec4(pos, 1.0);
    tex_coord = tex;
}

This is the fragment shader

#version 410 core

in float height;

out vec4 color;

void main()
{
    float h = (height+16)/64.0f;
    color = vec4(h,h,h,1.0);
}

This is the tessellation control shader

#version 410 core

layout(vertices=4) out;

uniform mat4 model;
uniform mat4 view;

in vec2 tex_coord[];
out vec2 texture_coord[];

void main()
{
    // essentially sets render distance
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
    texture_coord[gl_InvocationID] = tex_coord[gl_InvocationID];

    if(gl_InvocationID == 0)
    {
        const int MIN_TESS_LEVEL = 4;
        const int MAX_TESS_LEVEL = 64;
        const float MIN_DISTANCE = 20;
        const float MAX_DISTANCE = 800;

        vec4 eye_space_pos_00 = view * model * gl_in[0].gl_Position;
        vec4 eye_space_pos_01 = view * model * gl_in[1].gl_Position;
        vec4 eye_space_pos_10 = view * model * gl_in[2].gl_Position;
        vec4 eye_space_pos_11 = view * model * gl_in[3].gl_Position;

        // "distance" from camera scaled between 0 and 1
        float distance_00 = clamp( (abs(eye_space_pos_00.z) - MIN_DISTANCE) / (MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0 );
        float distance_01 = clamp( (abs(eye_space_pos_01.z) - MIN_DISTANCE) / (MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0 );
        float distance_10 = clamp( (abs(eye_space_pos_10.z) - MIN_DISTANCE) / (MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0 );
        float distance_11 = clamp( (abs(eye_space_pos_11.z) - MIN_DISTANCE) / (MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0 );

        float tess_level_0 = mix( MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_10, distance_00) );
        float tess_level_1 = mix( MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_00, distance_01) );
        float tess_level_2 = mix( MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_01, distance_11) );
        float tess_level_3 = mix( MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_11, distance_10) );

        gl_TessLevelOuter[0] = tess_level_0;
        gl_TessLevelOuter[1] = tess_level_1;
        gl_TessLevelOuter[2] = tess_level_2;
        gl_TessLevelOuter[3] = tess_level_3;

        gl_TessLevelInner[0] = max(tess_level_1, tess_level_3);
        gl_TessLevelInner[1] = max(tess_level_0, tess_level_2);
    }
}

This is the tessellation evaluation shader

#version 410 core
layout(quads, fractional_odd_spacing, ccw) in;

uniform sampler2D height_map;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

in vec2 texture_coord[];

out float height;

void main()
{
    // get the texture coordinate of point (x, y, z) in the terrain
    float u = gl_TessCoord.x;
    float v = gl_TessCoord.y;

    vec2 t_00 = texture_coord[0];
    vec2 t_01 = texture_coord[1];
    vec2 t_10 = texture_coord[2];
    vec2 t_11 = texture_coord[3];

    vec2 t_0 = (t_01 - t_00) * u + t_00;
    vec2 t_1 = (t_11 - t_10) * u + t_10;
    vec2 tex_coord = (t_1 - t_0) * v + t_0;

    height = texture(height_map, tex_coord).g * 64.0 - 16.0;

    vec4 p_00 = gl_in[0].gl_Position;
    vec4 p_01 = gl_in[1].gl_Position;
    vec4 p_10 = gl_in[2].gl_Position;
    vec4 p_11 = gl_in[3].gl_Position;

    vec4 u_vec = p_01 - p_00;
    vec4 v_vec = p_10 - p_00;
    vec4 normal = normalize( vec4(cross(v_vec.xyz, u_vec.xyz), 0) );

    vec4 p_0 = (p_01 - p_00) * u + p_00;
    vec4 p_1 = (p_11 - p_10) * u + p_10;
    vec4 p = (p_1 - p_0) * v + p_0 + normal * height;

    gl_Position = projection * view * model * p;
}

This is the initialization for GLFW

// init glfw
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif // __APPLE__
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// check to see if glfw was initialized
if(!glfwInit())
{
    printf("GLFW is not ok.\n");
}

This is where I loaded the height map

// height map
unsigned int texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load the image
int width, height, nr_components;
short unsigned int* data = stbi_load_16("textures/river_heightmap.png", &width, &height, &nr_components, 0);
if(data)
{
    // bind texture and specify its data and how to manage it
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, width, height, 0, GL_RED, GL_UNSIGNED_SHORT, data);

    // set the height map
    set_int(shader_program, "height_map", 0);
    printf("Loaded a height map of %i x %i\n", width, height);
}
else
{
    printf("Failed to load height map\n");
}
stbi_image_free(data);

This is where I uploaded the terrain data to the GPU

float vertices[1000];
unsigned rez = 20;
for(unsigned i = 0; i <= rez-1; i++)
{
    for(unsigned j = 0; j <= rez-1; j++)
    {
        push_back_float(-width/2.0f + width*i/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*j/(float)rez, vertices); // v.z
        push_back_float(i / (float)rez, vertices); // u
        push_back_float(j / (float)rez, vertices); // v

        push_back_float(-width/2.0f + width*(i+1)/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*j/(float)rez, vertices); // v.z
        push_back_float((i+1) / (float)rez, vertices); // u
        push_back_float(j / (float)rez, vertices); // v

        push_back_float(-width/2.0f + width*i/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*(j+1)/(float)rez, vertices); // v.z
        push_back_float(i / (float)rez, vertices); // u
        push_back_float((j+1) / (float)rez, vertices); // v

        push_back_float(-width/2.0f + width*(i+1)/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*(j+1)/(float)rez, vertices); // v.z
        push_back_float((i+1) / (float)rez, vertices); // u
        push_back_float((j+1) / (float)rez, vertices); // v
    }
}
printf("Loaded %i patches of 4 control points each\n", rez*rez);
printf("Processing %i vertices in vertex shader\n", rez*rez*4);

This is where I set up the VAO and VBO

unsigned int vao, vbo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, (float)(sizeof(vertices)/sizeof(vertices[0])) * sizeof(float), &vertices[0], GL_STATIC_DRAW);

// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// texture attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(sizeof(float) * 3));
glEnableVertexAttribArray(1);

glPatchParameteri(GL_PATCH_VERTICES, NUM_PATCH_PTS);

This is the main loop and the buffer deletion

// game loop
while (!glfwWindowShouldClose(window))
{
    // per-frame time logic and FPS counter
    float current_frame = glfwGetTime();
    delta_time = current_frame - last_frame;
    last_frame = current_frame;

    // fps counter, uncomment if needed
    //printf("%i ms %f FPS\n", (int)delta_time, 1.0f / delta_time);

    // input
    keyboard_input(window);

    // render
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // shader
    use_shader(shader_program);

    // view/projection transformations
    mat4 projection = GLM_MAT4_IDENTITY_INIT;
    glm_perspective(glm_rad(ccamera->zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f, projection);
    mat4 view = GLM_MAT4_IDENTITY_INIT;
    camera_get_view_matrix(view);
    set_mat_4(shader_program, "projection", projection);
    set_mat_4(shader_program, "view", view);

    // world transformation
    mat4 model = GLM_MAT4_IDENTITY_INIT;
    set_mat_4(shader_program, "model", model);

    // render terrain
    glBindVertexArray(vao);
    glDrawArrays(GL_PATCHES, 0, NUM_PATCH_PTS*rez*rez);

    // glfw: swap buffers and poll IO events
    glfwSwapBuffers(window);
    glfwPollEvents();
}

// deallocate resources that outlived their purpose
shader_clean_up(shader_program);
// clean up glfw
glfwTerminate();
return 0;

These are the screenshots of the RenderDoc report This is the RenderDoc report

enter image description here

enter image description here

If you need any more information tell me so I can add more screenshots and code if needed.

Edit: The shader loader, the original code is from here if you wanna have a look at that: https://github.com/CraftingInC/LearnOpenGLInC/blob/master/includes/learnopengl/shader.h

Note: I did change a few things around from the original so here is my version

#ifndef SHADER_H_INCLUDED
#define SHADER_H_INCLUDED

#include <GL/glew.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <CGLM/cglm.h>

// loads the shader then copies the data into a char variable and returns the shader id
int load_shader_file(const char* shader_file_name, int shader_type)
{
    FILE* shader_file = fopen(shader_file_name, "rb");
    if(shader_file != NULL)
    {
        char* shader_char;
        fseek(shader_file, 0, SEEK_END);
        size_t total_size = ftell(shader_file);
        rewind(shader_file);

        shader_char = (char*)malloc(total_size + 1);
        fread(shader_char, 1, total_size, shader_file);
        shader_char[total_size] = 0;
        fclose(shader_file);

        GLuint shader_id = 0;
        shader_id = glCreateShader(shader_type);
        glShaderSource(shader_id, 1, (const char**)&shader_char, NULL);
        glCompileShader(shader_id);

        GLint shader_compiled;
        glGetShaderiv(shader_id, GL_COMPILE_STATUS, &shader_compiled);
        if(shader_compiled != GL_TRUE)
        {
            GLsizei log_length;
            GLchar log[1024];
            glGetShaderInfoLog(shader_id, sizeof(log), &log_length, log);
            printf("Error in %s: %s\n", shader_file_name, log);
        }
        else
        {
            return shader_id;
        }
        }
        else
        {
            printf("Unable to open file %s\n", shader_file_name);
        }
        return -1;
}

// checks for shader program errors
void check_for_errors(int shader_program)
{
    int worked;
    char info_log[1024];
    glGetProgramiv(shader_program, GL_LINK_STATUS, &worked);
    if(!worked)
    {
        glGetShaderInfoLog(shader_program, 1024, NULL, info_log);
        printf("Program linking failed: %s\n", info_log);
    }
}

// takes the already loaded shaders and attaches them to the shader program then deletes them (debugs if necessary) and finally returns the shader program
unsigned int load_glsl_shaders(const char* frag_shader_path, const char* vert_shader_path,
const char* tess_control_path, const char* tess_eval_path)
{
    unsigned int fragment, vertex, tess_control, tess_eval, program;
    fragment = load_shader_file(frag_shader_path, GL_FRAGMENT_SHADER);
    vertex = load_shader_file(vert_shader_path, GL_VERTEX_SHADER);
    tess_control = load_shader_file(tess_control_path, GL_TESS_CONTROL_SHADER);
    tess_eval = load_shader_file(tess_eval_path, GL_TESS_EVALUATION_SHADER);
    program = glCreateProgram();
    glAttachShader(program, fragment);
    glAttachShader(program, vertex);
    glAttachShader(program, tess_control);
    glAttachShader(program, tess_eval);
    glLinkProgram(program);
    check_for_errors(program);
    glDeleteShader(fragment);
    glDeleteShader(vertex);
    glDeleteShader(tess_control);
    glDeleteShader(tess_eval);
    return program;
}

// compiles the shaders and shader program (also debugs if necessary) then returns the shader program
unsigned int load_embedded_shaders(const char* vertex_shader_text, const char* fragment_shader_text,
const char* tess_control_text, const char* tess_eval_text)
{
    GLchar vertex_shader, fragment_shader, tess_control_shader, tess_eval_shader, shader_program;
    int compiled;
    char info_log[512];

    // compile fragment shader
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
    glCompileShader(fragment_shader);
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &compiled);
    if(!compiled)
    {
        glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
        printf("Fragment shader failed: %s\n", info_log);
    }

    // compile vertex shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
    glCompileShader(vertex_shader);
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compiled);
    if(!compiled)
    {
        glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
        printf("Vertex shader failed: %s\n", info_log);
    }

    // compile tessellation control shader
    tess_control_shader = glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(tess_control_shader, 1, &tess_control_text, NULL);
    glCompileShader(tess_control_shader);
    glGetShaderiv(tess_control_shader, GL_COMPILE_STATUS, &compiled);
    if(!compiled)
    {
        glGetShaderInfoLog(tess_control_shader, 512, NULL, info_log);
        printf("Tessellation control shader failed: %s\n", info_log);
    }

    // compile tessellation evaluation shader
    tess_eval_shader = glCreateShader(GL_TESS_EVALUATION_SHADER);
    glShaderSource(tess_eval_shader, 1, &tess_eval_text, NULL);
    glCompileShader(tess_eval_shader);
    glGetShaderiv(tess_eval_shader, GL_COMPILE_STATUS, &compiled);
    if(!compiled)
    {
        glGetShaderInfoLog(tess_eval_shader, 512, NULL, info_log);
        printf("Tessellation evaluation shader failed: %s\n", info_log);
    }

    // compile the shader program
    shader_program = glCreateProgram();
    glAttachShader(shader_program, fragment_shader);
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, tess_control_shader);
    glAttachShader(shader_program, tess_eval_shader);
    glLinkProgram(shader_program);
    check_for_errors(shader_program);

    // deletes the shaders
    glDeleteShader(fragment_shader);
    glDeleteShader(vertex_shader);
    glDeleteShader(tess_control_shader);
    glDeleteShader(tess_eval_shader);

    // return shader program
    return shader_program;
}

// deletes the shader program
void shader_clean_up(unsigned int shader_program)
{
    glDeleteProgram(shader_program);
}

// uses the shader program
void use_shader(unsigned int shader_program)
{
    glUseProgram(shader_program);
}

// sets boolean values in the shader program / shader(s) that are linked to it
void set_bool(unsigned int shader_program, const char* name, bool value)
{
    glUniform1i(glGetUniformLocation(shader_program, name), (int)value);
}

// sets integer values in the shader program / shader(s) that are linked to it
void set_int(unsigned int shader_program, const char* name, int value)
{
    glUniform1i(glGetUniformLocation(shader_program, name), value);
}

// sets floating point values in the shader program / shader(s) that are linked to it
void set_float(unsigned int shader_program, const char* name, float value)
{
    glUniform1f(glGetUniformLocation(shader_program, name), value);
}

// sets 2 dimensional matrices in the shader program / shader(s) that are linked to it
void set_mat_2(unsigned int shader_program, const char* name, const mat2 mat)
{
    glUniformMatrix2fv(glGetUniformLocation(shader_program, name), 1, GL_FALSE, &mat[0][0]);
}

// sets 3 dimensional matrices in the shader program / shader(s) that are linked to it
void set_mat_3(unsigned int shader_program, const char* name, const mat3 mat)
{
    glUniformMatrix3fv(glGetUniformLocation(shader_program, name), 1, GL_FALSE, &mat[0][0]);
}

// sets 4 dimensional matrices in the shader program / shader(s) that are linked to it
void set_mat_4(unsigned int shader_program, const char* name, const mat4 mat)
{
    glUniformMatrix4fv(glGetUniformLocation(shader_program, name), 1, GL_FALSE, &mat[0][0]);
}

// sets 2 dimensional vectors in the shader program / shader(s) that are linked to it
void set_vec_2(unsigned int shader_program, const char* name, const vec2 value)
{
    glUniform2fv(glGetUniformLocation(shader_program, name), 1, &value[0]);
}

// sets 2 dimensional vectors with 3d space directions in the shader program / shader(s) that are linked to it
void set_vec_2_xyz(unsigned int shader_program, const char* name, float x, float y)
{
    glUniform2f(glGetUniformLocation(shader_program, name), x, y);
}

// sets 3 dimensional vectors in the shader program / shader(s) that are linked to it
void set_vec_3(unsigned int shader_program, const char* name, const vec3 value)
{
    glUniform3fv(glGetUniformLocation(shader_program, name), 1, &value[0]);
}

// sets 3 dimensional vectors with 3d space directions in the shader program / shader(s) that are linked to it
void set_vec_3_xyz(unsigned int shader_program, const char* name, float x, float y, float z)
{
    glUniform3f(glGetUniformLocation(shader_program, name), x, y, z);
}

// sets 4 dimensional vectors in the shader program / shader(s) that are linked to it
void set_vec_4(unsigned int shader_program, const char* name, const vec4 value)
{
    glUniform4fv(glGetUniformLocation(shader_program, name), 1, &value[0]);
}

// sets 4 dimensional vectors with 3d space directions that include the w (the component that scales the other dimensions) in the shader program / shader(s) that are linked to it
void set_vec_4_wyzx(unsigned int shader_program, const char* name, float x, float y, float z, float w)
{
    glUniform4f(glGetUniformLocation(shader_program, name), x, y, z, w);
}
#endif // SHADER_H_INCLUDED

Edit 2: Shaders getting loaded

unsigned int shader_program = load_glsl_shaders("frag.vert", "vert.vert", "gpu_tcs.vert", "gpu_tes.vert");

Errors

enter image description here

\$\endgroup\$
8
  • \$\begingroup\$ Please, share also the code where you create and compile the GLprogram shader_program \$\endgroup\$
    – gotanod
    Feb 2, 2023 at 17:53
  • \$\begingroup\$ Ok I'll edit the post right now to include that. \$\endgroup\$
    – Chillzy
    Feb 2, 2023 at 19:11
  • \$\begingroup\$ SHADER_H includes a lot of functions but we need the code that creates the shader_program that is later used in use_shader(shader_program); It seems that glUseProgram returns an error GL_INVALID_OPERATION in one of the RenderDoc captures. \$\endgroup\$
    – gotanod
    Feb 2, 2023 at 20:55
  • \$\begingroup\$ I already included that. use_shader(shader_program); has the code glUseProgram(shader_program) \$\endgroup\$
    – Chillzy
    Feb 2, 2023 at 21:37
  • \$\begingroup\$ I mean the lines where shader_program is created. Something like shader_program = load_embedded_shaders... and the previous shader definitions. \$\endgroup\$
    – gotanod
    Feb 2, 2023 at 21:43

1 Answer 1

0
\$\begingroup\$

Vertices array size

Please, review the array float vertices[1000];

You are adding 20 * 20 * 20 = 8000 floats with the function push_back_float, so you must be exceeding the array limit.

Vertex01 and vertex10 swapped

The order they are defined inside the loop do not match the way they are used inside the shaders.


vec4 p_00 = gl_in[0].gl_Position;
vec4 p_01 = gl_in[1].gl_Position;       // gl_in in the VBO is the 10
vec4 p_10 = gl_in[2].gl_Position;       // gl_in in the VBO is the 01
vec4 p_11 = gl_in[3].gl_Position;

vec4 u_vec = p_01 - p_00;
vec4 v_vec = p_10 - p_00;
vec4 normal = normalize( vec4(cross(v_vec.xyz, u_vec.xyz), 0) );        // cross product with opposite direction

vec4 p_0 = (p_01 - p_00) * u + p_00;
vec4 p_1 = (p_11 - p_10) * u + p_10;
vec4 p = (p_1 - p_0) * v + p_0 + normal * height;

gl_Position = projection * view * model * p;

Try changing the order of vertex01 and vertex10 inside the for loops, so they match what shaders are expecting.


float vertices[1000];  // Increase to rez * rez * 20
unsigned rez = 20;
for(unsigned i = 0; i <= rez-1; i++)
{
    for(unsigned j = 0; j <= rez-1; j++)
    {
        // Vertex00
        push_back_float(-width/2.0f + width*i/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*j/(float)rez, vertices); // v.z
        push_back_float(i / (float)rez, vertices); // u
        push_back_float(j / (float)rez, vertices); // v

        // Vertex10
        push_back_float(-width/2.0f + width*(i+1)/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*j/(float)rez, vertices); // v.z
        push_back_float((i+1) / (float)rez, vertices); // u
        push_back_float(j / (float)rez, vertices); // v

        // Vertex01
        push_back_float(-width/2.0f + width*i/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*(j+1)/(float)rez, vertices); // v.z
        push_back_float(i / (float)rez, vertices); // u
        push_back_float((j+1) / (float)rez, vertices); // v

        // Vertex11
        push_back_float(-width/2.0f + width*(i+1)/(float)rez, vertices); // v.x
        push_back_float(0.0f, vertices); // v.y
        push_back_float(-height/2.0f + height*(j+1)/(float)rez, vertices); // v.z
        push_back_float((i+1) / (float)rez, vertices); // u
        push_back_float((j+1) / (float)rez, vertices); // v
    }
}
printf("Loaded %i patches of 4 control points each\n", rez*rez);
printf("Processing %i vertices in vertex shader\n", rez*rez*4);

Camera position

Currently located at (vec3)(0.0f, 0.0f, 3.0f); y=0

In the tessellation evaluation shader, the height (y coord) is added using the heightMap and it is scaled and shifted.

// Comment from the reference learnopengl.com page
// lookup texel at patch coordinate for height and scale + shift as desired
// height_map provides values in range [0.0-1.0]
// scaled by 64.0,  range [0.0,64.0]
// offset by -16.0, range [-16.0, 48.0]
height = texture(height_map, tex_coord).g * 64.0 - 16.0;    


vec4 p_00 = gl_in[0].gl_Position;
vec4 p_01 = gl_in[1].gl_Position;
vec4 p_10 = gl_in[2].gl_Position;
vec4 p_11 = gl_in[3].gl_Position;

vec4 u_vec = p_01 - p_00;
vec4 v_vec = p_10 - p_00;
vec4 normal = normalize( vec4(cross(v_vec.xyz, u_vec.xyz), 0) );

vec4 p_0 = (p_01 - p_00) * u + p_00;
vec4 p_1 = (p_11 - p_10) * u + p_10;
vec4 p = (p_1 - p_0) * v + p_0 + normal * height;  // normal is Y axis, scaled by range [-16.0,48.0]

gl_Position = projection * view * model * p;      // position has a y coord in range [-16.0, 48.0]

The camera should be above y=48.0 to avoid looking the mesh from below. The map is very huge 2624x1744 (height_map size). You should also increase the Far plane (100.0f) to look more terrain and avoiding the clipping with far plane.

 glm_perspective(glm_rad(ccamera->zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f, projection);
\$\endgroup\$
8
  • \$\begingroup\$ Good to know. I'll try adding more space to the array and see if it works. \$\endgroup\$
    – Chillzy
    Feb 3, 2023 at 1:55
  • \$\begingroup\$ Ok so I tried it and it didn't seem to work. As a matter of fact when I tried it it didn't draw any terrain at all. \$\endgroup\$
    – Chillzy
    Feb 3, 2023 at 16:39
  • \$\begingroup\$ Apart from the incorrect value of the vertices array (8000), the vertex01 and vertex10 are swapped, so if I'm correct, the normal is reveresed. Please, try changing the positions of vertex01 and vertex10 inside the loop. \$\endgroup\$
    – gotanod
    Feb 3, 2023 at 17:25
  • 1
    \$\begingroup\$ Thank you, this did help draw, but what's happening now is the mesh is getting drawn in black, and the mesh shapes are weird looking. I'll edit the question to include what it looks like if that could help. \$\endgroup\$
    – Chillzy
    Feb 3, 2023 at 18:48
  • \$\begingroup\$ Please, share also the texture textures/river_heightmap.png \$\endgroup\$
    – gotanod
    Feb 3, 2023 at 19:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .