Skip to content

Commit

Permalink
Merge pull request #7 from phpgl/feature/frustum
Browse files Browse the repository at this point in the history
Frustum system
  • Loading branch information
mario-deluna authored Jun 6, 2024
2 parents 3f4e072 + ac48ce7 commit 9ca8276
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 9 deletions.
19 changes: 19 additions & 0 deletions src/Geo/AABB.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,23 @@ public function intersectRayDistance(Ray $ray) : ?float

return $tmin;
}

/**
* Returns an array of 8 Vec3 representing the corners of the AABB
*
* @return array<Vec3>
*/
public function getCorners() : array
{
return [
new Vec3($this->min->x, $this->min->y, $this->min->z),
new Vec3($this->max->x, $this->min->y, $this->min->z),
new Vec3($this->max->x, $this->max->y, $this->min->z),
new Vec3($this->min->x, $this->max->y, $this->min->z),
new Vec3($this->min->x, $this->min->y, $this->max->z),
new Vec3($this->max->x, $this->min->y, $this->max->z),
new Vec3($this->max->x, $this->max->y, $this->max->z),
new Vec3($this->min->x, $this->max->y, $this->max->z),
];
}
}
101 changes: 101 additions & 0 deletions src/Geo/Frustum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace VISU\Geo;

use GL\Math\Mat4;
use GL\Math\Vec3;

class Frustum
{
public static function fromMat4(Mat4 $mat) : self
{
// Gribb/Hartmann method
return new self(
left: new Plane(
new Vec3(
$mat[3] + $mat[0], // a

Check failure on line 16 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 0 on GL\Math\Mat4.

Check failure on line 16 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 3 on GL\Math\Mat4.
$mat[7] + $mat[4], // b

Check failure on line 17 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 4 on GL\Math\Mat4.

Check failure on line 17 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 7 on GL\Math\Mat4.
$mat[11] + $mat[8] // c

Check failure on line 18 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 11 on GL\Math\Mat4.

Check failure on line 18 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 8 on GL\Math\Mat4.
),
$mat[15] + $mat[12] // d

Check failure on line 20 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 12 on GL\Math\Mat4.

Check failure on line 20 in src/Geo/Frustum.php

View workflow job for this annotation

GitHub Actions / ubuntu (ubuntu-latest, 8.2, 9.6)

Cannot access offset 15 on GL\Math\Mat4.
),
right: new Plane(
new Vec3(
$mat[3] - $mat[0], // a
$mat[7] - $mat[4], // b
$mat[11] - $mat[8] // c
),
$mat[15] - $mat[12] // d
),
top: new Plane(
new Vec3(
$mat[3] - $mat[1], // a
$mat[7] - $mat[5], // b
$mat[11] - $mat[9] // c
),
$mat[15] - $mat[13] // d
),
bottom: new Plane(
new Vec3(
$mat[3] + $mat[1], // a
$mat[7] + $mat[5], // b
$mat[11] + $mat[9] // c
),
$mat[15] + $mat[13] // d
),
near: new Plane(
new Vec3(
$mat[3] + $mat[2], // a
$mat[7] + $mat[6], // b
$mat[11] + $mat[10] // c
),
$mat[15] + $mat[14] // d
),
far: new Plane(
new Vec3(
$mat[3] - $mat[2], // a
$mat[7] - $mat[6], // b
$mat[11] - $mat[10] // c
),
$mat[15] - $mat[14] // d
)
);
}

/**
* Holds an additional reference to the planes that can be accessed by index
*/
private array $planes = [];

/**
* Frustum is represented by 6 planes
*/
public function __construct(
public Plane $left,
public Plane $right,
public Plane $top,
public Plane $bottom,
public Plane $near,
public Plane $far
)
{
foreach ([$left, $right, $top, $bottom, $near, $far] as $plane) {
$this->planes[] = $plane;
}
}

/**
* Returns boolean if a given sphere is visible in the frustum
*/
public function isSphereInView(Vec3 $center, float $radius): bool
{
foreach ($this->planes as $plane) {
$distance = Vec3::dot($plane->normal, $center) + $plane->distance;
if ($distance < -$radius) {
return false;
}
}

return true;
}
}
18 changes: 18 additions & 0 deletions src/Geo/Plane.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace VISU\Geo;

use GL\Math\Vec3;

class Plane
{
public function __construct(
public Vec3 $normal,
public float $distance
)
{
$mag = $this->normal->length();
$this->normal = $this->normal / $mag;
$this->distance /= $mag;
}
}
27 changes: 20 additions & 7 deletions src/Graphics/Camera.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

namespace VISU\Graphics;

use GL\Math\GLM;
use GL\Math\Mat4;
use GL\Math\Quat;
use GL\Math\Vec2;
use GL\Math\Vec3;
use GL\Math\Vec4;
use GL\VectorGraphics\VGContext;
use VISU\Geo\Frustum;
use VISU\Geo\Ray;
use VISU\Geo\Transform;

Expand Down Expand Up @@ -225,23 +227,34 @@ public function getViewport(RenderTarget $renderTarget) : Viewport
}

/**
* Calculates and returns the cameras view matrix. The matrix is inverted on the fly
* so cache the result if you need to use it multiple times.
* Returns the model matrix of the camera
* This is basically the inverse of the cameras view matrix.
*
* @param float $deltaTime The delta time since the last frame
* @return Mat4 A copy of the calculated view matrix
* @return Mat4 The model matrix of the camera
*/
public function getViewMatrix(float $deltaTime = 0.0) : Mat4
public function getModelMatrix(float $deltaTime = 0.0) : Mat4
{
if ($this->allowInterpolation) {
$this->interpolationTransformAlloc->position = Vec3::mix($this->lfCameraPos, $this->transform->position, $deltaTime);
$this->interpolationTransformAlloc->orientation = Quat::slerp($this->lfCameraRot, $this->transform->orientation, $deltaTime);
$this->interpolationTransformAlloc->markDirty();

return Mat4::inverted($this->interpolationTransformAlloc->getLocalMatrix());
return $this->interpolationTransformAlloc->getLocalMatrix();
}

return Mat4::inverted($this->transform->getLocalMatrix());
return $this->transform->getLocalMatrix();
}

/**
* Calculates and returns the cameras view matrix. The matrix is inverted on the fly
* so cache the result if you need to use it multiple times.
*
* @param float $deltaTime The delta time since the last frame
* @return Mat4 A copy of the calculated view matrix
*/
public function getViewMatrix(float $deltaTime = 0.0) : Mat4
{
return Mat4::inverted($this->getModelMatrix($deltaTime));
}

/**
Expand Down
22 changes: 22 additions & 0 deletions src/Graphics/Rendering/Pass/CameraData.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use GL\Math\Mat4;
use GL\Math\Vec2;
use VISU\Geo\Frustum;
use VISU\Graphics\Camera;
use VISU\Graphics\Rendering\RenderResource;
use VISU\Graphics\Viewport;
Expand Down Expand Up @@ -33,6 +34,21 @@ class CameraData
*/
public readonly Mat4 $view;

/**
* Projection view matrix
*/
public readonly Mat4 $projectionView;

/**
* Inverse projection view matrix
*/
public readonly Mat4 $inverseProjectionView;

/**
* Frustum of the current frame
*/
public readonly Frustum $frustum;

/**
* Compensation / alpha value for the current frame
*/
Expand Down Expand Up @@ -71,6 +87,9 @@ public function __construct(
Camera $renderCamera,
Mat4 $projection,
Mat4 $view,
Mat4 $projectionView,
Mat4 $inverseProjectionView,
Frustum $frustum,
float $compensation,
int $resolutionX,
int $resolutionY,
Expand All @@ -83,6 +102,9 @@ public function __construct(
$this->renderCamera = $renderCamera;
$this->projection = $projection;
$this->view = $view;
$this->projectionView = $projectionView;
$this->inverseProjectionView = $inverseProjectionView;
$this->frustum = $frustum;
$this->compensation = $compensation;
$this->resolutionX = $resolutionX;
$this->resolutionY = $resolutionY;
Expand Down
90 changes: 90 additions & 0 deletions src/Graphics/Rendering/Renderer/Debug3DRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
namespace VISU\Graphics\Rendering\Renderer;

use GL\Buffer\FloatBuffer;
use GL\Math\Mat4;
use GL\Math\Vec2;
use GL\Math\Vec3;
use GL\Math\Vec4;
use VISU\Geo\Frustum;
use VISU\Graphics\GLState;
use VISU\Graphics\Rendering\Pass\CallbackPass;
use VISU\Graphics\Rendering\Pass\CameraData;
Expand Down Expand Up @@ -156,6 +159,30 @@ public static function bezier(Vec3 $origin, Vec3 $p0, Vec3 $destination, Vec3 $c
static::getGlobalInstance()->addBezierCurve($origin, $p0, $destination, $color, $segments);
}

/**
* Draws a line representation of the given frustum
*
* @param Mat4 $ivp The inverse view projection matrix
* @param Vec3 $color The color of the frustum
*/
public static function frustum(Mat4 $ivp, Vec3 $color) : void
{
static::getGlobalInstance()->addFrustum($ivp, $color);
}

/**
* Draws a plane in 3D space
*
* @param Vec3 $origin The origin of the plane
* @param Vec3 $normal The normal of the plane
* @param float $size The size of the plane
* @param Vec3 $color The color of the plane
*/
public static function plane(Vec3 $origin, Vec3 $normal, float $size, Vec3 $color) : void
{
static::getGlobalInstance()->addPlane($origin, $normal, $size, $color);
}

/**
* Constructor
*
Expand Down Expand Up @@ -398,4 +425,67 @@ public function addBezierCurve(
$this->addLine($last, $destination, static::$colorGreen);
$this->addCross($p0, static::$colorMagenta);
}

/**
* Draws a Frustum
*
* @param Mat4 $mat The view projection matrix to build the frustum from
* @param Vec3 $color The color of the frustum
*/
public function addFrustum(Mat4 $ivp, Vec3 $color)
{
static $planes = [
// near
new Vec4(-1, -1, -1, 1), new Vec4(1, -1, -1, 1),
new Vec4(1, 1, -1, 1), new Vec4(-1, 1, -1, 1),

// far
new Vec4(-1, -1, 1, 1), new Vec4(1, -1, 1, 1),
new Vec4(1, 1, 1, 1), new Vec4(-1, 1, 1, 1),
];

$points = [];
foreach ($planes as $plane) {
$p = $ivp * $plane;
$points[] = new Vec3($p->x / $p->w, $p->y / $p->w, $p->z / $p->w);
}

$this->addLine($points[0], $points[1], $color);
$this->addLine($points[1], $points[2], $color);
$this->addLine($points[2], $points[3], $color);
$this->addLine($points[3], $points[0], $color);

$this->addLine($points[4], $points[5], $color);
$this->addLine($points[5], $points[6], $color);
$this->addLine($points[6], $points[7], $color);
$this->addLine($points[7], $points[4], $color);

$this->addLine($points[0], $points[4], $color);
$this->addLine($points[1], $points[5], $color);
$this->addLine($points[2], $points[6], $color);
$this->addLine($points[3], $points[7], $color);
}

/**
* Draws a plane in 3D space
*
* @param Vec3 $origin The origin of the plane
* @param Vec3 $normal The normal of the plane
* @param float $size The size of the plane
* @param Vec3 $color The color of the plane
*/
public function addPlane(Vec3 $origin, Vec3 $normal, float $size, Vec3 $color) : void
{
$up = new Vec3(0, 1, 0);

$right = Vec3::cross($normal, $up);
$right->normalize();
$up = Vec3::cross($right, $normal);
$up->normalize();

$this->addLine($origin - $right * $size + $up * $size, $origin + $right * $size + $up * $size, $color);
$this->addLine($origin + $right * $size + $up * $size, $origin + $right * $size - $up * $size, $color);
$this->addLine($origin + $right * $size - $up * $size, $origin - $right * $size - $up * $size, $color);
$this->addLine($origin - $right * $size - $up * $size, $origin - $right * $size + $up * $size, $color);
}
}
3 changes: 2 additions & 1 deletion src/Quickstart/QuickstartApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace VISU\Quickstart;

use ClanCats\Container\Container;

use GL\Math\Vec2;
use VISU\ECS\EntityRegisty;
use VISU\Graphics\GLState;
use VISU\Graphics\RenderTarget;
Expand All @@ -26,6 +26,7 @@

use GL\VectorGraphics\{VGContext, VGColor};
use VISU\Graphics\Rendering\Resource\RenderTargetResource;
use VISU\Graphics\Viewport;

class QuickstartApp implements GameLoopDelegate
{
Expand Down
Loading

0 comments on commit 9ca8276

Please sign in to comment.