载入中...
搜索中...
未找到
TextureRecipe.cpp
浏览该文件的文档.
2
3#include "image/ImageData.h"
4
5#include <algorithm>
6#include <cmath>
7
8namespace eve::procgen {
9
14
16 recipes_[id] = std::move(fn);
17}
18
19bool TextureRecipeRegistry::has(const std::string &id) const {
20 return recipes_.find(id) != recipes_.end();
21}
22
23image::ImageData *TextureRecipeRegistry::generate(const std::string &id, const Params &params,
24 std::string &error) const {
25 auto it = recipes_.find(id);
26 if (it == recipes_.end()) {
27 error = "unknown texture recipe: " + id;
28 return nullptr;
29 }
30 return it->second(params, error);
31}
32
33std::vector<std::string> TextureRecipeRegistry::list() const {
34 std::vector<std::string> ids;
35 ids.reserve(recipes_.size());
36 for (const auto &kv : recipes_) ids.push_back(kv.first);
37 std::sort(ids.begin(), ids.end());
38 return ids;
39}
40
43 ctx.width = std::max(1, params.getWidth());
44 ctx.height = std::max(1, params.getHeight());
45 ctx.seed = params.getSeed();
46 ctx.scale = std::max(0.05f, params.getFloat("scale", 4.f));
47 ctx.octaves = std::max(1, params.getInt("octaves", 4));
48 ctx.colors = std::max(2, params.getInt("colors", 6));
49 ctx.pixelSize = std::max(1, params.getInt("pixelSize", 1));
50 ctx.seamless = params.getInt("seamless", 1) != 0;
51 ctx.warpAmp = params.getFloat("warp", 1.f);
52 return ctx;
53}
54
57 p.roughnessLow = std::clamp(params.getFloat("roughnessLow", p.roughnessLow), 0.f, 1.f);
58 p.roughnessHigh = std::clamp(params.getFloat("roughnessHigh", p.roughnessHigh), 0.f, 1.f);
59 p.metallic = std::clamp(params.getFloat("metallic", p.metallic), 0.f, 1.f);
60 p.normalStrength = std::max(0.01f, params.getFloat("normalStrength", p.normalStrength));
61 p.aoStrength = std::clamp(params.getFloat("aoStrength", p.aoStrength), 0.f, 5.f);
62 p.heightStrength = std::max(0.f, params.getFloat("heightStrength", p.heightStrength));
63 return p;
64}
65
67 const std::function<float(float, float, const NoiseField &)> &fn,
68 std::vector<float> &height) {
69 height.resize(size_t(ctx.width) * size_t(ctx.height));
71 n.seed = ctx.seed;
72 if (ctx.seamless) {
73 n.periodX = std::max(1, int(std::lround(ctx.scale)));
74 n.periodY = std::max(1, int(std::lround(ctx.scale * float(ctx.height) /
75 float(std::max(1, ctx.width)))));
76 }
77 for (int y = 0; y < ctx.height; ++y) {
78 for (int x = 0; x < ctx.width; ++x) {
79 const float u = float(x) / float(ctx.width) * ctx.scale;
80 const float v = float(y) / float(ctx.height) * ctx.scale;
81 height[size_t(y * ctx.width + x)] = std::clamp(fn(u, v, n), 0.f, 1.f);
82 }
83 }
84}
85
86void paintHeightToImage(image::ImageData &img, const std::vector<float> &height, int w, int h,
87 const ColorRamp &ramp, int bands, int pixelSize) {
88 auto *pixels = static_cast<uint8_t *>(img.getData());
89 if (!pixels || int(height.size()) < w * h) return;
90 pixelSize = std::max(1, pixelSize);
91 for (int y = 0; y < h; ++y) {
92 const int by = (y / pixelSize) * pixelSize;
93 for (int x = 0; x < w; ++x) {
94 const int bx = (x / pixelSize) * pixelSize;
95 const float t = height[size_t(by * w + bx)];
96 const Rgba8 c = ramp.sampleBanded(t, bands);
97 const size_t i = (size_t(y) * size_t(w) + size_t(x)) * 4u;
98 pixels[i + 0] = c.r;
99 pixels[i + 1] = c.g;
100 pixels[i + 2] = c.b;
101 pixels[i + 3] = c.a;
102 }
103 }
104}
105
106image::ImageData *heightToNormalImage(const std::vector<float> &height, int w, int h,
107 float strength, bool seamless) {
108 auto *img = new image::ImageData(w, h, "RGBA8");
109 auto *pixels = static_cast<uint8_t *>(img->getData());
110 auto sample = [&](int x, int y) -> float {
111 if (seamless) {
112 x = (x % w + w) % w;
113 y = (y % h + h) % h;
114 } else {
115 x = std::clamp(x, 0, w - 1);
116 y = std::clamp(y, 0, h - 1);
117 }
118 return height[size_t(y * w + x)];
119 };
120 strength = std::max(0.01f, strength);
121 for (int y = 0; y < h; ++y) {
122 for (int x = 0; x < w; ++x) {
123 const float dx = (sample(x + 1, y) - sample(x - 1, y)) * strength;
124 const float dy = (sample(x, y + 1) - sample(x, y - 1)) * strength;
125 float nx = -dx, ny = -dy, nz = 1.f;
126 const float len = std::sqrt(nx * nx + ny * ny + nz * nz);
127 if (len > 1e-6f) {
128 nx /= len;
129 ny /= len;
130 nz /= len;
131 }
132 const size_t i = (size_t(y) * size_t(w) + size_t(x)) * 4u;
133 pixels[i + 0] = uint8_t(std::lround((nx * 0.5f + 0.5f) * 255.f));
134 pixels[i + 1] = uint8_t(std::lround((ny * 0.5f + 0.5f) * 255.f));
135 pixels[i + 2] = uint8_t(std::lround((nz * 0.5f + 0.5f) * 255.f));
136 pixels[i + 3] = 255;
137 }
138 }
139 return img;
140}
141
142} // namespace eve::procgen
std::string id
int y
Definition Grass.cpp:135
float height
Definition Grass.cpp:235
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
std::string error
uint32_t c
glm::vec4 p[6]
SettlementPipeline::Stage fn
int v
Represents raw pixel data.
Definition ImageData.h:26
void * getData() const
Generation parameters. Algorithm-specific keys live in values as strings (no overloads; typed setters...
Definition Params.h:13
uint32_t getSeed() const
Definition Params.cpp:8
int getHeight() const
Definition Params.cpp:15
int getWidth() const
Definition Params.cpp:14
float getFloat(const std::string &key, float defaultValue) const
Definition Params.cpp:32
int getInt(const std::string &key, int defaultValue) const
Definition Params.cpp:23
bool has(const std::string &id) const
void registerRecipe(const std::string &id, TextureRecipeFn fn)
std::vector< std::string > list() const
image::ImageData * generate(const std::string &id, const Params &params, std::string &error) const
static TextureRecipeRegistry & instance()
void paintHeightToImage(image::ImageData &img, const std::vector< float > &height, int w, int h, const ColorRamp &ramp, int bands, int pixelSize)
image::ImageData * heightToNormalImage(const std::vector< float > &height, int w, int h, float strength, bool seamless)
void fillHeightField(const TextureGenContext &ctx, const std::function< float(float, float, const NoiseField &)> &fn, std::vector< float > &height)
Sample a height function over the full [w×h] grid into height (clamped to [0,1]).
std::function< image::ImageData *(const Params &params, std::string &error)> TextureRecipeFn
Recipe returns a new RGBA8 ImageData (caller owns), or nullptr on failure.
Piecewise-linear color ramp in t∈[0,1], with optional hard banding.
Definition ColorRamp.h:13
Rgba8 sampleBanded(float t, int bands) const
Quantize continuous t into bands steps then sample (pixel look).
Definition ColorRamp.cpp:34
Deterministic value-noise helpers for pixel textures. When periodX/periodY > 0, lattice wraps for sea...
Definition NoiseField.h:11
PBR surface defaults for a generated material. Every map in a PBR set is derived from the same displa...
static PbrParams fromParams(const Params &params)
static TextureGenContext fromParams(const Params &params)