2
\$\begingroup\$

I generated a terrain from a heightmap and now I'd like to apply shader on it which can contain different textures, based on height but I can't adapt any online code to my project. This is the GL_LINE rendered image enter image description here

The matrix generated from the heightmap has 0-255 values and -1 as the endline character.

This is the code of the terrain, the matrix is stored in a map<int, map<int, int>> data;structure:

#include "Terrain.h"

Terrain::Terrain(Scene* s, string filename): Entity(s) {
    this->hm = s->getHeightmap(filename);
    texture = scene->getTexture("avatar2.jpg");
    shader = scene->getShader("terrain.shader");
}

Terrain::~Terrain() {
}

void Terrain::draw() {
    cout << "Draw Terrain" << endl;
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
    //glUseProgramObjectARB(0);
    glUseProgram(this->shader->getRes());
    glTranslated(0, -20, -31.4);
    glRotatef(45, -1, 0, 0);

    const float offX = -25;
    const float offY = 0;
    const float lato = 0.5;
    const int limit = 100;
    const int limsx = 0;

    glBegin(GL_QUADS);
    for (float i = limsx; i < limit-1; ++i) {
        for (float j = limsx; j < limit-1; ++j) {
            glVertex3f(offX+lato*(j+1), offY+lato*i, hm->getHeight(i,j+1)/50);
            glVertex3f(offX + lato*(j + 1), offY + lato*(i + 1), hm->getHeight(i + 1, j+1)/50);
            glVertex3f(offX + lato*j, offY + lato*(i + 1), hm->getHeight(i+1, j)/50);
            glVertex3f(offX + lato*j, offY + lato*i, hm->getHeight(i, j)/50);
        }
    }
    glEnd();
}

Can you help me generating a terrain shader? Thank you very much

EDIT: thanks a lot to sakul_ca. This is what I got by using and editing his code

enter image description here

I used a shader that applies 4 textures to different heightmap values

\$\endgroup\$
  • 3
    \$\begingroup\$ Do you expect us to write that shader for you? Show your effort. Tell where you failed, why you could not write your own shader or adapt existing one. If you have specific coding questions, we can help with that. \$\endgroup\$ – HolyBlackCat Nov 24 '15 at 12:05
  • \$\begingroup\$ Your height map is flipped on one axis. \$\endgroup\$ – Trevor Powell Nov 24 '15 at 22:47
5
\$\begingroup\$

To give you exactly what you are asking for, look at the bottom two code examples.

To use those code examples, there are other code examples preceding it. These examples are using Vertex Buffer Objects. Which is something you should start using, and not "glBegin/glVertex/glEnd", because those are all deprecated OpenGL functions.

You are asking for multiple textures in your question too. You can do that by adding another texture with the shaders, and set them in the appropriate places in the C++ code.

Load Function

void LoadModel ( void )
{
    // ...
    // 1. Load the model from file.
    // 2. Get model information
    //  - Number of vertices 
    //  - Texture coordinates
    // 3. Make Data information
    //  - e.g.
    //  - Vertex_p4t4* pTempVertArray = new Vertex_p4t4[numVertices *2];
    //  - GLuint* pIndexArrayLocal = new GLuint[numIndicesInIndexArray * 2];
    // ...

    GLuint vboID;
    glGenVertexArrays( 1, &vboID );
    // Check for OpenGL error.

    glBindVertexArray( vboID );
    // Check for OpenGL error.

    // [SimpleTextureShader.vertex.glsl] 
    // layout (location=0) in vec4 in_Position
    // layout (location=1) in vec4 in_UVx2;
    glEnableVertexAttribArray ( 0 ); 
    glEnableVertexAttribArray ( 1 );
    // Check for OpenGL error.

    GLuint vertexBufferID;
    GLuint indexBufferID;
    glGenBuffers ( 1, &vertexBufferID );
    glGenBuffers ( 1, &indexBufferID );
    // Check for OpenGL error.

    glBindBuffer ( GL_ARRAY_BUFFER, vertexBufferID );
    // Check for OpenGL error.

    // In this case [sizeof ( YOURVERTEXDATA )] = 32)
    unsigned int vertSize = sizeof ( YOURVERTXDATA );
    unsigned int size = numVerticesInModel * vertSize ;
    glBufferData ( GL_ARRAY_BUFFER, size, VERTEXDATA, GL_STATIC_DRAW );
    // Check for OpenGL error.

    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, vertSize, 0 );
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, vertSize, 16 );
    // Check for OpenGL error.

    glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, indexBufferID );
    // Check for OpenGL error.

    glBufferData ( GL_ELEMENT_ARRAY_BUFFER, TOTALSIZEINBYTES, pIndexArrayLocal, GL_STATIC_DRAW);
    // Check for OpenGL error.

    glBindVertexArray( 0 );
    // Check for OpenGL error.

    // ...
    // Delete things you don't need anymore 
    // ...
    // Add model information to wherever you want
    // ...

    return;
}

Render Function

void Render ( void )
{
    // Set the texture shader program
    glUseProgram(currentProgramID);


    // uniform mat4 ModelMatrix;    
    // uniform mat4 ViewMatrix;
    // uniform mat4 ProjectionMatrix;
    // uniform sampler2D texture_0;

    // Normally you would get this information when loading the shader, and save all of the data somewhere else instead of getting it every time you render.
    GLint ModelMatrixUniformLocation = getUniformLocation ( currentShaderProgramID, "ModelMatrix" );
    GLint ViewMatrixUniformLocation = getUniformLocation ( currentShaderProgramID, "ViewMatrix" );
    GLint ProjectionMatrixUniformLocation = getUniformLocation ( currentShaderProgramID, "ProjectionMatrix" );
    GLint Texture0UniformLocation = getUniformLocation ( currentShaderProgramID, "texture_0" );

    // I'm using glm for this example, you can use whatever math library you wish, or write your own. 

    // Create a model matrix to use 
    glm::mat4 matModel = glm::mat4( 1.0f ); // initialize as identity;

    // Create a view matrix to use
    glm::mat4 matView = glm::lookAt(eye, look, up);

    // Create a projection matrix to use
    glm::mat4 matProj = glm::perspective( fovy, aspect, zNear, zFar );

    // OpenGL does matrix Transformation Calculations backwards, so you want to do:
    // Post Rotation, Translating, Pre Rotation, Scale
    // We are only translating in this example
    matMode = matMode = glm::translate ( matMode, ObjectPosition );

    // Send the matrix values to the shader program
    glUniformMatrix4fv( ModelMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr ( matModel ));
    glUniformMatrix4fv( ViewMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr ( matView));
    glUniformMatrix4fv( ProjectionMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr ( matProj));

    // Send the texture information to the shader program
    glActiveTexture(textureEnum);
    // Check for OpenGL error.

    glBindTexture(GL_TEXTURE_2D, textureID);
    // Check for OpenGL error.

    glUniform1i ( Texture0UniformLocation, textureID );
    // Check for OpenGL error.


    // Render your object(s) [ vboID from LoadTexture function ]
    glBindVertexArray ( vboID );
    // Check for OpenGL error.

    unsigned int numberOfIndices = NumberOfTrianglesInMesh * 3;
    glDrawElements ( GL_TRIANGLES, numberOfIndices, GL_UNSIGNED_INT, (GLvoid*)0 );
    // Check for OpenGL error.

    // All done
    return;
}

SimpleTextureShader.vertex.glsl

#version 400

layout (location=0) in vec4 in_Posiiton;
layout (location=1) in vec4 in_UVx2;

out vec4 ex_Position;
out vec4 ex_UVx2;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

void main ( void )
{
    mat4 MVPMatrix = ProjectionMatrix * ViewMatrix * ModelMatrix;
    gl_Position = MVPMatrix * in_Position;

    ex_Position = gl_Position;
    ex_UVx2 = in_UVx2;

    return;
}

SimpleTextureShader.fragment.glsl

#version 400

// From the vertex shader
in vec4 ex_Position;
in vec4 ex_UVx2;

// Texture information
uniform sampler2D texture_0;

// If you want multiple textures...
// uniform samples2D texture_1;
// uniform samples2D texture_2;
// uniform samples2D texture_3;
// ...

void main ( void )
{
    vec4 colour = vec4 ( 0.0f, 0.0f, 0.0f, 0.0f );
    colour = texture( texture_0, ex_UVx2.xy );

    // if you want multiple textures...
    // vec4 texture1Colour = texture( texture_1, ex_UVx2.xy );
    // vec4 texture2Colour = texture( texture_2, ex_UVx2.xy );
    // vec4 texture3Colour = texture( texture_3, ex_UVx2.xy );
    // Then do what you want with them.. e.g.
    // vec4 tex1Times2 = texture1Colour * texture2Colour;
    // vec4 texHeightColour = texture1Colour * ( 10.0f - gl_Position.y )
    // texHeightColour += texture2Colour * gl_Position;
    // colour= clamp ( texHeightColour, 0.0f, 1.0f );

    out_Colour = colour;

    return;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.