Skip to content
Snippets Groups Projects
terrain.cpp 2.46 KiB
Newer Older
Noé's avatar
Noé committed

#include "terrain.hpp"


using namespace cgp;


// Evaluate 3D position of the terrain for any (x,y)
float evaluate_terrain_height(float x, float y)
{
    vec2 p[] = { {-10, -10}, {5, 5}, {-3, 4}, {6, 4} };
    float h[] = { 3.0f, -1.5f, 1.0f, 2.0f };
    float sigma[] = { 10.0f, 3.0f, 4.0f, 4.0f };
    float noise = 0.4*noise_perlin(vec2(x/50,y/50), 4.5f, 0.5, 5.0f);

    float z = 0;
    for (int i = 0; i < 4; i++) {
        float d = norm(vec2(x, y) - p[i]) / sigma[i];
        z += h[i] * std::exp(-d * d);
    }
    z += noise;
    return z;
}


mesh create_terrain_mesh(int N, float terrain_length)
{

    mesh terrain; // temporary terrain storage (CPU only)
    terrain.position.resize(N*N);
    terrain.uv.resize(N * N);

    // Fill terrain geometry
    for(int ku=0; ku<N; ++ku)
    {
        for(int kv=0; kv<N; ++kv)
        {
            // Compute local parametric coordinates (u,v) \in [0,1]
            float u = ku/(N-1.0f);
            float v = kv/(N-1.0f);

            // Compute the real coordinates (x,y) of the terrain in [-terrain_length/2, +terrain_length/2]
            float x = (u - 0.5f) * terrain_length;
            float y = (v - 0.5f) * terrain_length;

            // Compute the surface height function at the given sampled coordinate
            float z = evaluate_terrain_height(x,y);

            // Store vertex coordinates
            terrain.position[kv+N*ku] = {x,y,z};
            terrain.uv[kv+N*ku] = {x,y};
        }
    }

    // Generate triangle organization
    //  Parametric surface with uniform grid sampling: generate 2 triangles for each grid cell
    for(int ku=0; ku<N-1; ++ku)
    {
        for(int kv=0; kv<N-1; ++kv)
        {
            unsigned int idx = kv + N*ku; // current vertex offset

            uint3 triangle_1 = {idx, idx+1+N, idx+1};
            uint3 triangle_2 = {idx, idx+N, idx+1+N};

            terrain.connectivity.push_back(triangle_1);
            terrain.connectivity.push_back(triangle_2);
        }
    }

    // need to call this function to fill the other buffer with default values (normal, color, etc)
	terrain.fill_empty_field(); 

    return terrain;
}

std::vector<cgp::vec3> generate_positions_on_terrain(int N, float terrain_length) {
    std::vector<vec3> rand_pos;
    float x, y;
    float d = terrain_length / 2.0f;
    for (int i = 0; i < N; i++) {
        x = rand_interval(-d, d);
        y = rand_interval(-d, d);
        rand_pos.push_back({ x,y, evaluate_terrain_height(x, y) });
    }

    return rand_pos;
}