Monday, March 30, 2015

c++ - Terrain shader from heightmap opengl GLSL


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> 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



Answer



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;
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...