载入中...
搜索中...
未找到
GrassPoints.cpp
浏览该文件的文档.
1#include <climits>
2#include <cmath>
3#include <limits>
4#include "graphics/Graphics.h"
5#include "graphics/Grass.h"
6#include "image/ImageData.h"
7namespace eve::graphics {
8Result<int> GrassField::bakePoints(const std::vector<grass::Point>& points, float width, float height) {
9 return bakePointData(points, width, height, nullptr);
10}
11Result<int> GrassField::bakeTexturedPoints(const std::vector<grass::Point>& points, float width, float height,
12 const image::ImageData& image) {
13 return bakePointData(points, width, height, &image);
14}
15Result<int> GrassField::bakeFoliagePoints(const std::vector<grass::Point>& points, float width, float height,
18 return bakePointData(points, width, height, &albedo, &normal, &mask, &settings);
19}
21 if (!foliageProfile_ || !shader_ || !std::isfinite(settings.pcgDetailDistance) ||
22 !std::isfinite(settings.pcgFadeoutDistance) || settings.unityDetailDistance < 0 ||
23 settings.unityDetailDistance > 8388607 ||
24 !std::isfinite(settings.unityDetailDensity) || settings.unityDetailDensity < 0 ||
25 settings.unityDetailDensity > 1)
27 DiagnosticCode::InvalidArgument, "grass.detailOverwrite: uploaded foliage and valid settings required"));
29 profile.renderDistance = shader_->pushConstantData()[13];
30 profile.fadeRange = shader_->pushConstantData()[14];
31 profile.hardRenderDistance = detailHardDistance_;
32 profile.density = detailDensity_;
33 auto applied = grass::applyTerrainDetailOverwrite(profile, settings);
34 if (!applied.ok()) return applied;
35 baseDetailRenderDistance_=profile.renderDistance;baseDetailFadeRange_=profile.fadeRange;
36 baseDetailHardDistance_=float(settings.unityDetailDistance);baseDetailDensity_=settings.unityDetailDensity;
37 applyPhotoModeShaderState();
38 return applied;
39}
40Result<int> GrassField::bakePointData(const std::vector<grass::Point>& points, float width, float height,
41 const image::ImageData* image, const image::ImageData* normal,
42 const image::ImageData* mask, const grass::GrassFoliageSettings* foliage) {
43 auto invalid = []() {
46 "grass.points: finite roots, scales above 0.001, 24-bit IDs and positive dimensions required"));
47 };
48 if (!gfx_ || !std::isfinite(width) || width <= 0 || !std::isfinite(height) || height <= 0 ||
49 points.size() > size_t(INT_MAX / 6))
50 return invalid();
51 for (const auto& point : points) {
52 const bool legacyTint = point.tint == glm::vec3(-1.f);
53 const bool validTint = std::isfinite(point.tint.x) && std::isfinite(point.tint.y) &&
54 std::isfinite(point.tint.z) && point.tint.x >= 0 && point.tint.x <= 1 &&
55 point.tint.y >= 0 && point.tint.y <= 1 && point.tint.z >= 0 && point.tint.z <= 1;
56 if (!std::isfinite(point.position.x) || !std::isfinite(point.position.y) || !std::isfinite(point.position.z) ||
57 (!legacyTint && !validTint) || !std::isfinite(point.scale) || point.scale <= 0.001F ||
58 point.id > 0xffffffu || !std::isfinite(point.widthScale) || point.widthScale < 0 ||
59 (point.widthScale > 0 && point.widthScale <= 0.001F) ||
60 double(point.widthScale > 0 ? point.widthScale : point.scale) * width > std::numeric_limits<float>::max() ||
61 double(point.scale) * height > std::numeric_limits<float>::max())
62 return invalid();
63 }
64 const auto validImage = [](const image::ImageData* value) {
65 return value && value->getWidth() > 0 && value->getHeight() > 0 && value->getFormat() == "RGBA8" &&
66 value->getData() && size_t(value->getWidth()) <= std::numeric_limits<size_t>::max() / 4 /
67 size_t(value->getHeight()) &&
68 size_t(value->getWidth()) * size_t(value->getHeight()) * 4 <= value->getSize();
69 };
70 if (image && !validImage(image))
72 Diagnostic::error(DiagnosticCode::InvalidArgument, "grass.points: complete RGBA8 image required"));
73 if (foliage) {
74 const auto finite01 = [](float value) { return std::isfinite(value) && value >= 0.f && value <= 1.f; };
75 if (!validImage(normal) || !validImage(mask) || normal->getWidth() != image->getWidth() ||
76 normal->getHeight() != image->getHeight() || mask->getWidth() != image->getWidth() ||
77 mask->getHeight() != image->getHeight() || !finite01(foliage->baseR) || !finite01(foliage->baseG) ||
78 !finite01(foliage->baseB) || !finite01(foliage->snowR) || !finite01(foliage->snowG) ||
79 !finite01(foliage->snowB) || !finite01(foliage->alphaCutoff) || !finite01(foliage->snowProgress) ||
80 !std::isfinite(foliage->normalStrength) || foliage->normalStrength < 0.01f ||
81 !std::isfinite(foliage->renderDistance) || foliage->renderDistance < 0.f ||
82 !std::isfinite(foliage->fadeRange) || foliage->fadeRange < 0.f ||
83 !std::isfinite(foliage->hardRenderDistance) || foliage->hardRenderDistance < 0.f ||
84 foliage->hardRenderDistance > 8388607.f ||
85 foliage->hardRenderDistance != std::floor(foliage->hardRenderDistance) ||
86 !finite01(foliage->density) ||
87 !std::isfinite(foliage->snowMinimumHeight) || !std::isfinite(foliage->snowFadeDistance) ||
88 foliage->snowFadeDistance <= 0.f)
90 DiagnosticCode::InvalidArgument, "grass.foliage: matching RGBA8 maps and finite surface settings required"));
91 }
92 if (points.empty()) {
93 denseMesh_ = nullptr;
94 sparseMesh_ = nullptr;
95 normal_ = nullptr;
96 mask_ = nullptr;
97 foliageProfile_ = false;
98 denseCount_ = 0;
99 sparseCount_ = 0;
100 return Result<int>::success(0);
101 }
102 const auto data = grass::buildBillboards(points, width, height, false);
103 auto* candidateShader = grass::createShader(gfx_);
104 auto* candidateAtlas = image ? gfx_->newTexture(image->getWidth(), image->getHeight(),
105 static_cast<const uint8_t*>(image->getData()), false, false)
106 : grass::createSwayAtlas(gfx_, 64, 64, 4);
107 auto* candidateNormal = foliage ? gfx_->newTexture(normal->getWidth(), normal->getHeight(),
108 static_cast<const uint8_t*>(normal->getData()), false, false)
109 : nullptr;
110 auto* candidateMask = foliage ? gfx_->newTexture(mask->getWidth(), mask->getHeight(),
111 static_cast<const uint8_t*>(mask->getData()), false, false)
112 : nullptr;
113 grass::PackedAtlasInfo layout;
114 layout.frames = image ? 1 : 4;
115 layout.atlasCols = layout.frames;
116 layout.atlasRows = 1;
117 if (foliage) grass::bindFoliage(candidateShader, *foliage);
118 else {
119 grass::bindDefaults(candidateShader);
120 grass::bindAtlasLayout(candidateShader, layout);
121 }
122 if (image) {
123 candidateShader->sendVec3("lightGreen", 1.0F, 1.0F, 1.0F);
124 candidateShader->sendVec3("darkGreen", 0.5F, 0.5F, 0.5F);
125 }
126 candidateShader->sendFloat("grassWidth", width);
127 candidateShader->sendFloat("grassHeight", height);
128 candidateShader->sendFloat("frameDuration", frameDuration_);
129 candidateShader->sendFloat("time", time_);
130 auto* candidateMesh =
131 gfx_->newMeshFromArrays(data.posXYZ.data(), data.nrmXYZ.data(), data.uvST.data(), int(data.posXYZ.size() / 3),
132 data.indices.data(), int(data.indices.size()));
133 if (!candidateShader || !candidateAtlas || !candidateMesh || (foliage && (!candidateNormal || !candidateMask)))
135 Diagnostic::error(DiagnosticCode::InvalidArgument, "grass.points: GPU resource creation returned empty"));
136 shader_ = candidateShader;
137 atlas_ = candidateAtlas;
138 normal_ = candidateNormal;
139 mask_ = candidateMask;
140 denseMesh_ = candidateMesh;
141 sparseMesh_ = nullptr;
142 denseCount_ = int(points.size());
143 sparseCount_ = 0;
144 foliageProfile_ = foliage != nullptr;
145 if (foliage) {
146 baseDetailRenderDistance_=foliage->renderDistance;baseDetailFadeRange_=foliage->fadeRange;
147 baseDetailHardDistance_=foliage->hardRenderDistance;baseDetailDensity_=foliage->density;
148 applyPhotoModeShaderState();
149 }
150 return Result<int>::success(denseCount_);
151}
152} // namespace eve::graphics
double value
int mask
graphics::Texture * albedo
std::string layout
vk::UniqueImage image
std::uint32_t height
std::uint32_t width
std::array< float, 3 > scale
Texture * normal
std::shared_ptr< const std::vector< glm::vec2 > > points
TerrainThermalSettings settings
glm::vec3 point
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
Creates a texture. @ownership Caller deletes unless documented otherwise.
virtual Mesh * newMeshFromArrays(const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount)=0
Upload a triangle mesh from packed CPU arrays. Owned by Graphics. posXYZ required (vertexCount*3)....
Result< int > bakePoints(const std::vector< grass::Point > &points, float width, float height)
Upload explicit grass roots without resampling, using the built-in four-frame atlas.
Result< int > bakeFoliagePoints(const std::vector< grass::Point > &points, float width, float height, const image::ImageData &albedo, const image::ImageData &normal, const image::ImageData &mask, const grass::GrassFoliageSettings &settings)
Upload static foliage albedo, tangent normal and metallic/occlusion/thickness/smoothness masks....
Result< int > setTerrainDetailOverwrite(const grass::TerrainDetailOverwriteSettings &settings)
Apply Pcg terrain detail hard distance, shader fade and density to an uploaded foliage field.
Result< int > bakeTexturedPoints(const std::vector< grass::Point > &points, float width, float height, const image::ImageData &image)
Upload roots with one static RGBA8 image, preserving original RGB and alpha. Image storage is borrowe...
const float * pushConstantData() const
Definition Shader.h:105
Represents raw pixel data.
Definition ImageData.h:38
EVENGINE_API_BACKENDS void bindFoliage(Shader *shader, const GrassFoliageSettings &settings)
Select the static foliage profile and copy its validated surface parameters.
Shader * createShader(Graphics *gfx)
Creates shader.
Definition Grass.cpp:306
Texture * createSwayAtlas(Graphics *gfx, int frameW, int frameH, int frames)
Creates sway atlas.
Definition Grass.cpp:348
EVENGINE_API_BACKENDS void bindDefaults(Shader *shader)
Binds defaults.
EVENGINE_API_BACKENDS Result< int > applyTerrainDetailOverwrite(GrassFoliageSettings &foliage, const TerrainDetailOverwriteSettings &settings)
Validate and copy TerrainDetailOverwrite distances/density into a foliage profile atomically.
EVENGINE_API_BACKENDS BillboardMesh buildBillboards(const std::vector< Point > &points, float width=0.62f, float height=0.95f, bool alwaysDark=false)
Expand a unit rectangle per point. Vertex layout: pos = grass root uv = quad corner in [0,...
void bindAtlasLayout(Shader *shader, const PackedAtlasInfo &info)
Binds atlas layout.
Definition Grass.cpp:281
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
Pcg-style static foliage surface controls packed into the grass shader profile. Values are copied dur...
Definition Grass.h:40
Runtime terrain-detail overrides kept distinct from foliage material settings.
Definition Grass.h:55