载入中...
搜索中...
未找到
MeshUvProjection.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <array>
5#include <cmath>
6
7namespace eve::procgen {
8namespace {
9std::array<float, 3> point(const MeshBuild& mesh, std::uint32_t i) {
10 const std::size_t b = static_cast<std::size_t>(i) * 3u;
11 return {mesh.positions()[b], mesh.positions()[b + 1u], mesh.positions()[b + 2u]};
12}
13} // namespace
14
15Result<MeshBuild> projectMeshUvResult(const MeshBuild& input, std::string_view mode, float scale, float offsetU,
16 float offsetV) {
17 if (input.empty() || input.positions().size() % 3u != 0u || input.normals().size() != input.positions().size())
18 return Result<MeshBuild>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "UV projection requires a valid non-empty mesh", "mesh", {}, "procgen.meshUvProjection"));
19 if ((mode != "planar" && mode != "box" && mode != "spherical") || !std::isfinite(scale) || scale <= 0.f ||
20 !std::isfinite(offsetU) || !std::isfinite(offsetV))
21 return Result<MeshBuild>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid UV projection parameters", "projection", {}, "procgen.meshUvProjection"));
23 output.uvs().assign(static_cast<std::size_t>(output.getVertexCount()) * 2u, 0.f);
24 constexpr float pi = 3.14159265358979323846f;
25 for (int i = 0; i < output.getVertexCount(); ++i) {
26 const std::size_t p = static_cast<std::size_t>(i) * 3u, uv = static_cast<std::size_t>(i) * 2u;
27 const float x = output.positions()[p], y = output.positions()[p + 1u], z = output.positions()[p + 2u];
28 float u = x, v = z;
29 if (mode == "spherical") {
30 const float length = std::sqrt(x * x + y * y + z * z);
31 if (length > 1e-7f) { u = std::atan2(z, x) / (2.f * pi) + 0.5f; v = std::asin(std::clamp(y / length, -1.f, 1.f)) / pi + 0.5f; }
32 } else if (mode == "box") {
33 const float nx = std::abs(output.normals()[p]), ny = std::abs(output.normals()[p + 1u]), nz = std::abs(output.normals()[p + 2u]);
34 if (nx >= ny && nx >= nz) { u = z; v = y; }
35 else if (ny >= nz) { u = x; v = z; }
36 else { u = x; v = y; }
37 }
38 output.uvs()[uv] = u * scale + offsetU;
39 output.uvs()[uv + 1u] = v * scale + offsetV;
40 }
41 output.setMeta("uvProjection", std::string(mode));
42 return Result<MeshBuild>::success(std::move(output));
43}
44
45Result<MeshSurfaceUv> mapMeshSurfacePointToUvResult(const MeshBuild& mesh, int triangleIndex, float x, float y,
46 float z) {
47 const std::size_t base = triangleIndex < 0 ? mesh.indices().size() : static_cast<std::size_t>(triangleIndex) * 3u;
48 if (base + 2u >= mesh.indices().size() || mesh.uvs().size() != static_cast<std::size_t>(mesh.getVertexCount()) * 2u)
49 return Result<MeshSurfaceUv>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "invalid dynamic mesh triangle or UV stream", "triangle", {}, "procgen.meshUvProjection"));
50 const auto ia = mesh.indices()[base], ib = mesh.indices()[base + 1u], ic = mesh.indices()[base + 2u];
51 if (ia >= static_cast<std::uint32_t>(mesh.getVertexCount()) || ib >= static_cast<std::uint32_t>(mesh.getVertexCount()) || ic >= static_cast<std::uint32_t>(mesh.getVertexCount()))
52 return Result<MeshSurfaceUv>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "triangle index exceeds dynamic mesh", "triangle", {}, "procgen.meshUvProjection"));
53 const auto a = point(mesh, ia), b = point(mesh, ib), c = point(mesh, ic);
54 const std::array<float,3> v0{b[0]-a[0],b[1]-a[1],b[2]-a[2]}, v1{c[0]-a[0],c[1]-a[1],c[2]-a[2]}, q{x-a[0],y-a[1],z-a[2]};
55 const float d00=v0[0]*v0[0]+v0[1]*v0[1]+v0[2]*v0[2], d01=v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2];
56 const float d11=v1[0]*v1[0]+v1[1]*v1[1]+v1[2]*v1[2], d20=q[0]*v0[0]+q[1]*v0[1]+q[2]*v0[2], d21=q[0]*v1[0]+q[1]*v1[1]+q[2]*v1[2];
57 const float denominator=d00*d11-d01*d01;
58 if (std::abs(denominator) < 1e-12f) return Result<MeshSurfaceUv>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "degenerate dynamic mesh triangle", "triangle", {}, "procgen.meshUvProjection"));
59 const float wb=(d11*d20-d01*d21)/denominator, wc=(d00*d21-d01*d20)/denominator, wa=1.f-wb-wc;
60 const auto uvAt=[&mesh](std::uint32_t i,int c0){return mesh.uvs()[static_cast<std::size_t>(i)*2u+static_cast<std::size_t>(c0)];};
61 return Result<MeshSurfaceUv>::success({wa*uvAt(ia,0)+wb*uvAt(ib,0)+wc*uvAt(ic,0), wa*uvAt(ia,1)+wb*uvAt(ib,1)+wc*uvAt(ic,1)});
62}
63} // namespace eve::procgen
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string output
float uv
float length
Definition CaveMesh.cpp:94
float nx
float nz
float ny
glm::vec4 p[6]
EvpackChunkInput input
Definition Evpack.cpp:170
float u
Definition Grass.cpp:233
std::array< double, 10 > q
float v
std::int32_t c
std::array< float, 3 > scale
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
Mesh * mesh
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
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
const std::vector< float > & uvs() const
Uvs.
Definition MeshBuild.h:129
Result< MeshSurfaceUv > mapMeshSurfacePointToUvResult(const MeshBuild &mesh, int triangleIndex, float x, float y, float z)
Map a surface point on a dynamic-mesh triangle to its interpolated UV.
Result< MeshBuild > projectMeshUvResult(const MeshBuild &input, std::string_view mode, float scale, float offsetU, float offsetV)
Generate topology-preserving UVs for a procedural or deformed mesh.