2018-11-16 11:47:55 +00:00
|
|
|
#version 330
|
|
|
|
// This source code is property of the Computer Graphics and Visualization
|
|
|
|
// chair of the TU Dresden. Do not distribute!
|
2018-11-13 08:35:18 +00:00
|
|
|
// Copyright (C) CGV TU Dresden - All Rights Reserved
|
|
|
|
|
|
|
|
in vec4 position;
|
2018-11-29 11:16:21 +00:00
|
|
|
in vec2 offset;
|
2018-11-13 08:35:18 +00:00
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
out vec3 n;
|
2018-11-26 12:11:05 +00:00
|
|
|
out vec2 uv;
|
2018-11-26 16:58:30 +00:00
|
|
|
out vec2 road_uv;
|
2018-11-13 08:35:18 +00:00
|
|
|
|
|
|
|
uniform mat4 mvp;
|
|
|
|
|
|
|
|
//Returns the height of the procedural terrain at a given xz position
|
|
|
|
float getTerrainHeight(vec2 p);
|
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
vec3 calculate_normal(vec4 terrain_position);
|
|
|
|
vec4 offset_point(vec4 base, vec2 offset);
|
2018-11-13 08:35:18 +00:00
|
|
|
|
2018-11-26 08:59:16 +00:00
|
|
|
const vec2 offsets[6] = vec2[6](
|
|
|
|
vec2(0.0, 0.0),
|
|
|
|
vec2(0.0, 1.0),
|
|
|
|
vec2(1.0, 0.0),
|
|
|
|
vec2(0.0, 1.0),
|
|
|
|
vec2(1.0, 0.0),
|
|
|
|
vec2(1.0, 1.0)
|
|
|
|
);
|
2018-11-13 08:35:18 +00:00
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
2018-11-29 11:16:21 +00:00
|
|
|
vec2 instanced_pos = vec2(position.x + offset.x, position.z + offset.y);
|
|
|
|
vec4 terrain_position = vec4(instanced_pos.x, getTerrainHeight(instanced_pos), instanced_pos.y, position.w);
|
2018-12-06 10:22:55 +00:00
|
|
|
|
2018-12-12 16:56:49 +00:00
|
|
|
|
2018-12-06 10:22:55 +00:00
|
|
|
// read neightbor heights using an arbitrary small offset
|
|
|
|
vec3 off = vec3(1.0, 1.0, 0.0);
|
2018-12-12 16:56:49 +00:00
|
|
|
float hL = getTerrainHeight(instanced_pos - off.xz);
|
|
|
|
float hR = getTerrainHeight(instanced_pos + off.xz);
|
|
|
|
float hD = getTerrainHeight(instanced_pos - off.zy);
|
|
|
|
float hU = getTerrainHeight(instanced_pos + off.zy);
|
2018-12-06 10:22:55 +00:00
|
|
|
|
|
|
|
// deduce terrain normal
|
|
|
|
n.x = hL - hR;
|
|
|
|
n.y = hD - hU;
|
|
|
|
n.z = 2.0;
|
|
|
|
n = normalize(n);
|
|
|
|
|
2018-12-12 16:56:49 +00:00
|
|
|
|
|
|
|
//n = calculate_normal(terrain_position);
|
2018-11-26 12:11:05 +00:00
|
|
|
//n = vec3(0.0, 1.0, 0.0);
|
|
|
|
|
2018-11-29 11:16:21 +00:00
|
|
|
uv = vec2(terrain_position.x / 25.5, terrain_position.z / 25.5);
|
2018-11-26 16:58:30 +00:00
|
|
|
road_uv = offsets[gl_VertexID % 6];
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
|
|
gl_Position = mvp * terrain_position;
|
2018-11-13 08:35:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//source: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
|
|
|
|
float rand(vec2 c)
|
|
|
|
{
|
|
|
|
return 2 * fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
float perlinNoise(vec2 p )
|
|
|
|
{
|
|
|
|
vec2 ij = floor(p);
|
|
|
|
vec2 xy = p - ij;
|
2018-11-27 19:22:35 +00:00
|
|
|
xy = 3.*xy*xy-2.*xy*xy*xy;
|
|
|
|
//xy = .5*(1.-cos(3.1415926 * xy));
|
2018-11-13 08:35:18 +00:00
|
|
|
float a = rand((ij+vec2(0.,0.)));
|
|
|
|
float b = rand((ij+vec2(1.,0.)));
|
|
|
|
float c = rand((ij+vec2(0.,1.)));
|
|
|
|
float d = rand((ij+vec2(1.,1.)));
|
|
|
|
float x1 = mix(a, b, xy.x);
|
|
|
|
float x2 = mix(c, d, xy.x);
|
|
|
|
return mix(x1, x2, xy.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
//based on https://www.seedofandromeda.com/blogs/58-procedural-heightmap-terrain-generation
|
|
|
|
float getTerrainHeight(vec2 p)
|
|
|
|
{
|
|
|
|
float total = 0.0;
|
|
|
|
float maxAmplitude = 0.0;
|
|
|
|
float amplitude = 1.0;
|
|
|
|
float frequency = 0.02;
|
2018-11-26 08:59:16 +00:00
|
|
|
for (int i = 0; i < 11; i++)
|
2018-11-13 08:35:18 +00:00
|
|
|
{
|
|
|
|
total += ((1.0 - abs(perlinNoise(p * frequency))) * 2.0 - 1.0) * amplitude;
|
|
|
|
frequency *= 2.0;
|
|
|
|
maxAmplitude += amplitude;
|
|
|
|
amplitude *= 0.45;
|
|
|
|
}
|
|
|
|
return 15 * total / maxAmplitude;
|
2018-11-16 08:27:11 +00:00
|
|
|
}
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
|
|
vec4 offset_point(vec4 base, vec2 offset) {
|
2018-11-27 19:22:35 +00:00
|
|
|
vec2 new_pos = vec2(base.x, base.z) + offset;
|
|
|
|
float y = getTerrainHeight(new_pos);
|
|
|
|
return vec4(new_pos.x, y, new_pos.y, base.w);
|
2018-11-26 08:59:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the position of the first vertex in this square
|
|
|
|
vec4 pos_to_base(vec4 pos, int v_id) {
|
|
|
|
return vec4(pos.x - offsets[v_id].x, pos.y, pos.z - offsets[v_id].y, pos.w);
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculates the normal of terrain_position
|
|
|
|
// it generates the complete triangle based on the gl_VertexID and then normal math
|
|
|
|
vec3 calculate_normal(vec4 terrain_position) {
|
|
|
|
int offset_index = gl_VertexID % 6;
|
|
|
|
|
|
|
|
vec4 base_vertex = pos_to_base(terrain_position, offset_index);
|
|
|
|
|
|
|
|
// the other 2 points from the triangle
|
|
|
|
int points_index = 0;
|
|
|
|
vec4 points[2];
|
|
|
|
|
|
|
|
int iterator_offset = 0;
|
|
|
|
|
|
|
|
// second triangle offset
|
|
|
|
if (offset_index > 2) {
|
|
|
|
iterator_offset = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = iterator_offset; i < (3 + iterator_offset); i++) {
|
|
|
|
// skip for current vertex
|
|
|
|
if (i == offset_index) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
points[points_index] = offset_point(base_vertex, offsets[i]);
|
|
|
|
points_index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create connection vectors
|
2018-11-27 19:22:35 +00:00
|
|
|
vec3 v1 = (points[0] - terrain_position).xyz;
|
|
|
|
vec3 v2 = (points[1] - terrain_position).xyz;
|
2018-11-26 08:59:16 +00:00
|
|
|
|
|
|
|
// calculate normal
|
2018-11-27 19:22:35 +00:00
|
|
|
vec3 normal = normalize(cross(v1, v2));
|
2018-11-26 09:41:27 +00:00
|
|
|
|
|
|
|
// naively assume that a normal always has to look upwards
|
|
|
|
if (normal.y < 0.0) {
|
|
|
|
return -normal;
|
|
|
|
} else {
|
|
|
|
return normal;
|
|
|
|
}
|
2018-11-26 08:59:16 +00:00
|
|
|
}
|