载入中...
搜索中...
未找到
VrmSurface.cpp
浏览该文件的文档.
1#include "avatar/VrmSurface.h"
2#include <bit>
3#include <cstring>
4#include <stdexcept>
5#include "common/Module.h"
7#include "graphics/Graphics.h"
8#include "graphics/Material.h"
9#include "graphics/Shader.h"
10#include "graphics/Texture.h"
11#include "graphics/shaders/mesh3d_mtoon_frag_spv.inc"
12#include "graphics/shaders/mesh3d_mtoon_vert_spv.inc"
13#include "image/ImageData.h"
14
15namespace eve::avatar {
16VrmSurface::VrmSurface() = default;
18 if (auto* gfx = ModuleManager::getInstance<graphics::Graphics>("Graphics"); gfx && !providerLifetime.expired()) {
19 if (gfx->releaseTexture(metadata)) delete metadata;
20 if (gfx->releaseShader(shader)) delete shader;
21 }
22}
23graphics::Texture& buildVrmAtlas(graphics::Graphics& gfx, const VrmDocument& d, std::vector<VrmAtlasRect>& rects) {
24 std::vector<std::unique_ptr<image::ImageData>> decoded;
25 int width = 4096, height = 1, x = 0, y = 0, row = 0;
26 for (const auto& bytes : d.images) {
27 filesystem::FileData file("embedded", bytes.size());
28 std::memcpy(file.getData(), bytes.data(), bytes.size());
29 auto img = std::make_unique<image::ImageData>(&file);
30 if (img->getWidth() > width) width = img->getWidth();
31 decoded.push_back(std::move(img));
32 }
33 for (const auto& img : decoded) {
34 const int w = img->getWidth(), h = img->getHeight();
35 if (x + w > width) {
36 x = 0;
37 y += row;
38 row = 0;
39 }
40 rects.push_back({x, y, w, h});
41 x += w;
42 row = std::max(row, h);
43 height = std::max(height, y + h);
44 }
45 if (width > 16384 || height > 16384) throw std::runtime_error("VRM image atlas exceeds supported dimensions");
46 image::ImageData atlas(width, height, "RGBA8");
47 for (size_t i = 0; i < decoded.size(); ++i)
48 atlas.paste(decoded[i].get(), rects[i].x, rects[i].y, 0, 0, rects[i].w, rects[i].h);
49 return *gfx.newTexture(&atlas);
50}
51std::unique_ptr<VrmSurface> buildVrmSurface(graphics::Graphics& gfx, const VrmMaterial& data, graphics::Texture& atlas,
52 const std::vector<VrmAtlasRect>& rects) {
53 if (gfx.getBackendName() != "vulkan") throw std::runtime_error("VRM MToon requires the Vulkan graphics provider");
54 auto s = std::make_unique<VrmSurface>();
55 s->providerLifetime = gfx.resourceLifetime();
56 s->base = s->current = data;
57 std::array<std::array<float, 4>, 32> values{};
58 values[0] = {data.shift, data.toony, data.gi, data.normalScale};
59 values[1] = {data.rimMix, data.rimPower, data.rimLift, data.outlineWidth};
60 values[2] = {data.outlineMix,
61 data.outlineMode == "worldCoordinates" ? 1.f
62 : data.outlineMode == "screenCoordinates" ? 2.f
63 : 0.f,
64 data.alphaMode == "MASK" ? 1.f
65 : data.alphaMode == "BLEND" ? 2.f
66 : 0.f,
67 data.cutoff};
68 values[3] = {data.scrollX, data.scrollY, data.rotationSpeed, data.shiftTextureScale};
69 values[4] = {data.mtoon ? 1.f : 0.f, data.doubleSided ? 1.f : 0.f, data.textures[5].image >= 0 ? 1.f : 0.f,
70 data.emissionStrength};
71 for (int t = 0; t < 9; ++t) {
72 const auto& slot = data.textures[t];
73 if (slot.image >= 0) {
74 const auto& r = rects.at(slot.image);
75 values[5 + t * 3] = {float(r.x), float(r.y), float(r.w), float(r.h)};
76 }
77 values[6 + t * 3] = {slot.offset[0], slot.offset[1], slot.scale[0], slot.scale[1]};
78 values[7 + t * 3] = {slot.rotation, float(slot.wrapS), float(slot.wrapT), slot.image >= 0 ? 1.f : 0.f};
79 }
80 // Encode IEEE floats losslessly into RGBA8 texels; every backend already supports this storage.
81 std::array<uint8_t, 512> packed{};
82 for (size_t i = 0; i < 32; ++i)
83 for (size_t c = 0; c < 4; ++c) {
84 uint32_t bits = std::bit_cast<uint32_t>(values[i][c]);
85 for (size_t b = 0; b < 4; ++b) packed[(i * 4 + c) * 4 + b] = uint8_t(bits >> (8 * b));
86 }
87 s->metadata = gfx.newTexture(128, 1, packed.data(), false, false);
88 s->shader = gfx.newMeshShaderFromSpv({mesh3d_mtoon_vert_spv, mesh3d_mtoon_vert_spv + mesh3d_mtoon_vert_spv_count},
89 {mesh3d_mtoon_frag_spv, mesh3d_mtoon_frag_spv + mesh3d_mtoon_frag_spv_count});
90 auto configured = gfx.configureMeshShaderSurface(
91 *s->shader, data.alphaMode == "BLEND" ? graphics::BlendMode::Alpha : graphics::BlendMode::Opaque,
92 data.alphaMode != "BLEND" || data.zWrite, true);
93 if (!configured.ok()) throw std::runtime_error(configured.status().describe());
94 for (int i = 0; i < 25; ++i) s->shader->declareFloat("vrm" + std::to_string(i));
95 auto material = [&]() {
96 auto m = std::make_unique<graphics::Material>();
97 m->setShadingModel("custom");
98 m->setShader(s->shader);
99 m->setAlbedoTexture(&atlas);
100 m->setHeightTexture(s->metadata);
101 m->setSurfaceMode(data.alphaMode == "BLEND" ? "transparent" : data.alphaMode == "MASK" ? "masked" : "opaque");
102 m->setSortPriority(data.queue);
103 m->setAlphaCutoff(data.cutoff);
104 m->setDepthWrite(data.alphaMode != "BLEND" || data.zWrite);
105 return m;
106 };
107 s->material = material();
108 if (data.outlineMode != "none" && data.outlineWidth > 0) s->outlineMaterial = material();
109 s->update(0);
110 return s;
111}
113 std::array<float, 25> v{};
114 size_t n = 0;
115 auto append = [&](const auto& values) {
116 for (float x : values) v[n++] = x;
117 };
118 append(current.color);
119 append(current.shade);
120 append(current.emission);
121 append(current.matcap);
122 append(current.rim);
123 append(current.outline);
124 append(uvScale);
125 append(uvOffset);
126 v[n++] = time;
127 for (int i = 0; i < 25; ++i) {
128 material->setFloat("vrm" + std::to_string(i), v[i]);
129 if (outlineMaterial) outlineMaterial->setFloat("vrm" + std::to_string(i), i == 24 ? 1.f : v[i]);
130 }
131}
132} // namespace eve::avatar
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
const std::string & s
std::map< std::string, Var > values
filesystem::File * file
glm::vec3 n
Definition Grass.cpp:63
double r
float v
std::int32_t c
int h
std::uint32_t height
std::uint32_t width
std::uint64_t bytes
MeleePoint3 b
Definition MeleeHit.cpp:41
float d
float t
Material * material
float m[16]
Data buffer paired with a filename (used for type identification).
Definition FileData.h:14
virtual std::string getBackendName() const =0
Renderer backend id used by sibling modules (e.g. Gpgpu).
virtual Shader * newMeshShaderFromSpv(const std::vector< uint32_t > &vertSpv, const std::vector< uint32_t > &fragSpv)=0
Create a Mesh3D custom shader (MeshVertex + Frame UBO + albedo). Empty vert → default mesh3d....
std::weak_ptr< const void > resourceLifetime() const
Observe this provider's resource lifetime without extending it.
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 eve::Result< void > configureMeshShaderSurface(Shader &, BlendMode, bool, bool)
Prepare a custom mesh shader's blend, depth and culling state.
Definition Graphics.h:1830
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Represents raw pixel data.
Definition ImageData.h:38
void paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh)
Paste part of one ImageData onto another. The subregion defined by the top-left corner (sx,...
graphics::Texture & buildVrmAtlas(graphics::Graphics &gfx, const VrmDocument &d, std::vector< VrmAtlasRect > &rects)
Prepare an atlas using the provider's owning resource factory. @ownership Graphics owns the result; c...
std::unique_ptr< VrmSurface > buildVrmSurface(graphics::Graphics &gfx, const VrmMaterial &data, graphics::Texture &atlas, const std::vector< VrmAtlasRect > &rects)
Builds vrm surface.
Validated VRM schema data. Unknown optional fields are ignored; unknown versions fail.
Definition VrmDocument.h:88
Linear material factors and image references from VRMC_materials_mtoon.
Definition VrmDocument.h:21
std::array< float, 3 > outline
Definition VrmDocument.h:26
std::array< float, 3 > matcap
Definition VrmDocument.h:26
std::array< float, 3 > shade
Definition VrmDocument.h:26
std::array< float, 4 > color
Definition VrmDocument.h:25
std::array< float, 3 > rim
Definition VrmDocument.h:26
std::array< float, 3 > emission
Definition VrmDocument.h:26
std::unique_ptr< graphics::Material > outlineMaterial
Definition VrmSurface.h:26
graphics::Texture * metadata
Definition VrmSurface.h:28
std::unique_ptr< graphics::Material > material
Definition VrmSurface.h:25
std::array< float, 2 > uvOffset
Definition VrmSurface.h:29
~VrmSurface()
Releases VrmSurface resources.
std::array< float, 2 > uvScale
Definition VrmSurface.h:29
VrmSurface()
Constructs a VrmSurface.
graphics::Shader * shader
Definition VrmSurface.h:27
void update(float time)
Updates .
std::weak_ptr< const void > providerLifetime
Definition VrmSurface.h:23