- Joined
- Oct 20, 2022
- Messages
- 3
- Reaction score
- 0
C++:
float clampDepth(float height) {
float minH = 5.92457f;
float maxH = 7.05437f;
float hNorm = (height - minH) / (maxH - minH); // 0..1
if (hNorm < .2) hNorm = .2;
return hNorm;
}
float getFinalHeight(float worldX, float worldZ)
{
float h = terrainHeight(worldX, worldZ, WORLD_SEED);
float minH = 5.92457f;
float maxH = 7.05437f;
float hNorm = (h - minH) / (maxH - minH);
if (hNorm < 0.2f) hNorm = 0.2f;
return (hNorm - 0.2f) * 25.0f;
}
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image/stb_image_write.h"
glm::vec3 getDiffuseColor(float worldHeight)
{
float maxWorldHeight = (1.0f - 0.2f) * 25.0f; // = 20
float hNorm = worldHeight / maxWorldHeight;
hNorm = 1 - hNorm;
glm::vec3 color;
if (hNorm < 0.2f) color = glm::vec3(0.1f, 0.3f, 0.8f);
else if (hNorm < 0.4f) color = glm::vec3(0.6f, 0.5f, 0.3f);
else if (hNorm < 0.7f) color = glm::vec3(0.2f, 0.7f, 0.2f);
else color = glm::vec3(0.8f);
return color;
}
void GenDiff() {
int texSize = 1024;
std::vector<unsigned char> diffuse(texSize * texSize * 3); // RGB
for (int y = 0; y < texSize; y++) {
for (int x = 0; x < texSize; x++) {
float u = float(x) / (texSize - 1);
float v = float(y) / (texSize - 1);
float worldX = chunkOriginX + (x / float(texSize - 1)) * chunkWidth;
float worldZ = chunkOriginZ + (y / float(texSize - 1)) * chunkWidth;
//float height = terrainHeight(worldX, worldZ, WORLD_SEED);
float height = getFinalHeight(worldX, worldZ);
glm::vec3 color = getDiffuseColor(height);
int idx = (y * texSize + x) * 3;
diffuse[idx + 0] = static_cast<unsigned char>(color.r * 255);
diffuse[idx + 1] = static_cast<unsigned char>(color.g * 255);
diffuse[idx + 2] = static_cast<unsigned char>(color.b * 255);
}
}
stbi_write_png("diffuse.png", texSize, texSize, 3, diffuse.data(), texSize * 3);
}
#pragma once
#include <iostream>
#include "glm/glm.hpp"
#include <assimp/scene.h> // aiScene, aiNode, aiMesh, aiMaterial
#include <assimp/types.h>
#include <assimp/Exporter.hpp>
#include "Noise.h"
#include "Vals.h"
glm::vec3 computeNormal(float worldX, float worldZ, float step)
{
float hL = terrainHeight(worldX - step, worldZ, WORLD_SEED);
float hR = terrainHeight(worldX + step, worldZ, WORLD_SEED);
float hD = terrainHeight(worldX, worldZ - step, WORLD_SEED);
float hU = terrainHeight(worldX, worldZ + step, WORLD_SEED);
glm::vec3 n(
hL - hR,
2.0f * step,
hD - hU
);
return glm::normalize(n);
}
void ModelGen() {
int numChunks = 1;
aiScene* scene = new aiScene();
scene->mRootNode = new aiNode();
scene->mNumMeshes = numChunks;
scene->mMeshes = new aiMesh * [numChunks];
aiMesh* mesh = new aiMesh();
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
int N = 64;
float chunkWidth = 64.0;
float step = chunkWidth / (N - 1);
int vertexCount = N * N;
mesh->mNumVertices = vertexCount;
mesh->mVertices = new aiVector3D[vertexCount];
mesh->mNormals = new aiVector3D[vertexCount];
mesh->mTextureCoords[0] = new aiVector3D[vertexCount];
mesh->mNumUVComponents[0] = 2;
int chunkX = 0;
int chunkZ = 0;
int index = 0;
for (int z = 0; z < N; z++)
{
for (int x = 0; x < N; x++)
{
float worldX = chunkOriginX + (x / float(N - 1)) * chunkWidth;
float worldZ = chunkOriginZ + (z / float(N - 1)) * chunkWidth;
float y = terrainHeight(worldX, worldZ, WORLD_SEED);
y = (clampDepth(y) - .2) * 25;
mesh->mVertices[index] = aiVector3D(
(float)worldX,
y,
(float)worldZ
);
aiVector3D norm;
glm::vec3 onorm = computeNormal(worldX, worldZ, step);
norm.x = onorm.x;
norm.y = onorm.y;
norm.z = onorm.z;
mesh->mNormals[index] = norm;
mesh->mTextureCoords[0][index] = aiVector3D(
x / float(N - 1),
z / float(N - 1),
0.0f
);
index++;
}
}
int faceCount = (N - 1) * (N - 1) * 2;
mesh->mNumFaces = faceCount;
mesh->mFaces = new aiFace[faceCount];
int faceIndex = 0;
for (int z = 0; z < N - 1; z++)
{
for (int x = 0; x < N - 1; x++)
{
unsigned int i0 = z * N + x;
unsigned int i1 = z * N + x + 1;
unsigned int i2 = (z + 1) * N + x;
unsigned int i3 = (z + 1) * N + x + 1;
// Triangle 1
mesh->mFaces[faceIndex].mNumIndices = 3;
mesh->mFaces[faceIndex].mIndices = new unsigned int[3] { i0, i2, i1 };
faceIndex++;
// Triangle 2
mesh->mFaces[faceIndex].mNumIndices = 3;
mesh->mFaces[faceIndex].mIndices = new unsigned int[3] { i1, i2, i3 };
faceIndex++;
}
}
scene->mMeshes[0] = mesh;
aiNode* node = new aiNode();
node->mName = aiString("chunk_0_0");
node->mNumMeshes = 1;
node->mMeshes = new unsigned int[1] { 0 };
scene->mRootNode->addChildren(1, &node);
Assimp::Exporter exporter;
exporter.Export(scene, "obj", "terrain.obj");
}
static inline float lerp(float a, float b, float t)
{
return a + t * (b - a);
}
static inline float fade(float t)
{
// Perlin fade curve
return t * t * t * (t * (t * 6 - 15) + 10);
}
static inline uint32_t hash2D(int x, int y, uint32_t seed)
{
uint32_t h = seed;
h ^= x * 374761393u;
h ^= y * 668265263u;
h = (h ^ (h >> 13)) * 1274126177u;
return h;
}
static inline float hashFloat(int x, int y, uint32_t seed)
{
return (hash2D(x, y, seed) & 0xFFFFFF) / float(0xFFFFFF);
}
float valueNoise2D(float x, float y, uint32_t seed)
{
int x0 = (int)std::floor(x);
int y0 = (int)std::floor(y);
int x1 = x0 + 1;
int y1 = y0 + 1;
float sx = fade(x - x0);
float sy = fade(y - y0);
float n00 = hashFloat(x0, y0, seed);
float n10 = hashFloat(x1, y0, seed);
float n01 = hashFloat(x0, y1, seed);
float n11 = hashFloat(x1, y1, seed);
float ix0 = lerp(n00, n10, sx);
float ix1 = lerp(n01, n11, sx);
return lerp(ix0, ix1, sy);
}
static inline void gradient(int x, int y, uint32_t seed, float& gx, float& gy)
{
uint32_t h = hash2D(x, y, seed) & 7;
gx = (h < 4) ? 1.0f : -1.0f;
gy = (h & 1) ? 1.0f : -1.0f;
}
float perlin2D(float x, float y, uint32_t seed)
{
int x0 = (int)std::floor(x);
int y0 = (int)std::floor(y);
int x1 = x0 + 1;
int y1 = y0 + 1;
float fx = x - x0;
float fy = y - y0;
float sx = fade(fx);
float sy = fade(fy);
float gx0, gy0, gx1, gy1;
gradient(x0, y0, seed, gx0, gy0);
float d00 = gx0 * fx + gy0 * fy;
gradient(x1, y0, seed, gx1, gy1);
float d10 = gx1 * (fx - 1) + gy1 * fy;
gradient(x0, y1, seed, gx0, gy0);
float d01 = gx0 * fx + gy0 * (fy - 1);
gradient(x1, y1, seed, gx1, gy1);
float d11 = gx1 * (fx - 1) + gy1 * (fy - 1);
float ix0 = lerp(d00, d10, sx);
float ix1 = lerp(d01, d11, sx);
return lerp(ix0, ix1, sy); // approx -1 to 1
}
float fbm2D(float x, float y, uint32_t seed,
int octaves = 5,
float lacunarity = 2.0f,
float gain = 0.5f)
{
float sum = 0.0f;
float amp = 1.0f;
float freq = 1.0f;
for (int i = 0; i < octaves; ++i)
{
sum += perlin2D(x * freq, y * freq, seed + i) * amp;
freq *= lacunarity;
amp *= gain;
}
return sum;
}
float ridgedNoise2D(float x, float y, uint32_t seed,
int octaves = 4)
{
float sum = 0.0f;
float freq = 1.0f;
float amp = 0.5f;
for (int i = 0; i < octaves; ++i)
{
float n = perlin2D(x * freq, y * freq, seed + i);
n = 1.0f - std::abs(n);
sum += n * amp;
freq *= 2.0f;
amp *= 0.5f;
}
return sum;
}
float terrainHeight(int worldX, int worldZ, uint32_t seed)
{
float x = float(worldX);
float z = float(worldZ);
float continent = valueNoise2D(x * 0.0005f, z * 0.0005f, seed);
continent = std::clamp(continent * 1.2f - 0.2f, 0.0f, 1.0f);
float mountains = ridgedNoise2D(x * 0.002f, z * 0.002f, seed + 100);
float detail = fbm2D(x * 0.01f, z * 0.01f, seed + 200);
float height =
continent * (
20.0f +
mountains * 60.0f +
detail * 10.0f
);
return height;
}
I got this code from an AI generator. This is a view of the model in Blender with the Z direction pointing straight upward. the lower and flat part is supposed to be blue and the higher parts are supposed to be white. There must be some mistake other than the height. Both the texture and the model are generated with the same function. When I get this fixed if I do I would like to be able to generate flat land features which this does not do.