载入中...
搜索中...
未找到
PrimitiveGizmoRenderer.cpp
浏览该文件的文档.
2
5
6#include <algorithm>
7#include <cmath>
8#include <exception>
9#include <glm/gtc/matrix_transform.hpp>
10#include <string_view>
11
12namespace eve::graphics_editing {
13namespace {
14
15eve::Result<graphics::PrimitiveDrawStatistics> failure(std::string message, std::string path) {
18 "graphics_editing.primitive_gizmo"));
19}
20
21bool finite(const editing::GizmoPrimitive& primitive) {
22 const auto finiteArray = [](const auto& values) {
23 for (double value : values)
24 if (!std::isfinite(value)) return false;
25 return true;
26 };
27 return finiteArray(primitive.position) && finiteArray(primitive.size) && finiteArray(primitive.direction) &&
28 finiteArray(primitive.color) && std::isfinite(primitive.radius) && std::isfinite(primitive.length) &&
29 std::isfinite(primitive.yaw);
30}
31
32bool supported(std::string_view kind) {
33 return kind == "line" || kind == "point" || kind == "box" || kind == "obb" || kind == "ellipsoid" ||
34 kind == "sphere" || kind == "capsule" ||
35 kind == "arrow" || kind == "camera" || kind == "area" || kind == "frustum";
36}
37
38glm::vec3 vector(const std::array<double, 3>& value) {
39 return {static_cast<float>(value[0]), static_cast<float>(value[1]), static_cast<float>(value[2])};
40}
41
42graphics::ScenePrimitivePaint paint(const editing::GizmoPrimitive& primitive) {
43 graphics::ScenePrimitivePaint result;
44 result.mode = graphics::PaintMode::Stroke;
45 result.color = graphics::Color(static_cast<float>(primitive.color[0]), static_cast<float>(primitive.color[1]),
46 static_cast<float>(primitive.color[2]), static_cast<float>(primitive.color[3]));
47 result.stroke.width = 2.f;
48 result.stroke.cap = graphics::LineCap::Round;
49 result.stroke.join = graphics::LineJoin::Round;
50 if (primitive.dashed)
51 result.stroke.dash = graphics::DashPattern{{8.f, 5.f}, 0.f, graphics::DashSpace::ScreenPixels};
52 return result;
53}
54
55} // namespace
56
59 graphics::IGraphics3D& graphicsBackend) const {
60 for (std::size_t index = 0; index < snapshot.primitives.size(); ++index) {
61 const auto& primitive = snapshot.primitives[index];
62 const std::string path = "primitives[" + std::to_string(index) + "]";
63 if (!supported(primitive.kind))
64 return failure("unsupported gizmo primitive kind: " + primitive.kind, path + ".kind");
65 if (!finite(primitive)) return failure("gizmo primitive must be finite", path);
66 if ((primitive.kind == "sphere" || primitive.kind == "capsule") && primitive.radius <= 0.0)
67 return failure("gizmo radius must be positive", path + ".radius");
68 if ((primitive.kind == "obb" || primitive.kind == "ellipsoid") &&
69 (primitive.size[0] <= 0.0 || primitive.size[1] <= 0.0 || primitive.size[2] <= 0.0))
70 return failure("gizmo size must be positive", path + ".size");
71 if ((primitive.kind == "line" || primitive.kind == "capsule" || primitive.kind == "arrow" ||
72 primitive.kind == "camera" || primitive.kind == "frustum") &&
73 primitive.length <= 0.0)
74 return failure("gizmo length must be positive", path + ".length");
75 }
76
77 try {
79 for (const auto& primitive : snapshot.primitives) {
80 const glm::vec3 origin = vector(primitive.position);
81 glm::vec3 direction = vector(primitive.direction);
82 if (glm::length(direction) <= 1e-6f) direction = {0.f, 0.f, -1.f};
83 direction = glm::normalize(direction);
84 auto style = paint(primitive);
85 if (primitive.kind == "point") {
86 style.stroke.width = primitive.radius > 0.0 ? static_cast<float>(primitive.radius) : 5.f;
87 canvas.drawPoint(origin, style);
88 } else if (primitive.kind == "line") {
89 canvas.drawLine(origin, origin + direction * static_cast<float>(primitive.length), style);
90 } else if (primitive.kind == "box") {
91 const glm::vec3 half = vector(primitive.size) * 0.5f;
92 canvas.drawAabb(origin - half, origin + half, style);
93 } else if (primitive.kind == "obb") {
94 const glm::vec3 half = vector(primitive.size) * 0.5f;
95 const float c = std::cos(static_cast<float>(primitive.yaw));
96 const float s = std::sin(static_cast<float>(primitive.yaw));
97 canvas.drawObb(origin, {{{c * half.x, 0.f, s * half.x}, {0.f, half.y, 0.f},
98 {-s * half.z, 0.f, c * half.z}}}, style);
99 } else if (primitive.kind == "ellipsoid") {
100 const glm::vec3 half = vector(primitive.size) * 0.5f;
101 canvas.save();
102 canvas.concat(glm::translate(glm::mat4(1.f), origin) *
103 glm::rotate(glm::mat4(1.f), static_cast<float>(primitive.yaw), glm::vec3(0, 1, 0)) *
104 glm::scale(glm::mat4(1.f), half));
105 canvas.drawSphere({}, 1.f, style, 32);
106 canvas.restore();
107 } else if (primitive.kind == "sphere") {
108 canvas.drawSphere(origin, static_cast<float>(primitive.radius), style);
109 } else if (primitive.kind == "capsule") {
110 canvas.drawCapsule(origin, origin + direction * static_cast<float>(primitive.length),
111 static_cast<float>(primitive.radius), style);
112 } else if (primitive.kind == "arrow" || primitive.kind == "camera") {
113 const float length = static_cast<float>(primitive.length);
114 canvas.drawArrow(origin, origin + direction * length, length * 0.2f, std::max(0.04f, length * 0.08f),
115 style);
116 } else if (primitive.kind == "area") {
117 const glm::vec3 half = vector(primitive.size) * 0.5f;
118 canvas.drawQuad(origin + glm::vec3(-half.x, 0.f, -half.z), origin + glm::vec3(half.x, 0.f, -half.z),
119 origin + glm::vec3(half.x, 0.f, half.z), origin + glm::vec3(-half.x, 0.f, half.z),
120 style);
121 } else {
122 const float length = static_cast<float>(primitive.length);
123 const float radius = std::max(0.01f, static_cast<float>(primitive.radius));
124 glm::vec3 up = std::abs(direction.y) < 0.99f ? glm::vec3(0.f, 1.f, 0.f) : glm::vec3(1.f, 0.f, 0.f);
125 const glm::vec3 right = glm::normalize(glm::cross(direction, up)) * radius;
126 up = glm::normalize(glm::cross(right, direction)) * radius;
127 const glm::vec3 farCenter = origin + direction * length;
128 const std::array<glm::vec3, 8> corners{origin,
129 origin,
130 origin,
131 origin,
132 farCenter - right - up,
133 farCenter + right - up,
134 farCenter - right + up,
135 farCenter + right + up};
136 canvas.drawFrustum(corners, style);
137 }
138 }
139 graphicsBackend.drawPrimitiveScene(canvas);
141 } catch (const std::exception& error) {
142 return failure(error.what(), "snapshot");
143 }
144}
145
146} // namespace eve::graphics_editing
double value
const std::string & s
float length
Definition CaveMesh.cpp:94
std::map< std::string, Var > values
std::string message
HexVec3 up
HexVec3 right
std::int32_t c
TokenKind kind
bool finite
std::string error
Definition Package.cpp:60
float radius
std::string path
Definition PlayHost.cpp:110
V3 origin
Definition RoadBake.cpp:138
RoadLaneDirection direction
uint32_t index
const VegetationPresetContext & context
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
3D frame / mesh / light / shadow rendering surface.
Definition IGraphics3D.h:51
virtual void drawPrimitiveScene(const PrimitiveSceneCanvas3D &canvas)=0
Submits an owning frame-local primitive canvas into the active 3D pass.
Frame-local scene recorder for 3D line primitives.
void drawArrow(glm::vec3 from, glm::vec3 to, float headLength, float headRadius, const ScenePrimitivePaint &paint)
Records a shaft and four-sided arrow head.
void drawSphere(glm::vec3 center, float radius, const ScenePrimitivePaint &paint, std::uint32_t segments=32)
Records three orthogonal great circles.
void concat(const glm::mat4 &transform)
Concat.
void drawCapsule(glm::vec3 a, glm::vec3 b, float radius, const ScenePrimitivePaint &paint, std::uint32_t segments=32)
Draws capsule.
void drawLine(glm::vec3 a, glm::vec3 b, const ScenePrimitivePaint &paint)
Draws line.
void drawFrustum(const std::array< glm::vec3, 8 > &corners, const ScenePrimitivePaint &paint)
Draws frustum.
void drawObb(glm::vec3 center, const std::array< glm::vec3, 3 > &halfAxes, const ScenePrimitivePaint &paint)
Draws obb.
void drawAabb(glm::vec3 minimum, glm::vec3 maximum, const ScenePrimitivePaint &paint)
Records the twelve edges of an axis-aligned box.
void drawPoint(glm::vec3 point, const ScenePrimitivePaint &paint)
Draws point.
const PrimitiveDrawStatistics & statistics() const noexcept
Statistics.
void drawQuad(glm::vec3 a, glm::vec3 b, glm::vec3 c, glm::vec3 d, const ScenePrimitivePaint &paint)
Draws quad.
eve::Result< graphics::PrimitiveDrawStatistics > render(const editing::GizmoSnapshot &snapshot, const graphics::SceneDrawContext &context, graphics::IGraphics3D &graphics) const
Validate, record and submit one immutable gizmo snapshot.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
Immutable revision-tagged overlay snapshot consumed by any viewport renderer.
std::vector< GizmoPrimitive > primitives
Immutable camera and viewport facts used to resolve one 3D draw list. Projection uses the engine's RH...