载入中...
搜索中...
未找到
TextureRecipe.cpp
浏览该文件的文档.
2
3#include "image/ImageData.h"
4
5#include <algorithm>
6#include <cctype>
7#include <cmath>
8#include <utility>
9
10namespace eve::procgen {
11
16
20 descriptor.displayName = id;
21 registerRecipe(std::move(descriptor), std::move(fn));
22}
23
25 const std::string id = descriptor.id;
26 recipes_[id] = Entry{std::move(fn), std::move(descriptor)};
27}
28
29bool TextureRecipeRegistry::has(const std::string &id) const {
30 return recipes_.find(id) != recipes_.end();
31}
32
33std::unique_ptr<image::ImageData> TextureRecipeRegistry::generate(const std::string &id, const Params &params,
34 std::string &error) const {
35 auto it = recipes_.find(id);
36 if (it == recipes_.end()) {
37 error = "unknown texture recipe: " + id;
38 return {};
39 }
40 return it->second.fn(params, error);
41}
42
43const RecipeDescriptor *TextureRecipeRegistry::descriptor(const std::string &id) const {
44 const auto it = recipes_.find(id);
45 return it == recipes_.end() ? nullptr : &it->second.descriptor;
46}
47
48bool TextureRecipeRegistry::applyDefaults(const std::string &id, Params &params) const {
49 const RecipeDescriptor *schema = descriptor(id);
50 if (!schema) return false;
51 schema->applyDefaults(params);
52 return true;
53}
54
55std::vector<std::string> TextureRecipeRegistry::list() const {
56 std::vector<std::string> ids;
57 ids.reserve(recipes_.size());
58 for (const auto &kv : recipes_) ids.push_back(kv.first);
59 std::sort(ids.begin(), ids.end());
60 return ids;
61}
62
65 ctx.width = std::max(1, params.getWidth());
66 ctx.height = std::max(1, params.getHeight());
67 ctx.seed = params.getSeed();
68 ctx.scale = std::max(0.05f, params.getFloat("scale", 4.f));
69 ctx.octaves = std::max(1, params.getInt("octaves", 4));
70 ctx.colors = std::max(2, params.getInt("colors", 6));
71 ctx.pixelSize = std::max(1, params.getInt("pixelSize", 1));
72 ctx.seamless = params.getInt("seamless", 1) != 0;
73 ctx.warpAmp = params.getFloat("warp", 1.f);
74 return ctx;
75}
76
79 p.roughnessLow = std::clamp(params.getFloat("roughnessLow", p.roughnessLow), 0.f, 1.f);
80 p.roughnessHigh = std::clamp(params.getFloat("roughnessHigh", p.roughnessHigh), 0.f, 1.f);
81 p.metallic = std::clamp(params.getFloat("metallic", p.metallic), 0.f, 1.f);
82 p.normalStrength = std::max(0.01f, params.getFloat("normalStrength", p.normalStrength));
83 p.aoStrength = std::clamp(params.getFloat("aoStrength", p.aoStrength), 0.f, 5.f);
84 p.heightStrength = std::max(0.f, params.getFloat("heightStrength", p.heightStrength));
85 return p;
86}
87
89 std::string displayName = definition.id;
90 const size_t dot = displayName.find('.');
91 if (dot != std::string::npos) displayName.erase(0, dot + 1);
92 for (char &ch : displayName) {
93 if (ch == '_') ch = ' ';
94 }
95 if (!displayName.empty())
96 displayName[0] = char(std::toupper(static_cast<unsigned char>(displayName[0])));
97
98 RecipeDescriptor descriptor = RecipeDescriptor::grid(definition.id, displayName, "Texture", 1, 1);
99 descriptor.params.push_back(ParamDescriptor::floating("scale", "Scale", 4.f, 0.05f, 256.f, 0.05f));
100 descriptor.params.push_back(ParamDescriptor::integer("octaves", "Octaves", 4, 1, 16));
101 descriptor.params.push_back(ParamDescriptor::integer("colors", "Color Bands", 6, 2, 64));
102 descriptor.params.push_back(ParamDescriptor::integer("pixelSize", "Pixel Size", 1, 1, 64));
103 descriptor.params.push_back(ParamDescriptor::boolean("seamless", "Seamless", true));
104 descriptor.params.push_back(ParamDescriptor::floating("warp", "Warp", 1.f, 0.f, 32.f, 0.05f));
105 return descriptor;
106}
107
109 const std::function<float(float, float, const NoiseField &)> &fn,
110 std::vector<float> &height) {
111 height.resize(size_t(ctx.width) * size_t(ctx.height));
113 n.seed = ctx.seed;
114 if (ctx.seamless) {
115 n.periodX = std::max(1, int(std::lround(ctx.scale)));
116 n.periodY = std::max(1, int(std::lround(ctx.scale * float(ctx.height) /
117 float(std::max(1, ctx.width)))));
118 }
119 for (int y = 0; y < ctx.height; ++y) {
120 for (int x = 0; x < ctx.width; ++x) {
121 const float u = float(x) / float(ctx.width) * ctx.scale;
122 const float v = float(y) / float(ctx.height) * ctx.scale;
123 height[size_t(y * ctx.width + x)] = std::clamp(fn(u, v, n), 0.f, 1.f);
124 }
125 }
126}
127
128void paintHeightToImage(image::ImageData &img, const std::vector<float> &height, int w, int h,
129 const ColorRamp &ramp, int bands, int pixelSize) {
130 auto *pixels = static_cast<uint8_t *>(img.getData());
131 if (!pixels || int(height.size()) < w * h) return;
132 pixelSize = std::max(1, pixelSize);
133 for (int y = 0; y < h; ++y) {
134 const int by = (y / pixelSize) * pixelSize;
135 for (int x = 0; x < w; ++x) {
136 const int bx = (x / pixelSize) * pixelSize;
137 const float t = height[size_t(by * w + bx)];
138 const Rgba8 c = ramp.sampleBanded(t, bands);
139 const size_t i = (size_t(y) * size_t(w) + size_t(x)) * 4u;
140 pixels[i + 0] = c.r;
141 pixels[i + 1] = c.g;
142 pixels[i + 2] = c.b;
143 pixels[i + 3] = c.a;
144 }
145 }
146}
147
148std::unique_ptr<image::ImageData> heightToNormalImage(const std::vector<float> &height, int w, int h, float strength,
149 bool seamless) {
150 auto img = std::make_unique<image::ImageData>(w, h, "RGBA8");
151 auto *pixels = static_cast<uint8_t *>(img->getData());
152 auto sample = [&](int x, int y) -> float {
153 if (seamless) {
154 x = (x % w + w) % w;
155 y = (y % h + h) % h;
156 } else {
157 x = std::clamp(x, 0, w - 1);
158 y = std::clamp(y, 0, h - 1);
159 }
160 return height[size_t(y * w + x)];
161 };
162 strength = std::max(0.01f, strength);
163 for (int y = 0; y < h; ++y) {
164 for (int x = 0; x < w; ++x) {
165 const float dx = (sample(x + 1, y) - sample(x - 1, y)) * strength;
166 const float dy = (sample(x, y + 1) - sample(x, y - 1)) * strength;
167 float nx = -dx, ny = -dy, nz = 1.f;
168 const float len = std::sqrt(nx * nx + ny * ny + nz * nz);
169 if (len > 1e-6f) {
170 nx /= len;
171 ny /= len;
172 nz /= len;
173 }
174 const size_t i = (size_t(y) * size_t(w) + size_t(x)) * 4u;
175 pixels[i + 0] = uint8_t(std::lround((nx * 0.5f + 0.5f) * 255.f));
176 pixels[i + 1] = uint8_t(std::lround((ny * 0.5f + 0.5f) * 255.f));
177 pixels[i + 2] = uint8_t(std::lround((nz * 0.5f + 0.5f) * 255.f));
178 pixels[i + 3] = 255;
179 }
180 }
181 return img;
182}
183
184} // namespace eve::procgen
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
std::string descriptor
bool seamless
int bx
Definition CaveMesh.cpp:114
int by
Definition CaveMesh.cpp:114
float nx
float nz
float ny
glm::vec4 p[6]
int pixelSize
glm::uvec4 ids
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
float v
std::int32_t c
int h
std::uint32_t height
std::string error
Definition Package.cpp:60
std::string id
Definition PlayHost.cpp:108
float t
uint8_t * pixels
float dy
float dx
Represents raw pixel data.
Definition ImageData.h:38
void * getData() const
Owning, typed generation parameters.
Definition Params.h:27
EVENGINE_API_DOMAINS public API.
bool has(const std::string &id) const
Test whether a recipe exists.
bool applyDefaults(const std::string &id, Params &params) const
Fill missing values from metadata.
std::unique_ptr< image::ImageData > generate(const std::string &id, const Params &params, std::string &error) const
Generates an image and transfers its unique ownership to the caller.
const RecipeDescriptor * descriptor(const std::string &id) const
Look up recipe metadata.
void registerRecipe(const std::string &id, TextureRecipeFn fn)
Register a recipe without metadata.
std::vector< std::string > list() const
List registered recipe ids.
static TextureRecipeRegistry & instance()
Access the process-wide texture recipe registry.
std::vector< ParamSpec > params
double sample(const Heightmap &map, double u, double v)
Sample.
std::function< std::unique_ptr< image::ImageData >(const Params &params, std::string &error)> TextureRecipeFn
Recipe returns a newly owned RGBA8 image, or null on failure.
RecipeDescriptor makeTextureRecipeDescriptor(const TextureRecipeDef &definition)
Build editable metadata for a texture definition.
void paintHeightToImage(image::ImageData &img, const std::vector< float > &height, int w, int h, const ColorRamp &ramp, int bands, int pixelSize)
Paint height to image.
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::unique_ptr< image::ImageData > heightToNormalImage(const std::vector< float > &height, int w, int h, float strength, bool seamless)
Builds a normal-map image and transfers its unique ownership to the caller.
SettlementPipeline::Stage fn
Piecewise-linear color ramp in t∈[0,1], with optional hard banding.
Definition ColorRamp.h:16
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:13
static ParamDescriptor boolean(std::string key, std::string label, bool defaultValue)
Construct a Boolean descriptor stored as zero or one in Params.
static ParamDescriptor floating(std::string key, std::string label, float defaultValue, float minimum, float maximum, float step)
Construct a bounded floating-point descriptor.
static ParamDescriptor integer(std::string key, std::string label, int defaultValue, int minimum, int maximum, int step=1)
Construct a bounded integer descriptor.
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)
From params.
Complete metadata and parameter schema shared by every procgen recipe family.
Definition ParamSchema.h:52
static RecipeDescriptor grid(std::string id, std::string displayName, std::string category, int minimumWidth, int minimumHeight, int maximumWidth=4096, int maximumHeight=4096)
Create a schema with common seed, width and height parameters.
void applyDefaults(Params &params) const
Fill missing Params values from this schema.
Rgba8 public API.
Definition ColorRamp.h:11
TextureGenContext public API.
static TextureGenContext fromParams(const Params &params)
From params.
A procedural texture is fully described by an albedo ramp + a displacement field + PBR knobs....