Initial tree generation
Still very slow because multiple noise evaluations are neededpull/6/head
parent
9bc5bab3b2
commit
381cd698c7
|
@ -6,7 +6,9 @@ enum class Block{
|
||||||
AIR,
|
AIR,
|
||||||
STONE,
|
STONE,
|
||||||
DIRT,
|
DIRT,
|
||||||
GRASS
|
GRASS,
|
||||||
|
WOOD,
|
||||||
|
LEAVES
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -16,6 +16,9 @@ extr Camera theCamera;
|
||||||
constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE));
|
constexpr int chunks_volume = static_cast<int>(1.333333333333*M_PI*(RENDER_DISTANCE*RENDER_DISTANCE*RENDER_DISTANCE));
|
||||||
extr bool wireframe;
|
extr bool wireframe;
|
||||||
|
|
||||||
|
extr float sines[360];
|
||||||
|
extr float cosines[360];
|
||||||
|
|
||||||
extr uint32_t MORTON_XYZ_ENCODE[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
|
extr uint32_t MORTON_XYZ_ENCODE[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
|
||||||
extr uint32_t MORTON_XYZ_DECODE[CHUNK_VOLUME][3];
|
extr uint32_t MORTON_XYZ_DECODE[CHUNK_VOLUME][3];
|
||||||
extr uint32_t HILBERT_XYZ_ENCODE[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
|
extr uint32_t HILBERT_XYZ_ENCODE[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <random> // for std::mt19937
|
#include <random> // for std::mt19937
|
||||||
|
#include <experimental/random>
|
||||||
|
|
||||||
#include "block.hpp"
|
#include "block.hpp"
|
||||||
#include "chunkgenerator.hpp"
|
#include "chunkgenerator.hpp"
|
||||||
|
@ -8,34 +9,43 @@
|
||||||
#include "OpenSimplexNoise.h"
|
#include "OpenSimplexNoise.h"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
#define GRASS_OFFSET 100
|
#define GRASS_OFFSET 40
|
||||||
#define NOISE_GRASS_MULT 50
|
#define NOISE_GRASS_MULT 30
|
||||||
#define NOISE_DIRT_MULT 3
|
#define NOISE_DIRT_MULT 3
|
||||||
#define NOISE_DIRT_MIN 3
|
#define NOISE_DIRT_MIN 3
|
||||||
#define NOISE_DIRT_X_MULT 0.001f
|
#define NOISE_DIRT_X_MULT 0.001f
|
||||||
#define NOISE_DIRT_Z_MULT 0.001f
|
#define NOISE_DIRT_Z_MULT 0.001f
|
||||||
#define NOISE_GRASS_X_MULT 0.018f
|
#define NOISE_GRASS_X_MULT 0.018f
|
||||||
#define NOISE_GRASS_Z_MULT 0.018f
|
#define NOISE_GRASS_Z_MULT 0.018f
|
||||||
|
#define NOISE_TREE_X_MULT 0.01f
|
||||||
|
#define NOISE_TREE_Z_MULT 0.01f
|
||||||
|
|
||||||
|
#define LEAVES_RADIUS 3
|
||||||
|
#define WOOD_CELL_SIZE 13
|
||||||
|
#define WOOD_CELL_CENTER 7
|
||||||
|
#define WOOD_CELL_BORDER (LEAVES_RADIUS-1)
|
||||||
|
#define WOOD_MAX_OFFSET (WOOD_CELL_SIZE-WOOD_CELL_CENTER-WOOD_CELL_BORDER)
|
||||||
|
#define TREE_STANDARD_HEIGHT 7
|
||||||
|
#define TREE_HEIGHT_VARIATION 2
|
||||||
|
|
||||||
void generatePyramid(Chunk::Chunk *chunk);
|
void generatePyramid(Chunk::Chunk *chunk);
|
||||||
void generateNoise(Chunk::Chunk *chunk);
|
void generateNoise(Chunk::Chunk *chunk);
|
||||||
void generateNoise3D(Chunk::Chunk *chunk);
|
void generateNoise3D(Chunk::Chunk *chunk);
|
||||||
|
|
||||||
void generateChunk(Chunk::Chunk *chunk)
|
|
||||||
{
|
|
||||||
generateNoise(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
Block block;
|
|
||||||
|
|
||||||
std::random_device dev;
|
std::random_device dev;
|
||||||
std::mt19937 mt(dev());
|
std::mt19937 mt(dev());
|
||||||
OpenSimplexNoise::Noise noiseGen1(mt());
|
OpenSimplexNoise::Noise noiseGen1(mt());
|
||||||
OpenSimplexNoise::Noise noiseGen2(mt());
|
OpenSimplexNoise::Noise noiseGen2(mt());
|
||||||
|
OpenSimplexNoise::Noise noiseGenWood(mt());
|
||||||
|
|
||||||
std::array<int, CHUNK_SIZE * CHUNK_SIZE> grassNoiseLUT;
|
std::array<int, CHUNK_SIZE * CHUNK_SIZE> grassNoiseLUT;
|
||||||
std::array<int, CHUNK_SIZE * CHUNK_SIZE> dirtNoiseLUT;
|
std::array<int, CHUNK_SIZE * CHUNK_SIZE> dirtNoiseLUT;
|
||||||
|
|
||||||
|
void generateChunk(Chunk::Chunk *chunk)
|
||||||
|
{
|
||||||
|
generateNoise(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
double evaluateNoise(OpenSimplexNoise::Noise noiseGen, double x, double y, double amplitude, double
|
double evaluateNoise(OpenSimplexNoise::Noise noiseGen, double x, double y, double amplitude, double
|
||||||
frequency, double persistence, double lacunarity, int octaves){
|
frequency, double persistence, double lacunarity, int octaves){
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
|
@ -49,12 +59,60 @@ double evaluateNoise(OpenSimplexNoise::Noise noiseGen, double x, double y, doubl
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int TREE_MASTER_SEED_X = mt();
|
||||||
|
const int TREE_MASTER_SEED_Z = mt();
|
||||||
|
|
||||||
|
void evaluateTreeCell(int cx, int cz, int wcx, int wcz, int* wcx_offset, int*
|
||||||
|
wcz_offset, int* wx, int* wz, int* bwx, int* bwz, int* leaves_noise){
|
||||||
|
|
||||||
|
static int old_cx = -1, old_cz = -1, old_leaves_noise = -1;
|
||||||
|
|
||||||
|
int anglex = TREE_MASTER_SEED_X*wcx+TREE_MASTER_SEED_Z*wcz;
|
||||||
|
int anglez = TREE_MASTER_SEED_Z*wcz+TREE_MASTER_SEED_X*wcx;
|
||||||
|
|
||||||
|
// Start at the center of the cell, with a bit of random offset
|
||||||
|
int wcx_off = WOOD_CELL_CENTER + WOOD_MAX_OFFSET * sines[anglex % 360];
|
||||||
|
int wcz_off = WOOD_CELL_CENTER + WOOD_MAX_OFFSET * cosines[anglez % 360];
|
||||||
|
|
||||||
|
//std::cout << "cell: (" << wcx << "," << wcz << "): offset: (" << (int)wcx_off << "," << (int)wcz_off << ")\n";
|
||||||
|
|
||||||
|
// Cell to world coordinates
|
||||||
|
*wx = wcx * WOOD_CELL_SIZE + wcx_off;
|
||||||
|
*wz = wcz * WOOD_CELL_SIZE + wcz_off;
|
||||||
|
|
||||||
|
*wcx_offset = wcx_off;
|
||||||
|
*wcz_offset = wcz_off;
|
||||||
|
|
||||||
|
*bwx = *wx - cx;
|
||||||
|
*bwz = *wz - cz;
|
||||||
|
|
||||||
|
if(old_leaves_noise == -1 || old_cx != cx || old_cz != cx || *bwx < 0 || *bwz < 0 || *bwx >= CHUNK_SIZE || *bwz >= CHUNK_SIZE)
|
||||||
|
*leaves_noise = TREE_STANDARD_HEIGHT + GRASS_OFFSET + evaluateNoise(noiseGen1, *wx, *wz, NOISE_GRASS_MULT, 0.01, 0.35, 2.1, 5);
|
||||||
|
else *leaves_noise = TREE_STANDARD_HEIGHT + grassNoiseLUT[*bwx * CHUNK_SIZE + *bwz];
|
||||||
|
|
||||||
|
old_leaves_noise = *leaves_noise;
|
||||||
|
old_cx = cx;
|
||||||
|
old_cz = cz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Block block;
|
||||||
|
|
||||||
void generateNoise(Chunk::Chunk *chunk)
|
void generateNoise(Chunk::Chunk *chunk)
|
||||||
{
|
{
|
||||||
|
int cx = chunk->getPosition().x * CHUNK_SIZE;
|
||||||
|
int cy = chunk->getPosition().y * CHUNK_SIZE;
|
||||||
|
int cz = chunk->getPosition().z * CHUNK_SIZE;
|
||||||
|
|
||||||
|
// Precalculate LUTs
|
||||||
for (int i = 0; i < grassNoiseLUT.size(); i++)
|
for (int i = 0; i < grassNoiseLUT.size(); i++)
|
||||||
{
|
{
|
||||||
grassNoiseLUT[i] = -1;
|
int bx = i / CHUNK_SIZE;
|
||||||
dirtNoiseLUT[i] = -1;
|
int bz = i % CHUNK_SIZE;
|
||||||
|
|
||||||
|
grassNoiseLUT[i] = GRASS_OFFSET + evaluateNoise(noiseGen1, cx+bx, cz+bz, NOISE_GRASS_MULT, 0.01, 0.35, 2.1, 5);
|
||||||
|
dirtNoiseLUT[i] = NOISE_DIRT_MIN + (int)((1 + noiseGen2.eval(cx+bx * NOISE_DIRT_X_MULT,
|
||||||
|
cz+bz * NOISE_DIRT_Z_MULT)) * NOISE_DIRT_MULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block block_prev{Block::AIR};
|
Block block_prev{Block::AIR};
|
||||||
|
@ -64,18 +122,13 @@ void generateNoise(Chunk::Chunk *chunk)
|
||||||
for (int s = 0; s < CHUNK_VOLUME; s++)
|
for (int s = 0; s < CHUNK_VOLUME; s++)
|
||||||
{
|
{
|
||||||
|
|
||||||
int x = HILBERT_XYZ_DECODE[s][0] + CHUNK_SIZE * chunk->getPosition().x;
|
int bx = HILBERT_XYZ_DECODE[s][0];
|
||||||
int y = HILBERT_XYZ_DECODE[s][1] + CHUNK_SIZE * chunk->getPosition().y;
|
int by = HILBERT_XYZ_DECODE[s][1];
|
||||||
int z = HILBERT_XYZ_DECODE[s][2] + CHUNK_SIZE * chunk->getPosition().z;
|
int bz = HILBERT_XYZ_DECODE[s][2];
|
||||||
int d2 = HILBERT_XYZ_DECODE[s][0] * CHUNK_SIZE + HILBERT_XYZ_DECODE[s][2];
|
int x = bx + cx;
|
||||||
|
int y = by + cy;
|
||||||
if (grassNoiseLUT[d2] == -1)
|
int z = bz + cz;
|
||||||
grassNoiseLUT[d2] = GRASS_OFFSET + evaluateNoise(noiseGen1, x, z, NOISE_GRASS_MULT,
|
int d2 = bx * CHUNK_SIZE + bz;
|
||||||
0.01, 0.35, 2.1, 5);
|
|
||||||
if (dirtNoiseLUT[d2] == -1)
|
|
||||||
dirtNoiseLUT[d2] = NOISE_DIRT_MIN + (int)((1 + noiseGen2.eval(x
|
|
||||||
* NOISE_DIRT_X_MULT, z * NOISE_DIRT_Z_MULT)) * NOISE_DIRT_MULT);
|
|
||||||
|
|
||||||
|
|
||||||
int grassNoise = grassNoiseLUT[d2];
|
int grassNoise = grassNoiseLUT[d2];
|
||||||
int dirtNoise = dirtNoiseLUT[d2];
|
int dirtNoise = dirtNoiseLUT[d2];
|
||||||
|
@ -90,15 +143,56 @@ void generateNoise(Chunk::Chunk *chunk)
|
||||||
else
|
else
|
||||||
block = Block::AIR;
|
block = Block::AIR;
|
||||||
|
|
||||||
|
|
||||||
|
// Divide the world into cells, so that no two trees will be adjacent of each other
|
||||||
|
int wcx = x / WOOD_CELL_SIZE, wcz = z / WOOD_CELL_SIZE;
|
||||||
|
int wcx_offset, wcz_offset, wx, wz, bwx, bwz, leavesNoise;
|
||||||
|
|
||||||
|
evaluateTreeCell(cx, cz, wcx, wcz, &wcx_offset, &wcz_offset, &wx, &wz, &bwx, &bwz,
|
||||||
|
&leavesNoise);
|
||||||
|
|
||||||
|
// A tree is to be places if the coordinates are those of the tree of the current cell
|
||||||
|
int wood_height = TREE_STANDARD_HEIGHT;// + noiseGenWood.eval(wcx * NOISE_TREE_X_MULT, wcz * NOISE_TREE_Z_MULT) * TREE_HEIGHT_VARIATION;
|
||||||
|
bool wood = x == wx && z == wz && y > grassNoiseLUT[d2] && y <= leavesNoise;
|
||||||
|
bool leaf = false;
|
||||||
|
|
||||||
|
leaf = wood && y > leavesNoise && y < leavesNoise+LEAVES_RADIUS;
|
||||||
|
if(!leaf) leaf = utils::withinDistance(x,y,z, wx, leavesNoise, wz, LEAVES_RADIUS);
|
||||||
|
|
||||||
|
if(!leaf){
|
||||||
|
evaluateTreeCell(cx, cz, wcx+1, wcz, &wcx_offset, &wcz_offset, &wx, &wz, &bwx, &bwz,
|
||||||
|
&leavesNoise);
|
||||||
|
leaf = utils::withinDistance(x,y,z, wx, leavesNoise, wz, LEAVES_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!leaf){
|
||||||
|
evaluateTreeCell(cx, cz, wcx, wcz+1, &wcx_offset, &wcz_offset, &wx, &wz, &bwx, &bwz,
|
||||||
|
&leavesNoise);
|
||||||
|
leaf = utils::withinDistance(x,y,z, wx, leavesNoise, wz, LEAVES_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!leaf){
|
||||||
|
evaluateTreeCell(cx, cz, wcx-1, wcz, &wcx_offset, &wcz_offset, &wx, &wz, &bwx, &bwz,
|
||||||
|
&leavesNoise);
|
||||||
|
leaf = utils::withinDistance(x,y,z, wx, leavesNoise, wz, LEAVES_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!leaf){
|
||||||
|
evaluateTreeCell(cx, cz, wcx, wcz-1, &wcx_offset, &wcz_offset, &wx, &wz, &bwx, &bwz,
|
||||||
|
&leavesNoise);
|
||||||
|
leaf = utils::withinDistance(x,y,z, wx, leavesNoise, wz, LEAVES_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wood) block = Block::WOOD;
|
||||||
|
if(leaf) block = Block::LEAVES;
|
||||||
|
|
||||||
if (block != block_prev)
|
if (block != block_prev)
|
||||||
{
|
{
|
||||||
chunk->setBlocks(block_prev_start, s, block_prev);
|
chunk->setBlocks(block_prev_start, s, block_prev);
|
||||||
block_prev_start = s;
|
block_prev_start = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
block_prev = block;
|
block_prev = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk->setBlocks(block_prev_start, CHUNK_VOLUME, block_prev);
|
chunk->setBlocks(block_prev_start, CHUNK_VOLUME, block_prev);
|
||||||
chunk->setState(Chunk::CHUNK_STATE_GENERATED, true);
|
chunk->setState(Chunk::CHUNK_STATE_GENERATED, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,12 @@ int main()
|
||||||
|
|
||||||
std::cout << "Using GPU: " << glGetString(GL_VENDOR) << " " << glGetString(GL_RENDERER) << "\n";
|
std::cout << "Using GPU: " << glGetString(GL_VENDOR) << " " << glGetString(GL_RENDERER) << "\n";
|
||||||
|
|
||||||
SpaceFilling::initLUT();
|
|
||||||
wireframe = false;
|
wireframe = false;
|
||||||
|
for(int i = 0; i < 360; i++){
|
||||||
|
sines[i] = sin(3.14 / 180 * i);
|
||||||
|
cosines[i] = cos(3.14 / 180 * i);
|
||||||
|
}
|
||||||
|
SpaceFilling::initLUT();
|
||||||
renderer::init();
|
renderer::init();
|
||||||
std::thread chunkmanager_thread = chunkmanager::init();
|
std::thread chunkmanager_thread = chunkmanager::init();
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace renderer{
|
||||||
theShader = new Shader{"shaders/shader-texture.gs", "shaders/shader-texture.vs", "shaders/shader-texture.fs"};
|
theShader = new Shader{"shaders/shader-texture.gs", "shaders/shader-texture.vs", "shaders/shader-texture.fs"};
|
||||||
|
|
||||||
// Create 3d array texture
|
// Create 3d array texture
|
||||||
constexpr int layerCount = 3;
|
constexpr int layerCount = 5;
|
||||||
glGenTextures(1, &chunkTexture);
|
glGenTextures(1, &chunkTexture);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, chunkTexture);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, chunkTexture);
|
||||||
|
|
||||||
|
@ -38,6 +38,10 @@ namespace renderer{
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texels1);
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texels1);
|
||||||
unsigned char *texels2 = stbi_load("textures/grass_top.png", &width, &height, &nrChannels, 0);
|
unsigned char *texels2 = stbi_load("textures/grass_top.png", &width, &height, &nrChannels, 0);
|
||||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, texels2);
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, texels2);
|
||||||
|
unsigned char *texels3 = stbi_load("textures/wood.png", &width, &height, &nrChannels, 0);
|
||||||
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 3, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texels3);
|
||||||
|
unsigned char *texels4 = stbi_load("textures/leaves.png", &width, &height, &nrChannels, 0);
|
||||||
|
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 4, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, texels4);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 263 B |
Loading…
Reference in New Issue