演示程序已上傳: https://download.csdn.net/download/qq_31804159/10383143
從學習圖形學開始,就想做一個關於地形方面的東西(因爲看起來比較酷emmm),有一次機會瞭解到了基於高度圖渲染地形。這是一個比較簡單的方法,對新手而言比較友好的。其實這個是我好早之前做的一個東西了,但是算是真正進入圖形學的一個標誌吧,以後我會陸續的把我做的一些有意思的東西分享給大家,也很希望與你們共同交流進步hhh。好,開始正題!
先附我的實現:
下面介紹實現原理:
所謂高度圖,其實是一張簡單的2D圖片,由黑色,白色和之間的灰度所生成。高度圖代表了我們地形的低、高點(灰度表示高度)! 通過讀取一張高度圖的灰度我們去構造三角形網格,模型中某點的x,y座標可以用圖像的x,y座標表示而z座標即表示爲圖像中x,y處的灰度gray(x,y)來表示。
關鍵代碼:
//定義點和紋理數組
QVector<QVector3D> vertex;
QVector<QVector2D> texture;
//讀取地形文件
void terrain::loadTerrain(const QString &filename)
{
QImage image(filename);
vertex.clear();
texture.clear();
//構造三角網格
for( int i = 0; i< image.height()-1; i++){
for( int k = 0; k< image.width()-1;k++)
{
QVector3D v1(k+0-image.width()/2.0,QColor(image.pixel(k+0,i+0)).red(),i+0-image.height()/2.0);
QVector3D v2(k+0-image.width()/2.0,QColor(image.pixel(k+0,i+1)).red(),i+1-image.height()/2.0);
QVector3D v3(k+1-image.width()/2.0,QColor(image.pixel(k+1,i+1)).red(),i+1-image.height()/2.0);
QVector3D v4(k+1-image.width()/2.0,QColor(image.pixel(k+1,i+0)).red(),i+0-image.height()/2.0);
vertex.push_back(v1);
vertex.push_back(v2);
vertex.push_back(v3);
vertex.push_back(v1);
vertex.push_back(v3);
vertex.push_back(v4);
}
}
//綁定紋理座標
for( int i = 0; i < vertex.size(); i++){
QVector2D tmp( (vertex[i].x()+image.width()/2)/image.width(), (vertex[i].z()+image.height()/2)/image.height() );
texture.push_back(tmp);
}
}
下面的渲染是渲染函數,我是使用着色器渲染的。如果沒有用過着色器的同學可以瞭解一下,或者直接跳過使用固定管線的頂點數組也可。
//渲染
void terrain::renderTerrain(QGLShaderProgram *program)
{
program->bindAttributeLocation("a_Vertex",0);
program->enableAttributeArray(0);
program->bindAttributeLocation("a_TexCoord",1);
program->enableAttributeArray(1);
program->setAttributeArray(0,vertex.data());
program->setAttributeArray(1,texture.data());
glDrawArrays(GL_TRIANGLES,0,vertex.size());
}
下面簡單的貼上我的着色器代碼
頂點着色器:
attribute vec3 a_Vertex;
attribute vec2 a_TexCoord;
uniform mat4 MVP_matrix;
varying vec2 v_TexCoord0;
varying vec3 v_position;
void main(void)
{
gl_Position = MVP_matrix *vec4(a_Vertex,1.0);
v_position = a_Vertex;
v_TexCoord0 = a_TexCoord;
}
片元着色器:
uniform sampler2D u_Texture0;
uniform sampler2D u_Texture1;
varying vec2 v_TexCoord0;
varying vec3 v_position;
void main(void)
{
if(v_position.y > 60)
gl_FragColor = texture2D(u_Texture0, v_TexCoord0)*0.9;
else
{
float delta = v_position.y/60;
gl_FragColor = texture2D(u_Texture0, v_TexCoord0)*delta +
texture2D(u_Texture1, v_TexCoord0)*(1-delta);
}
}
在片元着色器中我實現了兩個紋理混合,以上的效果圖中底面的水波紋和山的紋理即爲混合的效果。當然還可以拓展爲多個紋理的混合。