载入中...
搜索中...
未找到
Biome.cpp
浏览该文件的文档.
1#include "procgen/Biome.h"
2
3#include <algorithm>
4#include <sstream>
5
6namespace eve::procgen {
7namespace {
8
9uint32_t mixBiome(uint32_t value) {
10 value += 0x9e3779b9u;
11 value = (value ^ (value >> 16u)) * 0x21f0aaadu;
12 value = (value ^ (value >> 15u)) * 0x735a2d97u;
13 return value ^ (value >> 15u);
14}
15
16float biomeUnit(uint32_t seed) { return float(mixBiome(seed) >> 8u) * (1.f / 16777216.f); }
17
18} // namespace
19
21 layers_.clear();
22 exclusions_.clear();
23 error_.clear();
24 lastCandidateCount_ = 0;
25 lastOutputCount_ = 0;
26}
27
28bool BiomeRules::addLayer(const std::string& name, SpatialData* spatial, int priority, float density) {
29 if (name.empty() || !spatial || hasLayer(name)) return false;
31 layer.name = name;
32 layer.priority = priority;
33 layer.density = std::clamp(density, 0.f, 1.f);
34 layer.spatial = std::make_shared<SpatialData>(*spatial);
35 layers_.push_back(std::move(layer));
36 return true;
37}
38
39bool BiomeRules::removeLayer(const std::string& name) {
40 const auto found =
41 std::find_if(layers_.begin(), layers_.end(), [&](const BiomeLayerRule& layer) { return layer.name == name; });
42 if (found == layers_.end()) return false;
43 layers_.erase(found);
44 return true;
45}
46
47bool BiomeRules::hasLayer(const std::string& name) const { return findLayer(name) != nullptr; }
48int BiomeRules::getLayerCount() const { return int(layers_.size()); }
49std::string BiomeRules::getLayerName(int index) const {
50 return index >= 0 && index < int(layers_.size()) ? layers_[size_t(index)].name : std::string();
51}
52int BiomeRules::getLayerPriority(const std::string& name) const {
53 const auto* layer = findLayer(name);
54 return layer ? layer->priority : 0;
55}
56float BiomeRules::getLayerDensity(const std::string& name) const {
57 const auto* layer = findLayer(name);
58 return layer ? layer->density : 0.f;
59}
60
61bool BiomeRules::addAsset(const std::string& layerName, const std::string& asset, float weight, float minScale,
62 float maxScale, bool randomYaw) {
63 auto* layer = findLayer(layerName);
64 if (!layer || asset.empty() || weight <= 0.f || minScale <= 0.f || maxScale <= 0.f) return false;
65 if (minScale > maxScale) std::swap(minScale, maxScale);
66 layer->assets.push_back({asset, weight, minScale, maxScale, randomYaw});
67 return true;
68}
69
70int BiomeRules::getAssetCount(const std::string& layerName) const {
71 const auto* layer = findLayer(layerName);
72 return layer ? int(layer->assets.size()) : 0;
73}
74std::string BiomeRules::getAssetName(const std::string& layerName, int index) const {
75 const auto* layer = findLayer(layerName);
76 return layer && index >= 0 && index < int(layer->assets.size()) ? layer->assets[size_t(index)].asset
77 : std::string();
78}
79
81 if (!spatial) return false;
82 exclusions_.push_back(std::make_shared<SpatialData>(*spatial));
83 return true;
84}
85int BiomeRules::getExclusionCount() const { return int(exclusions_.size()); }
86
87PointSet* BiomeRules::generate(SpatialData* domain, float spacing, uint32_t seed, float jitter) {
88 error_.clear();
89 lastCandidateCount_ = 0;
90 lastOutputCount_ = 0;
91 if (!domain || spacing <= 0.f) {
92 error_ = "generate: requires domain and positive spacing";
93 return nullptr;
94 }
95 if (layers_.empty()) {
96 error_ = "generate: no biome layers";
97 return nullptr;
98 }
99 PointSet candidates = domain->sample(spacing, seed, jitter);
100 lastCandidateCount_ = candidates.getCount();
102 for (size_t candidateIndex = 0; candidateIndex < candidates.points().size(); ++candidateIndex) {
103 const auto& candidate = candidates.points()[candidateIndex];
104 bool excluded = false;
105 for (const auto& exclusion : exclusions_) {
106 if (exclusion->contains(candidate.x, candidate.y, candidate.z)) {
107 excluded = true;
108 break;
109 }
110 }
111 if (excluded) continue;
112
113 const BiomeLayerRule* selected = nullptr;
114 for (const auto& layer : layers_) {
115 if (!layer.spatial->contains(candidate.x, candidate.y, candidate.z)) continue;
116 if (!selected || layer.priority > selected->priority) selected = &layer;
117 }
118 if (!selected || selected->assets.empty()) continue;
119 const uint32_t densitySeed = mixBiome(seed ^ candidate.seed ^ 0x243f6a88u);
120 if (biomeUnit(densitySeed) >= selected->density) continue;
121
122 float totalWeight = 0.f;
123 for (const auto& asset : selected->assets) totalWeight += asset.weight;
124 float choice = biomeUnit(densitySeed ^ 0xb7e15162u) * totalWeight;
125 const BiomeAssetRule* selectedAsset = &selected->assets.back();
126 for (const auto& asset : selected->assets) {
127 choice -= asset.weight;
128 if (choice <= 0.f) {
129 selectedAsset = &asset;
130 break;
131 }
132 }
133
134 ProcgenPoint point = candidate;
135 point.density = selected->density;
136 const float scaleT = biomeUnit(densitySeed ^ 0x9e3779b9u);
137 const float scale = selectedAsset->minScale + (selectedAsset->maxScale - selectedAsset->minScale) * scaleT;
138 point.scaleX = point.scaleY = point.scaleZ = scale;
139 if (selectedAsset->randomYaw) point.yaw = biomeUnit(densitySeed ^ 0xdeadbeefu) * 360.f;
140 const int outputIndex =
141 std::move(output.appendPointFrom(candidates, candidateIndex)).expect("biome output attribute schema");
142 output.mutablePoint(size_t(outputIndex)) = std::move(point);
143 output.trySetStringAttribute(outputIndex, "biome", selected->name).expect("biome metadata schema");
144 output.trySetStringAttribute(outputIndex, "asset", selectedAsset->asset).expect("biome asset metadata schema");
145 }
146 lastOutputCount_ = output.getCount();
147 return new PointSet(std::move(output));
148}
149
150std::string BiomeRules::getError() const { return error_; }
151std::string BiomeRules::debugReport() const {
152 std::ostringstream out;
153 out << "layers=" << layers_.size() << " exclusions=" << exclusions_.size() << " candidates=" << lastCandidateCount_
154 << " output=" << lastOutputCount_;
155 if (!error_.empty()) out << " error=" << error_;
156 return out.str();
157}
158
159BiomeLayerRule* BiomeRules::findLayer(const std::string& name) {
160 const auto found =
161 std::find_if(layers_.begin(), layers_.end(), [&](const BiomeLayerRule& layer) { return layer.name == name; });
162 return found == layers_.end() ? nullptr : &*found;
163}
164const BiomeLayerRule* BiomeRules::findLayer(const std::string& name) const {
165 const auto found =
166 std::find_if(layers_.begin(), layers_.end(), [&](const BiomeLayerRule& layer) { return layer.name == name; });
167 return found == layers_.end() ? nullptr : &*found;
168}
169
170} // namespace eve::procgen
double value
std::string output
eve::action::ActionSpatialBinding spatial
int priority
std::array< float, 3 > scale
std::string name
TileLayer * layer
std::uint32_t seed
Definition PointSet.cpp:807
bool found
int spacing
float size
Definition TreeMesh.cpp:156
uint32_t index
glm::vec3 point
std::string getLayerName(int index) const
Returns the layer name.
Definition Biome.cpp:49
int getExclusionCount() const
Returns the exclusion count.
Definition Biome.cpp:85
bool addAsset(const std::string &layerName, const std::string &asset, float weight, float minScale, float maxScale, bool randomYaw)
Add a weighted asset rule to a layer.
Definition Biome.cpp:61
std::string getError() const
Returns the error.
Definition Biome.cpp:150
int getLayerPriority(const std::string &name) const
Returns the layer priority.
Definition Biome.cpp:52
float getLayerDensity(const std::string &name) const
Returns the layer density.
Definition Biome.cpp:56
std::string getAssetName(const std::string &layerName, int index) const
Returns the asset name.
Definition Biome.cpp:74
bool hasLayer(const std::string &name) const
True when layer.
Definition Biome.cpp:47
int getAssetCount(const std::string &layerName) const
Returns the asset count.
Definition Biome.cpp:70
int getLayerCount() const
Returns the layer count.
Definition Biome.cpp:48
bool addLayer(const std::string &name, SpatialData *spatial, int priority, float density)
Add a named spatial layer. Names are unique.
Definition Biome.cpp:28
bool removeLayer(const std::string &name)
Removes layer.
Definition Biome.cpp:39
void clear()
Remove layers and exclusions.
Definition Biome.cpp:20
bool addExclusion(SpatialData *spatial)
Add a copied spatial exclusion shared by every layer.
Definition Biome.cpp:80
std::string debugReport() const
Debug report.
Definition Biome.cpp:151
PointSet * generate(SpatialData *domain, float spacing, uint32_t seed, float jitter)
Generate attributed biome points.
Definition Biome.cpp:87
Script-friendly collection of attributed 3D samples.
Definition PointSet.h:59
const std::vector< ProcgenPoint > & points() const
Borrow immutable point rows; structural ownership remains with this set.
Definition PointSet.h:212
int getCount() const
Returns the count.
Definition PointSet.cpp:48
Queryable spatial input for procedural pipelines.
Definition SpatialData.h:35
PointSet sample(float spacing, uint32_t seed, float jitter) const
Deterministically sample a 3D lattice inside the domain.
One weighted asset entry in a procedural biome layer.
Definition Biome.h:16
One spatially-defined biome layer and its asset table.
Definition Biome.h:25
std::vector< BiomeAssetRule > assets
Definition Biome.h:30
One deterministic sample used by script-first procedural pipelines.
Definition PointSet.h:17