Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
Terrain.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include <vlGraphics/Terrain.hpp>
33 #include <vlGraphics/Actor.hpp>
34 #include <vlGraphics/Effect.hpp>
35 #include <vlGraphics/Geometry.hpp>
36 #include <vlGraphics/GLSL.hpp>
38 #include <vlCore/Log.hpp>
39 #include <vlCore/Say.hpp>
40 
41 using namespace vl;
42 
44 {
45  mChunks.clear();
46 
47  if (mWidth <= 0 || mHeight <= 0 || mDepth <= 0 || mDetailRepetitionCount <= 0)
48  {
49  Log::error(
50  Say("Terrain initialization failed: invalid parameters.\n"
51  "width = %n\n"
52  "hieght = %n\n"
53  "depth = %n\n"
54  "detail repetition = %n\n")
56  );
57  return;
58  }
59 
60  if (useGLSL())
61  {
62  if(fragmentShader().empty() || vertexShader().empty())
63  {
64  Log::error("vertex shader or fragment shader not defined.\n");
65  /*mFragmentShader = "/glsl/terrain.fs";
66  mVertexShader = "/glsl/terrain.vs";*/
67  return;
68  }
69  }
70 
71  bool use_uniform_transform = false; // experimental only
72 
73  // Log::print("Loading detail texture... ");
75 
76  // Log::print("Loading terrain texture... ");
77  ref<Image> terrain_img = loadImage(terrainTexture());
78 
79  // Log::print("Loading heightmap... ");
80  ref<Image> heightmap_img = loadImage(heightmapTexture());
81 
82  if ( (!detail_img && !detailTexture().empty()) || !terrain_img || !heightmap_img)
83  {
84  Log::error("Terrain initialization failed.\n");
85  return;
86  }
87 
88  double dx = width() / heightmap_img->width();
89  double dz = depth() / heightmap_img->height();
90 
91  int x_subdivision = -1;
92  for(int ch=1; ch<1024; ++ch)
93  {
94  for(int ts=128; ts<=1024*8; ts*=2)
95  {
96  // printf("[%d][%d]x = %d\n", ch, ts, ch*ts-ch+1);
97  if (ch*ts-ch+1 == heightmap_img->width())
98  {
99  x_subdivision = ch;
100  break;
101  }
102  }
103  }
104 
105  int y_subdivision = -1;
106  for(int ch=1; ch<1024; ++ch)
107  {
108  for(int ts=128; ts<=1024*8; ts*=2)
109  {
110  // printf("[%d][%d]y = %d\n", ch, ts, ch*ts-ch+1);
111  if (ch*ts-ch+1 == heightmap_img->height())
112  {
113  y_subdivision = ch;
114  break;
115  }
116  }
117  }
118 
119  if ( x_subdivision == -1 )
120  {
121  Log::error("texture width must be of the type: cn*ts-cn+1 where cn=chunk-number, ts=texture-chunk-size\n");
122  return;
123  }
124  if ( y_subdivision == -1 )
125  {
126  Log::error("texture height must be of the type: cn*ts-cn+1 where cn=chunk-number, ts=texture-chunk-size\n");
127  return;
128  }
129 
130  int xsize = (heightmap_img->width() -1 + x_subdivision)/x_subdivision;
131  int zsize = (heightmap_img->height() -1 + y_subdivision)/y_subdivision;
132  int tx_xsize = (terrain_img->width() -1 + x_subdivision)/x_subdivision;
133  int tx_zsize = (terrain_img->height() -1 + y_subdivision)/y_subdivision;
134 
135  float dtu = float(1.0 / tx_xsize / 2.0);
136  float dtv = float(1.0 / tx_zsize / 2.0);
137  float dtu2 = 1.0f - dtu;
138  float dtv2 = 1.0f - dtv;
139  float du = float(1.0 / xsize / 2.0);
140  float dv = float(1.0 / zsize / 2.0);
141  float du2 = 1.0f - du;
142  float dv2 = 1.0f - dv;
143 
144  float detail_du = detail_img ? float(1.0 / detail_img->width() / 2.0) : 0;
145  float detail_dv = detail_img ? float(1.0 / detail_img->height() / 2.0) : 0;
146  float detail_du2 = mDetailRepetitionCount - detail_du;
147  float detail_dv2 = mDetailRepetitionCount - detail_dv;
148 
149  ref<Geometry> terr_tile;
150  ref<GLSLProgram> glsl;
151 
152  ref<ArrayFloat2> tmap_uv = new ArrayFloat2; // texture map
153  ref<ArrayFloat2> dmap_uv = detail_img ? new ArrayFloat2 : NULL; // detail texture map
154  ref<ArrayFloat2> hmap_uv = new ArrayFloat2; // height map
155  tmap_uv->resize( xsize * zsize );
156  if(detail_img)
157  dmap_uv->resize( xsize * zsize );
158  hmap_uv->resize( xsize * zsize );
159  for(int z=0; z<zsize; ++z)
160  {
161  for(int x=0; x<xsize; ++x)
162  {
163  float u = (float)x/(xsize-1); // 0 .. 1
164  float v = (float)z/(zsize-1); // 0 .. 1
165  tmap_uv->at(x + z*xsize).s() = (1.0f-u) * dtu + u * dtu2;
166  tmap_uv->at(x + z*xsize).t() = (1.0f-v) * dtv + v * dtv2;
167  if (detail_img)
168  {
169  dmap_uv->at(x + z*xsize).s() = (1.0f-u) * detail_du + u * detail_du2;
170  dmap_uv->at(x + z*xsize).t() = (1.0f-v) * detail_dv + v * detail_dv2;
171  }
172  hmap_uv->at(x + z*xsize).s() = (1.0f-u) * du + u * du2;
173  hmap_uv->at(x + z*xsize).t() = (1.0f-v) * dv + v * dv2;
174  }
175  }
176 
177  if (useGLSL())
178  {
179  terr_tile = vl::makeGrid( vec3(0,0,0), 1.0f, 1.0f, xsize, zsize);
180  terr_tile->setTexCoordArray(0, tmap_uv.get());
181  terr_tile->setTexCoordArray(1, dmap_uv.get());
182  terr_tile->setTexCoordArray(2, hmap_uv.get());
183 
184  glsl = new GLSLProgram;
185  ref<Uniform> Height = new vl::Uniform("Height");
186  Height->setUniformF((float)height());
187  glsl->setUniform( Height.get() );
189  if (use_uniform_transform)
190  glsl->attachShader( new GLSLVertexShader( String::loadText("/glsl/terrain_ut.vs") ) );
191  else
193 
194  // setup GLSL program 'static' uniforms
195  ref<Uniform> terrain_tex = new Uniform("terrain_tex");
196  ref<Uniform> detail_tex = new Uniform("detail_tex");
197  ref<Uniform> heightmap_tex = new Uniform("heightmap_tex");
198  terrain_tex ->setUniformI(0);
199  detail_tex ->setUniformI(1);
200  heightmap_tex->setUniformI(2);
201  glsl->setUniform(terrain_tex.get());
202  if (!detailTexture().empty())
203  glsl->setUniform(detail_tex.get());
204  glsl->setUniform(heightmap_tex.get());
205 
206  AABB aabb;
207  aabb.setMinCorner((real)-0.5, 0, (real)-0.5);
208  aabb.setMaxCorner((real)+0.5, (real)height(), (real)+0.5);
209  terr_tile->setBoundingBox( aabb );
210  terr_tile->setBoundingSphere(aabb);
211  terr_tile->setBoundsDirty(false);
212 
214  }
215 
218 
219  if (!useGLSL())
220  {
221  ref<TexEnv> texenv = new TexEnv;
222  texenv->setMode(TEM_MODULATE);
223  shaderNode()->setRenderState(IN_Propagate, texenv.get(), 1);
224  }
225 
226  // generate chunks
227  for(int mz=0, tz=0; mz<heightmap_img->height()-1; mz+=zsize-1, tz+=tx_zsize-1)
228  {
229  for(int mx=0, tx=0; mx<heightmap_img->width()-1; mx+=xsize-1, tx+=tx_xsize-1)
230  {
231  // effect settings for this tile
232  ref<Effect> terr_fx = new Effect;
233  ref<ShaderNode> shader_node = new ShaderNode;
234  shaderNode()->addChild(shader_node.get());
235  shader_node->setShader(terr_fx->shader());
236 
237  // terrain texture
238  ref<Image> tex_image = terrain_img->subImage(tx, tz, tx_xsize, tx_zsize);
239  ref<TextureImageUnit> tex_unit0 = new TextureImageUnit;
240  shader_node->setRenderState(IN_Propagate, tex_unit0.get(), 0);
241  tex_unit0->setTexture(new Texture(tex_image.get(), terrainTextureFormat(), false));
244  tex_unit0->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
245  tex_unit0->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
246 
247  // detail texture
248  if (detail_img)
249  {
250  ref<TextureImageUnit> tex_unit1 = new TextureImageUnit;
251  shader_node->setRenderState(IN_Propagate, tex_unit1.get(), 1);
252  tex_unit1->setTexture(new Texture(detail_img.get(), detailTextureFormat(), true));
255  tex_unit1->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
256  tex_unit1->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
257  if (Has_GL_EXT_texture_filter_anisotropic)
258  {
259  float max = 1.0f;
260  glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max);
261  tex_unit1->texture()->getTexParameter()->setAnisotropy(max);
262  }
263  }
264 
265  // heightmap texture
266  ref<Image> hmap_image = heightmap_img->subImage(mx, mz, xsize, zsize);
267  if (useGLSL())
268  {
269  ref<TextureImageUnit> tex_unit2 = new TextureImageUnit;
270  shader_node->setRenderState(IN_Propagate, tex_unit2.get(), 2);
271  tex_unit2->setTexture(new Texture(hmap_image.get(), heightmapTextureFormat(), false));
274  tex_unit2->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
275  tex_unit2->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
276  }
277 
278  // compute tile transform
279  dmat4 dmat;
280  dmat.scale((xsize-1)*dx, 1.0, (zsize-1)*dz);
281  dmat.translate(mx*dx + (xsize-1)*dx*0.5 - width()/2.0, 0, mz*dz + (zsize-1)*dz*0.5 - depth()/2.0);
282  dmat.translate((dvec3)mOrigin);
283  ref<Transform> transform = new Transform;
284  transform->setLocalAndWorldMatrix((mat4)dmat);
285 
286  if (!useGLSL())
287  {
288  terr_tile = vl::makeGrid( vec3(0,0,0), 1.0f, 1.0f, xsize, zsize);
289  terr_tile->setTexCoordArray(0, tmap_uv.get());
290  terr_tile->setTexCoordArray(1, dmap_uv.get());
291 
292  ref<ArrayFloat3> verts = terr_tile->vertexArray()->as<ArrayFloat3>(); VL_CHECK(verts.get());
293  for(int z=0; z<zsize; ++z)
294  {
295  for(int x=0; x<xsize; ++x)
296  {
297  fvec4 sample = hmap_image->sample(x,z) * (float)height();
298  int index = x + xsize * z;
299  verts->at(index).y() = sample.r();
300  }
301  }
302  }
303 
304  // collect the terrain chunks to be inserted later in the ActorKdTree
305 
306  ref<Actor> actor = new Actor(terr_tile.get(), terr_fx.get(), (use_uniform_transform && useGLSL())?NULL:transform.get());
307  mChunks.push_back(actor.get());
308 
309  if (use_uniform_transform && useGLSL())
310  {
311  #if 1
312  actor->setUniformSet( new UniformSet );
313  ref<Uniform> uniform_matrix = new Uniform("matrix");
314  uniform_matrix->setUniform( (fmat4)dmat );
315  actor->setUniform( uniform_matrix.get() );
316  #else
317  ref<Uniform> uniform_matrix = new Uniform("matrix");
318  uniform_matrix->setUniform( (mat4)dmat );
319  terr_fx->shader()->setUniform( uniform_matrix.get() );
320  #endif
321  }
322 
323  #if 0 // for debuggin purposes
324  // terr_fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
325  terr_tile->setColorArray( fvec4(rand()%256/255.0f,rand()%256/255.0f,rand()%256/255.0f) );
326  #endif
327  }
328  }
329 
332 }
const ShaderNode * shaderNode() const
Definition: Terrain.hpp:133
Associates a Renderable object to an Effect and Transform.
Definition: Actor.hpp:130
int mDetailRepetitionCount
Definition: Terrain.hpp:148
Wraps an OpenGL Shading Language uniform to be associated to a GLSLProgram (see vl::GLSLProgram docum...
Definition: Uniform.hpp:59
TexParameter * getTexParameter()
The TexParameter object associated to a Texture.
Definition: Texture.hpp:281
const T_Scalar & t() const
Definition: Vector2.hpp:146
Implements a 4x4 matrix transform used to define the position and orientation of an Actor...
Definition: Transform.hpp:72
ETextureFormat detailTextureFormat() const
Definition: Terrain.hpp:89
const T * get() const
Definition: Object.hpp:128
If enabled, do depth comparisons and update the depth buffer; Note that even if the depth buffer exis...
Vector4< float > fvec4
A 4 components vector with float precision.
Definition: Vector4.hpp:280
A simple String formatting class.
Definition: Say.hpp:124
const T_Scalar & s() const
Definition: Vector2.hpp:145
ActorCollection mChunks
Definition: Terrain.hpp:138
Matrix4 & translate(T_Scalar x, T_Scalar y, T_Scalar z)
Definition: Matrix4.hpp:579
Wraps a GLSL vertex shader to be bound to a GLSLProgram: the shader this shader will run on the progr...
Definition: GLSL.hpp:117
const T_Scalar & r() const
Definition: Vector4.hpp:112
const ArrayAbstract * vertexArray() const
Conventional vertex array.
Definition: Geometry.hpp:248
bool useGLSL() const
Definition: Terrain.hpp:78
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
void setWrapT(ETexParamWrap texturewrap)
Definition: Texture.hpp:104
void setBoundsDirty(bool dirty)
Marks the bounding box and bounding sphere as dirty in order to be recomputed at the next rendering...
Definition: Renderable.hpp:127
void init()
Definition: Terrain.cpp:43
ETextureFormat terrainTextureFormat() const
Definition: Terrain.hpp:88
Wraps a GLSL program to which you can bind vertex, fragment and geometry shaders. ...
Definition: GLSL.hpp:233
Wraps an OpenGL texture object representing and managing all the supported texture types...
Definition: Texture.hpp:178
ref< Image > subImage(int xstart, int ystart, int width, int height)
Creates a new image containing the specified rectangular pixel area taken from the source image...
Definition: Image.cpp:2086
void setWrapS(ETexParamWrap texturewrap)
Definition: Texture.hpp:103
The ShaderNode class is used to conveniently manage complex hierarchies of Shader[s].
Definition: ShaderNode.hpp:45
void resize(size_t dim)
Definition: Array.hpp:233
ETextureFormat heightmapTextureFormat() const
Definition: Terrain.hpp:87
void setBoundingSphere(const Sphere &sphere)
Sets the bounding sphere of a Renderable.
Definition: Renderable.hpp:144
void setColorArray(const fvec4 &color)
Fills the color array with the given color.
Definition: Geometry.hpp:108
const String & heightmapTexture() const
Definition: Terrain.hpp:86
void setLocalAndWorldMatrix(const mat4 &matrix)
Sets both the local and the world matrices.
Definition: Transform.hpp:176
VLCORE_EXPORT ref< Image > loadImage(VirtualFile *file)
Loads an image from the specified file.
Definition: Image.cpp:1214
void setBoundingBox(const AABB &aabb)
Sets the bounding box of a Renderable.
Definition: Renderable.hpp:133
Visualization Library main namespace.
Wraps a GLSL fragment shader to be bound to a GLSLProgram: the shader this shader will run on the pro...
Definition: GLSL.hpp:136
Propagates to children; does not override children settings; can be overridden.
The TextureImageUnit class associates a Texture object to an OpenGL texture unit. ...
Definition: Shader.hpp:1747
RenderState wrapping the OpenGL function glTexEnv(), see also http://www.opengl.org/sdk/docs/man/xhtm...
Definition: Shader.hpp:1589
Texture * texture()
The texture sampler by a texture unit.
Definition: Shader.hpp:1768
void setMinFilter(ETexParamFilter minfilter)
Definition: Texture.hpp:100
double width() const
Definition: Terrain.hpp:80
double mHeight
Definition: Terrain.hpp:140
int height() const
Definition: Image.hpp:209
The AABB class implements an axis-aligned bounding box using vl::real precision.
Definition: AABB.hpp:44
The Vector3 class is a template class that implements a generic 3 components vector, see also vl::fvec3, vl::dvec3, vl::uvec3, vl::ivec3, vl::svec3, vl::usvec3, vl::bvec3, vl::ubvec3.
Definition: Vector3.hpp:44
void setUniformF(const float &value)
Definition: Uniform.hpp:188
float max(float a, float b)
Definition: Vector2.hpp:312
void setMinCorner(real x, real y, real z)
Sets the corner of the AABB with the minimum x y z coordinates.
Definition: AABB.hpp:196
void addChild(ShaderNode *node)
Definition: ShaderNode.hpp:94
void push_back(T *data)
Definition: Collection.hpp:79
void setMaxCorner(real x, real y, real z)
Sets the corner of the AABB with the maximum x y z coordinates.
Definition: AABB.hpp:202
int width() const
Definition: Image.hpp:207
void buildKdTree(ActorCollection &actors, int max_depth=100, float minimum_volume=0)
Builds a ActorKdTree with the given list of Actors.
double depth() const
Definition: Terrain.hpp:81
const T_Scalar & y() const
Definition: Vector3.hpp:91
bool empty() const
Returns true if length() == 0.
Definition: String.hpp:136
void setUniform(Uniform *uniform)
Utility function using getUniformSet(). Adds a Uniform to this program&#39;s static uniform set...
Definition: GLSL.hpp:476
static String loadText(const String &path, EStringEncoding encoding=VL_PLATFORM_DEFAULT_ENCODING)
Loads a String from the specified path.
Definition: String.cpp:86
void setTexCoordArray(int tex_unit, ArrayAbstract *data)
Conventional texture coords arrays.
Definition: Geometry.cpp:222
T * as()
Casts an Object to the specified class.
Definition: Object.hpp:282
Matrix4 & scale(T_Scalar x, T_Scalar y, T_Scalar z)
Definition: Matrix4.hpp:615
double mWidth
Definition: Terrain.hpp:139
void setUniform(Uniform *uniform)
Equivalent to getUniformSet()->setUniform(uniform)
Definition: Actor.cpp:119
#define NULL
Definition: OpenGLDefs.hpp:81
const String & fragmentShader() const
Definition: Terrain.hpp:105
void setUniformI(const int &value)
Definition: Uniform.hpp:176
void setUniformSet(UniformSet *uniforms)
Installs a new UniformSet.
Definition: Actor.hpp:334
Shader * shader(int lodi=0, int pass=0)
Utility function, same as &#39;lod(lodi)->at(pass);&#39;.
Definition: Effect.hpp:178
Defines the sequence of Shader objects used to render an Actor.
Definition: Effect.hpp:91
double mDepth
Definition: Terrain.hpp:141
double height() const
Definition: Terrain.hpp:82
T_VectorType & at(size_t i)
Definition: Array.hpp:255
fvec3 vec3
Defined as: &#39;typedef fvec3 vec3&#39;. See also VL_PIPELINE_PRECISION.
Definition: Vector3.hpp:270
const String & detailTexture() const
Definition: Terrain.hpp:84
void updateHierarchy()
Definition: ShaderNode.hpp:149
void setShader(Shader *shader)
Definition: ShaderNode.hpp:86
vec3 mOrigin
Definition: Terrain.hpp:142
void setUniform(int count, const int *value)
Definition: Uniform.hpp:145
A set of Uniform objects managed by a Shader.
Definition: UniformSet.hpp:50
void setTexture(Texture *texture)
The texture sampler by a texture unit.
Definition: Shader.hpp:1765
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
const String & terrainTexture() const
Definition: Terrain.hpp:85
void setAnisotropy(float anisotropy)
Definition: Texture.hpp:107
An array of vl::fvec3.
Definition: Array.hpp:414
void setRenderState(EInheritance inheritance, RenderStateNonIndexed *rs)
Definition: ShaderNode.hpp:260
VLGRAPHICS_EXPORT ref< Geometry > makeGrid(const vec3 &origin, real xside, real zside, int x, int z, bool gen_texcoords=false, fvec2 uv0=fvec2(0, 0), fvec2 uv1=fvec2(1, 1), bool center=true)
Creates a 2D grid.
bool attachShader(GLSLShader *shader)
Attaches the GLSLShader to this GLSLProgram.
Definition: GLSL.cpp:354
void setUniform(Uniform *uniform)
Equivalent to gocUniformSet()->setUniform(...)
Definition: Shader.hpp:2202
fvec4 sample(int x, int y=0, int z=0) const
Returns the color associated to the specified pixel.
Definition: Image.cpp:1998
void setMagFilter(ETexParamFilter magfilter)
Definition: Shader.cpp:754
An array of vl::fvec2.
Definition: Array.hpp:412
#define VL_CHECK(expr)
Definition: checks.hpp:73
void setEnable(EEnable en, bool on, EInheritance inheritance=IN_Propagate)
Definition: ShaderNode.hpp:285
const String & vertexShader() const
Definition: Terrain.hpp:102
const ActorKdTree * tree() const
Returns the tree used by the scene manager.
void setMode(ETexEnvMode mode)
Definition: Shader.hpp:1598
If enabled, cull polygons based on their winding in window coordinates, see also CullFace.