载入中...
搜索中...
未找到
CaveNormals.cpp
浏览该文件的文档.
2
3#include "procgen/MeshBuild.h"
5
6#include <cmath>
7#include <cstdint>
8#include <unordered_map>
9
10namespace eve::procgen {
11namespace {
12
13struct VertexKey {
14 int x = 0, y = 0, z = 0, island = 0;
15
16 bool operator==(const VertexKey& other) const {
17 return x == other.x && y == other.y && z == other.z && island == other.island;
18 }
19};
20
21uint32_t hashCoordinate(uint32_t value) {
22 value ^= value >> 16u;
23 value *= 0x7feb352du;
24 value ^= value >> 15u;
25 value *= 0x846ca68bu;
26 return value ^ (value >> 16u);
27}
28
29struct VertexKeyHash {
30 size_t operator()(const VertexKey& key) const {
31 size_t value = size_t(hashCoordinate(uint32_t(key.x)));
32 value ^= size_t(hashCoordinate(uint32_t(key.y))) << 1u;
33 value ^= size_t(hashCoordinate(uint32_t(key.z))) << 2u;
34 value ^= size_t(key.island) * 0x9e3779b9u;
35 return value;
36 }
37};
38
39struct Vec3 {
40 float x = 0.f, y = 0.f, z = 0.f;
41};
42
43Vec3 normalized(Vec3 value) {
44 const float length = std::sqrt(value.x * value.x + value.y * value.y + value.z * value.z);
45 return length > 1e-8f ? Vec3{value.x / length, value.y / length, value.z / length} : Vec3{};
46}
47
48} // namespace
49
50CaveNormalStatus applyCaveSurfaceNormals(MeshBuild& mesh, const std::vector<float>& density, int nx, int ny, int nz,
51 float width, float height, float depth, const std::string& mode, float blend,
52 std::string& error) {
53 if (mode != "faceAverage" && mode != "densityGradient") {
54 error = "mesh.cave: unknown surfaceNormalMode '" + mode + "' (use faceAverage|densityGradient)";
56 }
57
58 auto& normals = mesh.normals();
59 if (mode == "densityGradient") {
60 for (int vertex = 0; vertex < mesh.getVertexCount(); ++vertex) {
61 const CaveFieldPoint point{mesh.getPositionX(vertex) * 2.f, mesh.getPositionY(vertex) * 2.f,
62 mesh.getPositionZ(vertex) * 2.f};
63 const CaveFieldPoint gradient = sampleCaveDensityGradient(density, nx, ny, nz, point);
64 const Vec3 fieldNormal = normalized({-gradient.x / width, -gradient.y / height, -gradient.z / depth});
65 const size_t offset = size_t(vertex) * 3u;
66 const Vec3 faceNormal =
67 normalized({normals[offset] / width, normals[offset + 1] / height, normals[offset + 2] / depth});
68 const Vec3 blended = normalized({faceNormal.x + (fieldNormal.x - faceNormal.x) * blend,
69 faceNormal.y + (fieldNormal.y - faceNormal.y) * blend,
70 faceNormal.z + (fieldNormal.z - faceNormal.z) * blend});
71 if (blended.x != 0.f || blended.y != 0.f || blended.z != 0.f) {
72 normals[offset] = blended.x;
73 normals[offset + 1] = blended.y;
74 normals[offset + 2] = blended.z;
75 }
76 }
78 }
79
80 std::unordered_map<VertexKey, Vec3, VertexKeyHash> normalSums;
81 normalSums.reserve(size_t(mesh.getVertexCount()));
82 auto vertexKey = [&](int vertex) {
83 const int triangle = vertex / 3;
84 // Wet and dry limestone are one continuous surface. Secondary calcite
85 // deposits keep a separate smoothing island at their material seam.
86 const int island = mesh.getTriangleGroup(triangle) == 1 ? 1 : 0;
87 return VertexKey{int(std::lround(mesh.getPositionX(vertex) * 10000.f)),
88 int(std::lround(mesh.getPositionY(vertex) * 10000.f)),
89 int(std::lround(mesh.getPositionZ(vertex) * 10000.f)), island};
90 };
91 for (int vertex = 0; vertex < mesh.getVertexCount(); ++vertex) {
92 const size_t offset = size_t(vertex) * 3u;
93 const Vec3 worldNormal =
94 normalized({normals[offset] / width, normals[offset + 1] / height, normals[offset + 2] / depth});
95 normals[offset] = worldNormal.x;
96 normals[offset + 1] = worldNormal.y;
97 normals[offset + 2] = worldNormal.z;
98 Vec3& sum = normalSums[vertexKey(vertex)];
99 sum.x += worldNormal.x;
100 sum.y += worldNormal.y;
101 sum.z += worldNormal.z;
102 }
103 for (int vertex = 0; vertex < mesh.getVertexCount(); ++vertex) {
104 const Vec3 average = normalized(normalSums[vertexKey(vertex)]);
105 if (average.x == 0.f && average.y == 0.f && average.z == 0.f) continue;
106 const size_t offset = size_t(vertex) * 3u;
107 const Vec3 smoothed = normalized({normals[offset] + (average.x - normals[offset]) * blend,
108 normals[offset + 1] + (average.y - normals[offset + 1]) * blend,
109 normals[offset + 2] + (average.z - normals[offset + 2]) * blend});
110 normals[offset] = smoothed.x;
111 normals[offset + 1] = smoothed.y;
112 normals[offset + 2] = smoothed.z;
113 }
115}
116
117} // namespace eve::procgen
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
float length
Definition CaveMesh.cpp:94
int island
float nx
float nz
float ny
int triangle
std::uint32_t key
std::vector< float > normals
float blend
std::uint32_t height
std::uint32_t width
size_t offset
std::string error
Definition Package.cpp:60
Mesh * mesh
std::uint32_t depth
glm::vec3 point
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
CaveNormalStatus applyCaveSurfaceNormals(MeshBuild &mesh, const std::vector< float > &density, int nx, int ny, int nz, float width, float height, float depth, const std::string &mode, float blend, std::string &error)
Applies cave surface normals.
CaveFieldPoint sampleCaveDensityGradient(const std::vector< float > &density, int nx, int ny, int nz, CaveFieldPoint point)
Sample cave density gradient.
CaveNormalStatus
CaveNormalStatus public API.
Definition CaveNormals.h:11
CaveFieldPoint public API.