12#include "TinyGPU/Vector.h"
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40template <
typename RGB_T =
RGB565>
50 return {
x + other.x,
y + other.y,
z + other.z};
54 return {
x - other.x,
y - other.y,
z - other.z};
58 return {
x * scalar,
y * scalar,
z * scalar};
62 return {
x / scalar,
y / scalar,
z / scalar};
81 result.m[0][0] = 1.0f;
82 result.m[1][1] = 1.0f;
83 result.m[2][2] = 1.0f;
84 result.m[3][3] = 1.0f;
91 return multiplyEspDsp(*
this, other);
94 for (size_t row = 0; row < 4; ++row) {
95 for (size_t column = 0; column < 4; ++column) {
96 for (size_t index = 0; index < 4; ++index) {
97 result.m[row][column] += m[row][index] * other.m[index][column];
108 return transformEspDsp(*
this, vector);
110 return {(
m[0][0] * vector.x) + (
m[0][1] * vector.y) +
111 (
m[0][2] * vector.z) + (
m[0][3] * vector.w),
112 (
m[1][0] * vector.x) + (
m[1][1] * vector.y) +
113 (
m[1][2] * vector.z) + (
m[1][3] * vector.w),
114 (
m[2][0] * vector.x) + (
m[2][1] * vector.y) +
115 (
m[2][2] * vector.z) + (
m[2][3] * vector.w),
116 (
m[3][0] * vector.x) + (
m[3][1] * vector.y) +
117 (
m[3][2] * vector.z) + (
m[3][3] * vector.w)};
127 reinterpret_cast<
const float*>(
right.
m),
128 reinterpret_cast<
float*>(
result.
m), 4, 4, 4);
148 static Mat4 multiplyGeneric(
const Mat4& left,
const Mat4& right) {
150 for (size_t row = 0; row < 4; ++row) {
151 for (size_t column = 0; column < 4; ++column) {
152 for (size_t index = 0; index < 4; ++index) {
153 result.m[row][column] +=
154 left.m[row][index] * right.m[index][column];
161 static Vec4 transformGeneric(
const Mat4& matrix,
const Vec4& vector) {
162 return {(matrix.m[0][0] * vector.x) + (matrix.m[0][1] * vector.y) +
163 (matrix.m[0][2] * vector.z) + (matrix.m[0][3] * vector.w),
164 (matrix.m[1][0] * vector.x) + (matrix.m[1][1] * vector.y) +
165 (matrix.m[1][2] * vector.z) + (matrix.m[1][3] * vector.w),
166 (matrix.m[2][0] * vector.x) + (matrix.m[2][1] * vector.y) +
167 (matrix.m[2][2] * vector.z) + (matrix.m[2][3] * vector.w),
168 (matrix.m[3][0] * vector.x) + (matrix.m[3][1] * vector.y) +
169 (matrix.m[3][2] * vector.z) + (matrix.m[3][3] * vector.w)};
216 viewportWidth_ = viewportWidth;
217 viewportHeight_ = viewportHeight;
244 float farPlane = 100.0f) {
254 float nearPlane = 0.1f,
float farPlane = 100.0f) {
273 std::fill(depthBuffer_.begin(), depthBuffer_.end(),
274 std::numeric_limits<
float>::infinity());
279 const Vec4 transformed = matrix *
Vec4{point.x, point.y, point.z, 1.0f};
280 if (transformed.w != 0.0f) {
281 return {transformed.x / transformed.w, transformed.y / transformed.w,
282 transformed.z / transformed.w};
284 return {transformed.x, transformed.y, transformed.z};
308 const float cosine = std::cos(radians);
309 const float sine = std::sin(radians);
310 result.m[1][1] = cosine;
311 result.m[1][2] = -sine;
312 result.m[2][1] = sine;
313 result.m[2][2] = cosine;
320 const float cosine = std::cos(radians);
321 const float sine = std::sin(radians);
322 result.m[0][0] = cosine;
323 result.m[0][2] = sine;
324 result.m[2][0] = -sine;
325 result.m[2][2] = cosine;
332 const float cosine = std::cos(radians);
333 const float sine = std::sin(radians);
334 result.m[0][0] = cosine;
335 result.m[0][1] = -sine;
336 result.m[1][0] = sine;
337 result.m[1][1] = cosine;
343 const float halfSize = size * 0.5f;
344 return {{{-halfSize, -halfSize, -halfSize},
345 {halfSize, -halfSize, -halfSize},
346 {halfSize, halfSize, -halfSize},
347 {-halfSize, halfSize, -halfSize},
348 {-halfSize, -halfSize, halfSize},
349 {halfSize, -halfSize, halfSize},
350 {halfSize, halfSize, halfSize},
351 {-halfSize, halfSize, halfSize}},
368 return {{{0.0f, 0.0f, 0.0f},
369 {length, 0.0f, 0.0f},
370 {0.0f, length, 0.0f},
371 {0.0f, 0.0f, length}},
372 {{0, 1}, {0, 2}, {0, 3}}};
376 static Mesh grid(size_t subdivisions = 10,
float spacing = 1.0f) {
378 const float halfExtent =
379 (
static_cast<
float>(subdivisions) * spacing) * 0.5f;
381 for (size_t index = 0; index <= subdivisions; ++index) {
382 const float offset = (
static_cast<
float>(index) * spacing) - halfExtent;
384 const size_t lineStart = mesh.vertices.size();
385 mesh.vertices.push_back({-halfExtent, 0.0f, offset});
386 mesh.vertices.push_back({halfExtent, 0.0f, offset});
387 mesh.edges.push_back({lineStart, lineStart + 1});
389 const size_t columnStart = mesh.vertices.size();
390 mesh.vertices.push_back({offset, 0.0f, -halfExtent});
391 mesh.vertices.push_back({offset, 0.0f, halfExtent});
392 mesh.edges.push_back({columnStart, columnStart + 1});
399 static Mesh sphere(
float radius = 1.0f, size_t latitudeSteps = 8,
400 size_t longitudeSteps = 12) {
402 const size_t latCount = std::max<size_t>(2, latitudeSteps);
403 const size_t lonCount = std::max<size_t>(3, longitudeSteps);
404 const float pi = 3.14159265358979323846f;
406 mesh.vertices.reserve((latCount + 1) * (lonCount + 1));
407 mesh.edges.reserve((latCount * lonCount) + ((latCount + 1) * lonCount));
409 for (size_t latitude = 0; latitude <= latCount; ++latitude) {
411 static_cast<
float>(latitude) /
static_cast<
float>(latCount);
412 const float phi = v * pi;
413 const float ringY = radius * std::cos(phi);
414 const float ringRadius = radius * std::sin(phi);
416 for (size_t longitude = 0; longitude <= lonCount; ++longitude) {
418 static_cast<
float>(longitude) /
static_cast<
float>(lonCount);
419 const float theta = u * (2.0f * pi);
420 mesh.vertices.push_back({ringRadius * std::cos(theta), ringY,
421 ringRadius * std::sin(theta)});
425 const size_t rowSize = lonCount + 1;
426 for (size_t latitude = 0; latitude <= latCount; ++latitude) {
427 for (size_t longitude = 0; longitude < lonCount; ++longitude) {
428 const size_t current = (latitude * rowSize) + longitude;
429 mesh.edges.push_back({current, current + 1});
433 for (size_t latitude = 0; latitude < latCount; ++latitude) {
434 for (size_t longitude = 0; longitude <= lonCount; ++longitude) {
435 const size_t current = (latitude * rowSize) + longitude;
436 mesh.edges.push_back({current, current + rowSize});
450 result.m[0][0] = right.x;
451 result.m[0][1] = right.y;
452 result.m[0][2] = right.z;
453 result.m[0][3] = -
dot(right
, eye
);
455 result.m[1][0] = actualUp.x;
456 result.m[1][1] = actualUp.y;
457 result.m[1][2] = actualUp.z;
458 result.m[1][3] = -
dot(actualUp
, eye
);
460 result.m[2][0] = -forward.x;
461 result.m[2][1] = -forward.y;
462 result.m[2][2] = -forward.z;
463 result.m[2][3] =
dot(forward
, eye
);
469 float& depth,
const Mat4& model =
Mat4::identity())
const {
479 screenX = projected.x;
480 screenY = projected.y;
481 depth = projected.depth;
487 const Mat4& model =
Mat4::identity(),
488 RGB_T color = RGB_T(255, 255, 255),
489 bool clearDepth =
true) {
490 if (viewportWidth_ != target.width() ||
491 viewportHeight_ != target.height()) {
492 setViewport(target.width(), target.height());
499 for (
const Edge& edge : mesh.edges) {
500 if (edge.start >= mesh.vertices.size() ||
501 edge.end >= mesh.vertices.size()) {
547 return dotEspDsp(first, second);
549 return (first.x * second.x) + (first.y * second.y) + (first.z * second.z);
554 return {(first.y * second.z) - (first.z * second.y),
555 (first.z * second.x) - (first.x * second.z),
556 (first.x * second.y) - (first.y * second.x)};
571 return std::sqrt(
dot(vector
, vector
));
575 const float vectorLength =
length(vector
);
576 if (vectorLength == 0.0f) {
577 return {0.0f, 0.0f, 0.0f};
579 return vector / vectorLength;
583 const Vec4 transformed = matrix *
Vec4{point.x, point.y, point.z, 1.0f};
584 return {transformed.x, transformed.y, transformed.z};
605 if (viewportWidth_ == 0 || viewportHeight_ == 0) {
608 return static_cast<
float>(viewportWidth_) /
609 static_cast<
float>(viewportHeight_);
613 size_t bytes = viewportWidth_ * viewportHeight_;
614 depthBuffer_.resize(bytes);
616 return depthBuffer_.size() == bytes;
620 float nearPlane,
float farPlane) {
622 const float halfFovRadians =
623 (fovYDegrees * 3.14159265358979323846f / 180.0f) * 0.5f;
624 const float focalLength = 1.0f / std::tan(halfFovRadians);
626 result.m[0][0] = focalLength / aspect;
627 result.m[1][1] = focalLength;
628 result.m[2][2] = (farPlane + nearPlane) / (nearPlane - farPlane);
629 result.m[2][3] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
630 result.m[3][2] = -1.0f;
635 float top,
float nearPlane,
638 result.m[0][0] = 2.0f / (right - left);
639 result.m[1][1] = 2.0f / (top - bottom);
640 result.m[2][2] = -2.0f / (farPlane - nearPlane);
641 result.m[0][3] = -(right + left) / (right - left);
642 result.m[1][3] = -(top + bottom) / (top - bottom);
643 result.m[2][3] = -(farPlane + nearPlane) / (farPlane - nearPlane);
648 return point.z <= -
camera_.nearPlane && point.z >= -
camera_.farPlane;
659 bool keepLessEqual) {
660 const bool startInside =
661 keepLessEqual ? start.z <= planeZ : start.z >= planeZ;
662 const bool endInside = keepLessEqual ? end.z <= planeZ : end.z >= planeZ;
664 if (!startInside && !endInside) {
667 if (startInside && endInside) {
671 const float deltaZ = end.z - start.z;
672 if (deltaZ == 0.0f) {
676 const float t = (planeZ - start.z) / deltaZ;
677 const Vec3 intersection = start + ((end - start) * t);
679 start = intersection;
690 if (clip.w == 0.0f) {
694 const float inverseW = 1.0f / clip.w;
695 const float ndcX = clip.x * inverseW;
696 const float ndcY = clip.y * inverseW;
697 const float ndcZ = clip.z * inverseW;
698 const float screenX =
699 ((ndcX * 0.5f) + 0.5f) *
700 static_cast<
float>(viewportWidth_ > 0 ? viewportWidth_ - 1 : 0);
701 const float screenY =
702 (1.0f - ((ndcY * 0.5f) + 0.5f)) *
703 static_cast<
float>(viewportHeight_ > 0 ? viewportHeight_ - 1 : 0);
705 projected.x =
static_cast<int16_t>(std::lround(screenX));
706 projected.y =
static_cast<int16_t>(std::lround(screenY));
707 projected.depth = (ndcZ + 1.0f) * 0.5f;
713 const int deltaX =
static_cast<
int>(end.x) -
static_cast<
int>(start.x);
714 const int deltaY =
static_cast<
int>(end.y) -
static_cast<
int>(start.y);
715 const int steps = std::max(std::abs(deltaX), std::abs(deltaY));
722 for (
int step = 0; step <= steps; ++step) {
723 const float factor =
static_cast<
float>(step) /
static_cast<
float>(steps);
724 const int x =
static_cast<
int>(std::lround(
725 static_cast<
float>(start.x) + (
static_cast<
float>(deltaX) * factor)));
726 const int y =
static_cast<
int>(std::lround(
727 static_cast<
float>(start.y) + (
static_cast<
float>(deltaY) * factor)));
728 const float depth = start.depth + ((end.depth - start.depth) * factor);
735 if (x < 0 || y < 0 ||
static_cast<size_t>(x) >= viewportWidth_ ||
736 static_cast<size_t>(y) >= viewportHeight_) {
740 const size_t bufferIndex =
741 (
static_cast<size_t>(y) * viewportWidth_) +
static_cast<size_t>(x);
742 if (bufferIndex >= depthBuffer_.size()) {
745 if (depth >= depthBuffer_[bufferIndex]) {
749 depthBuffer_[bufferIndex] = depth;
750 target.setPixel(
static_cast<size_t>(x),
static_cast<size_t>(y), color);
#define TINYGPU_ENABLE_ESP32S3_OPTIMIZATIONS
Activate ESP32-S3-specific optimizations.
Definition: TinyGPUConfig.h:11
RGB color stored in 16-bit RGB565 format.
Definition: RGB565.h:13
Lightweight 3D wireframe renderer for TinyGPU drawing targets.
Definition: WireFrame3D.h:41
static float length(const Vec3 &vector)
Definition: WireFrame3D.h:570
size_t viewportWidth() const
Returns the current viewport width.
Definition: WireFrame3D.h:227
static Mat4 lookAt(const Vec3 &eye, const Vec3 &target, const Vec3 &up)
Creates a view matrix from camera parameters.
Definition: WireFrame3D.h:444
bool projectViewPoint(const Vec3 &viewPoint, ProjectedPoint &projected) const
Definition: WireFrame3D.h:686
void renderWireframe(ISurface< RGB_T > &target, const Mesh &mesh, const Mat4 &model=Mat4::identity(), RGB_T color=RGB_T(255, 255, 255), bool clearDepth=true)
Renders a wireframe mesh with minimal depth buffering.
Definition: WireFrame3D.h:486
bool clipLineToCameraRange(Vec3 &start, Vec3 &end) const
Definition: WireFrame3D.h:651
void setViewport(size_t viewportWidth, size_t viewportHeight)
Sets the viewport size used for projection and depth buffering.
Definition: WireFrame3D.h:215
static Mesh sphere(float radius=1.0f, size_t latitudeSteps=8, size_t longitudeSteps=12)
Creates a wireframe sphere centered at the origin.
Definition: WireFrame3D.h:399
static float dot(const Vec3 &first, const Vec3 &second)
Definition: WireFrame3D.h:545
ProjectionMode projectionMode_
Definition: WireFrame3D.h:537
static Vec3 transformAffine(const Mat4 &matrix, const Vec3 &point)
Definition: WireFrame3D.h:582
const Camera & camera() const
Returns the active camera.
Definition: WireFrame3D.h:240
bool projectPoint(const Vec3 &point, int16_t &screenX, int16_t &screenY, float &depth, const Mat4 &model=Mat4::identity()) const
Projects a world-space point into screen space.
Definition: WireFrame3D.h:468
static Mat4 createPerspectiveMatrix(float fovYDegrees, float aspect, float nearPlane, float farPlane)
Definition: WireFrame3D.h:619
float orthographicLeft_
Definition: WireFrame3D.h:539
void clearDepthBuffer()
Clears the internal depth buffer.
Definition: WireFrame3D.h:272
Camera camera_
Definition: WireFrame3D.h:534
WireFrame3D()
Creates an empty wireframe renderer.
Definition: WireFrame3D.h:195
void drawDepthLine(ISurface< RGB_T > &target, const ProjectedPoint &start, const ProjectedPoint &end, RGB_T color)
Definition: WireFrame3D.h:711
static Mat4 rotationX(float radians)
Creates a rotation matrix around the X axis.
Definition: WireFrame3D.h:306
static Mat4 translation(float x, float y, float z)
Creates a translation matrix.
Definition: WireFrame3D.h:288
WireFrame3D(ISurface< RGB_T > &surface)
Creates a wireframe renderer with the dimensions of the given surface.
Definition: WireFrame3D.h:208
WireFrame3D(size_t viewportWidth, size_t viewportHeight)
Creates a wireframe renderer with the specified viewport size.
Definition: WireFrame3D.h:201
bool begin()
Definition: WireFrame3D.h:221
ProjectionMode
Definition: WireFrame3D.h:530
static Vec3 cross(const Vec3 &first, const Vec3 &second)
Definition: WireFrame3D.h:553
static Mat4 rotationY(float radians)
Creates a rotation matrix around the Y axis.
Definition: WireFrame3D.h:318
void setCamera(const Camera &camera)
Sets the active camera.
Definition: WireFrame3D.h:233
static Mesh cube(float size=1.0f)
Creates a wireframe cube centered at the origin.
Definition: WireFrame3D.h:342
const Mat4 & viewMatrix() const
Returns the current view matrix.
Definition: WireFrame3D.h:266
size_t viewportWidth_
Definition: WireFrame3D.h:532
Vector< float > depthBuffer_
Definition: WireFrame3D.h:543
float orthographicRight_
Definition: WireFrame3D.h:540
Mat4 projectionMatrix_
Definition: WireFrame3D.h:536
static Mesh grid(size_t subdivisions=10, float spacing=1.0f)
Creates a wireframe grid on the XZ plane.
Definition: WireFrame3D.h:376
static bool clipLineToPlane(Vec3 &start, Vec3 &end, float planeZ, bool keepLessEqual)
Definition: WireFrame3D.h:658
size_t viewportHeight_
Definition: WireFrame3D.h:533
size_t viewportHeight() const
Returns the current viewport height.
Definition: WireFrame3D.h:230
float orthographicTop_
Definition: WireFrame3D.h:542
void updateViewMatrix()
Definition: WireFrame3D.h:587
static Mat4 createOrthographicMatrix(float left, float right, float bottom, float top, float nearPlane, float farPlane)
Definition: WireFrame3D.h:634
float perspectiveFovYDegrees_
Definition: WireFrame3D.h:538
void setPerspective(float fovYDegrees, float nearPlane=0.1f, float farPlane=100.0f)
Sets a perspective projection using the current viewport aspect ratio.
Definition: WireFrame3D.h:243
Mat4 viewMatrix_
Definition: WireFrame3D.h:535
float currentAspectRatio() const
Definition: WireFrame3D.h:604
static Mesh axis(float length=1.0f)
Creates RGB-style axis lines centered at the origin.
Definition: WireFrame3D.h:367
bool resizeDepthBuffer()
Definition: WireFrame3D.h:612
static Vec3 normalize(const Vec3 &vector)
Definition: WireFrame3D.h:574
void updateProjectionMatrix()
Definition: WireFrame3D.h:591
const Mat4 & projectionMatrix() const
Returns the current projection matrix.
Definition: WireFrame3D.h:269
void setOrthographic(float left, float right, float bottom, float top, float nearPlane=0.1f, float farPlane=100.0f)
Sets an orthographic projection volume.
Definition: WireFrame3D.h:253
float orthographicBottom_
Definition: WireFrame3D.h:541
static Vec3 transformPoint(const Mat4 &matrix, const Vec3 &point)
Transforms a point by a matrix and divides by w when possible.
Definition: WireFrame3D.h:278
static Mat4 rotationZ(float radians)
Creates a rotation matrix around the Z axis.
Definition: WireFrame3D.h:330
bool clipPointToCameraRange(const Vec3 &point) const
Definition: WireFrame3D.h:647
static Mat4 scaling(float x, float y, float z)
Creates a scale matrix.
Definition: WireFrame3D.h:297
void plotDepthPixel(ISurface< RGB_T > &target, int x, int y, float depth, RGB_T color)
Definition: WireFrame3D.h:733
Definition: AVIWriter.h:9
Stores camera parameters for view transformation.
Definition: WireFrame3D.h:186
Vec3 target
Definition: WireFrame3D.h:188
float farPlane
Definition: WireFrame3D.h:191
float nearPlane
Definition: WireFrame3D.h:190
Vec3 position
Definition: WireFrame3D.h:187
Vec3 up
Definition: WireFrame3D.h:189
Represents an edge between two mesh vertices.
Definition: WireFrame3D.h:174
size_t start
Definition: WireFrame3D.h:175
size_t end
Definition: WireFrame3D.h:176
Represents a 4x4 transformation matrix.
Definition: WireFrame3D.h:75
static Mat4 identity()
Returns an identity matrix.
Definition: WireFrame3D.h:79
float m[4][4]
Definition: WireFrame3D.h:76
Mat4 operator*(const Mat4 &other) const
Multiplies two matrices.
Definition: WireFrame3D.h:89
Vec4 operator*(const Vec4 &vector) const
Transforms a homogeneous vector.
Definition: WireFrame3D.h:106
Represents a wireframe mesh.
Definition: WireFrame3D.h:180
Vector< Edge > edges
Definition: WireFrame3D.h:182
Vector< Vec3 > vertices
Definition: WireFrame3D.h:181
Represents a projected vertex on screen.
Definition: WireFrame3D.h:524
float depth
Definition: WireFrame3D.h:527
int16_t x
Definition: WireFrame3D.h:525
int16_t y
Definition: WireFrame3D.h:526
Represents a 3D point or vector.
Definition: WireFrame3D.h:44
Vec3 operator*(float scalar) const
Definition: WireFrame3D.h:57
Vec3 operator/(float scalar) const
Definition: WireFrame3D.h:61
Vec3 operator+(const Vec3 &other) const
Definition: WireFrame3D.h:49
float y
Definition: WireFrame3D.h:46
Vec3 operator-(const Vec3 &other) const
Definition: WireFrame3D.h:53
float x
Definition: WireFrame3D.h:45
float z
Definition: WireFrame3D.h:47
Represents a homogeneous 4D vector.
Definition: WireFrame3D.h:67
float w
Definition: WireFrame3D.h:71
float y
Definition: WireFrame3D.h:69
float x
Definition: WireFrame3D.h:68
float z
Definition: WireFrame3D.h:70