载入中...
搜索中...
未找到
TerrainNoiseMask.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <utility>
6#include <vector>
10
11namespace eve::procgen {
12using namespace raster_detail;
13namespace {
14double baseNoise(const NoiseField& field, TerrainNoiseType type, double x, double z) {
15 const double perlin = field.perlinNoise(float(x), float(z));
16 switch (type) {
17 case TerrainNoiseType::Perlin: return perlin;
18 case TerrainNoiseType::Value: return field.valueNoise(float(x), float(z));
19 case TerrainNoiseType::Billow: return std::abs(perlin * 2 - 1);
20 case TerrainNoiseType::Ridge: return 1 - std::abs(perlin * 2 - 1);
22 const int ix = int(std::floor(x)), iz = int(std::floor(z));
23 double best = 1;
24 for (int dz = -2; dz <= 2; ++dz)
25 for (int dx = -2; dx <= 2; ++dx) {
26 const double px = dx + field.hash01(ix + dx, iz + dz) - (x - ix);
27 const double pz = dz + field.hash01(ix + dx + 7919, iz + dz) - (z - iz);
28 best = std::min(best, px * px + pz * pz);
29 }
30 return best;
31 }
32 }
33 return 0;
34}
35
36double fractal(const NoiseField& field, TerrainNoiseType type, double x, double z,
37 const TerrainNoiseMaskSettings& s) {
38 const int whole = int(std::floor(s.octaves));
39 const double fraction = s.octaves - whole;
40 double sum = 0, amplitude = s.amplitude, frequency = s.frequency;
41 for (int i = 0; i < whole; ++i) {
42 sum += amplitude * baseNoise(field, type, x * frequency, z * frequency);
43 amplitude *= s.persistence;
44 frequency *= s.lacunarity;
45 }
46 if (fraction > 0) sum += fraction * amplitude * baseNoise(field, type, x * frequency, z * frequency);
47 return sum;
48}
49} // namespace
50
54 target.getWidth() != input.getWidth() || target.getHeight() != input.getHeight() || curve.getHeight() != 1 ||
56 mode < TerrainMaskBlend::Multiply || mode > TerrainMaskBlend::Subtract || s.scaleX == 0 || s.scaleZ == 0 ||
57 s.octaves < 0 || s.octaves > 16 || s.warpIterations < 0 || s.warpIterations > 16)
58 return invalid("terrain.noiseMask: finite compatible rasters and valid noise controls required");
59 for (float value : {s.translationX, s.translationZ, s.scaleX, s.scaleZ, s.rotation, s.octaves, s.amplitude,
60 s.frequency, s.persistence, s.lacunarity, s.warpIterations, s.warpStrength,
61 s.warpOffsetX, s.warpOffsetZ})
62 if (!std::isfinite(value)) return invalid("terrain.noiseMask: finite controls required");
63 NoiseField field;
64 field.seed = s.seed;
65 const double cosine = std::cos(s.rotation), sine = std::sin(s.rotation);
66 std::vector<float> output(target.data().size());
67 for (int z = 0; z < target.getHeight(); ++z)
68 for (int x = 0; x < target.getWidth(); ++x) {
69 const double ux = (x + 0.5) / target.getWidth() - 0.5;
70 const double uz = (z + 0.5) / target.getHeight() - 0.5;
71 double px = (cosine * ux - sine * uz) * s.scaleX + s.translationX;
72 double pz = (sine * ux + cosine * uz) * s.scaleZ + s.translationZ;
73 const int warpWhole = int(std::floor(s.warpIterations));
74 const double warpFraction = s.warpIterations - warpWhole;
75 for (int i = 0; i < warpWhole + (warpFraction > 0); ++i) {
76 const double qx = fractal(field, s.type, px, pz, s);
77 const double qz = fractal(field, s.type, px + s.warpOffsetX, pz + s.warpOffsetZ, s);
78 const double weight = i == warpWhole ? warpFraction : 1;
79 px += weight * s.warpStrength * qx;
80 pz += weight * s.warpStrength * qz;
81 }
82 const double transformed = curveSample(curve, fractal(field, s.type, px, pz, s));
83 const size_t index = size_t(z) * target.getWidth() + x;
84 const double old = input.data()[index];
85 double result = old;
86 switch (mode) {
87 case TerrainMaskBlend::Multiply: result = old * transformed; break;
88 case TerrainMaskBlend::Maximum: result = std::max(old, transformed); break;
89 case TerrainMaskBlend::Minimum: result = std::min(old, transformed); break;
90 case TerrainMaskBlend::Add: result = old + transformed; break;
91 case TerrainMaskBlend::Subtract: result = old - transformed; break;
92 }
93 if (!isRepresentable(result)) return invalid("terrain.noiseMask: output exceeds finite float range");
94 output[index] = float(result);
95 }
96 return publish(target, std::move(output));
97}
98} // namespace eve::procgen
LogicalId target
double value
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string output
const std::string & s
float pz
EvpackChunkInput input
Definition Evpack.cpp:170
std::vector< Colorf > px
float dz
float dx
std::map< Cell, int > best
Heightmap curve
uint32_t index
float qx
float qz
Move-only operation result carrying either a value or Status.
Definition Result.h:155
Type type() const
Return the active value type.
In-memory terrain heightmap: a dense float grid (row-major, index = y * width + x) materialized from ...
Definition Heightmap.h:21
int getHeight() const
Returns the height.
Definition Heightmap.cpp:17
double curveSample(const Heightmap &curve, double value)
Curve sample.
Result< int > publish(Heightmap &target, std::vector< float > candidate)
Publish.
bool validRaster(const Heightmap &map)
Valid raster.
Result< int > invalid(std::string message)
Invalid.
bool isRepresentable(double value)
True when representable.
const EditorValue * field(const EditorValue &value, const char *name)
Result< int > generateTerrainNoiseMask(Heightmap &target, const Heightmap &input, const Heightmap &curve, const TerrainNoiseMaskSettings &s, TerrainMaskBlend mode)
Generate a transformed Pcg-style fBm noise source, curve it, then combine it with an input mask.
TerrainMaskBlend
Ordered scalar-mask arithmetic; intermediate values are not clamped.
Definition TerrainStamp.h:9
TerrainNoiseType
Pcg NoiseLib families available to the native scalar mask generator.
Deterministic value-noise helpers for pixel textures. When periodX/periodY > 0, lattice wraps for sea...
Definition NoiseField.h:13
Value-only 2D NoiseMask transform, fBm, optional domain-warp and deterministic-stream settings.