Skip to content

Commit

Permalink
Merge pull request #81 from martinlaxenaire/develop
Browse files Browse the repository at this point in the history
Minor bugs fixes and improvements - v0.7.6
  • Loading branch information
martinlaxenaire committed Jun 27, 2024
2 parents b9a7879 + 45e2578 commit 7383c3d
Show file tree
Hide file tree
Showing 438 changed files with 5,089 additions and 4,442 deletions.
1 change: 0 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
## TODO / possible improvements

- Add/improve GLTFScenesManager features
- Option to chose between sphere and OBB frustum culling
- Mesh raycasting
- Lights management?
- Improve typedoc documentation?
Expand Down
59 changes: 42 additions & 17 deletions dist/esm/core/DOM/DOMFrustum.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box3 } from '../../math/Box3.mjs';
import { Mat4 } from '../../math/Mat4.mjs';
import { Vec3 } from '../../math/Vec3.mjs';

const defaultDOMFrustumMargins = {
top: 0,
Expand Down Expand Up @@ -32,6 +33,7 @@ class DOMFrustum {
}
}) {
this.boundingBox = boundingBox;
this.clipSpaceAABB = new Box3();
this.modelViewProjectionMatrix = modelViewProjectionMatrix;
this.containerBoundingRect = containerBoundingRect;
this.DOMFrustumMargins = { ...defaultDOMFrustumMargins, ...DOMFrustumMargins };
Expand Down Expand Up @@ -69,29 +71,52 @@ class DOMFrustum {
};
}
/**
* Applies all {@link modelViewProjectionMatrix} transformations to our {@link boundingBox} and then check against intersections
* Compute the axis aligned bounding box in clip space.
*/
computeProjectedToDocumentCoords() {
const projectedBox = this.boundingBox.applyMat4(this.modelViewProjectionMatrix);
projectedBox.min.x = (projectedBox.min.x + 1) * 0.5;
projectedBox.max.x = (projectedBox.max.x + 1) * 0.5;
projectedBox.min.y = 1 - (projectedBox.min.y + 1) * 0.5;
projectedBox.max.y = 1 - (projectedBox.max.y + 1) * 0.5;
computeClipSpaceAABB() {
this.clipSpaceAABB.set();
this.boundingBox.applyMat4(this.modelViewProjectionMatrix, this.clipSpaceAABB);
}
/**
* Applies all {@link modelViewProjectionMatrix} transformations to our {@link boundingBox}, i.e. apply AABB to document coordinates and set {@link projectedBoundingRect}.
*/
setDocumentCoordsFromClipSpaceAABB() {
this.computeClipSpaceAABB();
const minX = (this.clipSpaceAABB.min.x + 1) * 0.5;
const maxX = (this.clipSpaceAABB.max.x + 1) * 0.5;
const minY = 1 - (this.clipSpaceAABB.min.y + 1) * 0.5;
const maxY = 1 - (this.clipSpaceAABB.max.y + 1) * 0.5;
const { width, height, top, left } = this.containerBoundingRect;
this.projectedBoundingRect = {
left: projectedBox.min.x * width + left,
x: projectedBox.min.x * width + left,
top: projectedBox.max.y * height + top,
y: projectedBox.max.y * height + top,
right: projectedBox.max.x * width + left,
bottom: projectedBox.min.y * height + top,
width: projectedBox.max.x * width + left - (projectedBox.min.x * width + left),
height: projectedBox.min.y * height + top - (projectedBox.max.y * height + top)
left: minX * width + left,
x: minX * width + left,
top: maxY * height + top,
y: maxY * height + top,
right: maxX * width + left,
bottom: minY * height + top,
width: maxX * width + left - (minX * width + left),
height: minY * height + top - (maxY * height + top)
};
this.intersectsContainer();
}
/**
* Check whether our {@link projectedBoundingRect} intersects with our {@link DOMFrustumBoundingRect}
* Apply the bounding sphere in clip space to document coordinates and set {@link projectedBoundingRect}.
* @param boundingSphere - bounding sphere in clip space.
*/
setDocumentCoordsFromClipSpaceSphere(boundingSphere = { center: new Vec3(), radius: 0 }) {
const centerX = (boundingSphere.center.x + 1) * 0.5;
const centerY = 1 - (boundingSphere.center.y + 1) * 0.5;
const { width, height, top, left } = this.containerBoundingRect;
this.projectedBoundingRect.width = boundingSphere.radius * height * 0.5;
this.projectedBoundingRect.height = boundingSphere.radius * height * 0.5;
this.projectedBoundingRect.left = centerX * width + left - this.projectedBoundingRect.width * 0.5;
this.projectedBoundingRect.x = centerX * width + left - this.projectedBoundingRect.width * 0.5;
this.projectedBoundingRect.top = centerY * height + top - this.projectedBoundingRect.height * 0.5;
this.projectedBoundingRect.y = centerY * height + top - this.projectedBoundingRect.height * 0.5;
this.projectedBoundingRect.right = this.projectedBoundingRect.left + this.projectedBoundingRect.width;
this.projectedBoundingRect.bottom = this.projectedBoundingRect.top + this.projectedBoundingRect.height;
}
/**
* Check whether our {@link projectedBoundingRect} intersects with our {@link DOMFrustumBoundingRect}.
*/
intersectsContainer() {
if (Math.round(this.DOMFrustumBoundingRect.right) <= this.containerBoundingRect.left || Math.round(this.DOMFrustumBoundingRect.left) >= this.containerBoundingRect.left + this.containerBoundingRect.width || Math.round(this.DOMFrustumBoundingRect.bottom) <= this.containerBoundingRect.top || Math.round(this.DOMFrustumBoundingRect.top) >= this.containerBoundingRect.top + this.containerBoundingRect.height) {
Expand Down
40 changes: 30 additions & 10 deletions dist/esm/core/camera/Camera.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ class Camera extends Object3D {
matrix: new Mat4(),
shouldUpdate: true,
onUpdate: () => this.updateProjectionMatrix()
},
viewProjection: {
matrix: new Mat4(),
shouldUpdate: true,
onUpdate: () => this.viewProjectionMatrix.multiplyMatrices(this.projectionMatrix, this.viewMatrix)
}
};
}
Expand All @@ -85,7 +90,7 @@ class Camera extends Object3D {
}
set viewMatrix(value) {
this.matrices.view.matrix = value;
this.matrices.view.shouldUpdate = true;
this.shouldUpdateViewMatrices();
}
/**
* Get our projection matrix
Expand All @@ -96,28 +101,43 @@ class Camera extends Object3D {
}
set projectionMatrix(value) {
this.matrices.projection.matrix = value;
this.shouldUpdateProjectionMatrix();
this.shouldUpdateProjectionMatrices();
}
/**
* Get our view projection matrix
* @readonly
*/
get viewProjectionMatrix() {
return this.matrices.viewProjection.matrix;
}
/**
* Set our projection matrix shouldUpdate flag to true (tell it to update)
* Set our view dependent matrices shouldUpdate flag to true (tell it to update)
*/
shouldUpdateProjectionMatrix() {
shouldUpdateViewMatrices() {
this.matrices.view.shouldUpdate = true;
this.matrices.viewProjection.shouldUpdate = true;
}
/**
* Set our projection dependent matrices shouldUpdate flag to true (tell it to update)
*/
shouldUpdateProjectionMatrices() {
this.matrices.projection.shouldUpdate = true;
this.matrices.viewProjection.shouldUpdate = true;
}
/**
* Update our model matrix and tell our view matrix to update as well
*/
updateModelMatrix() {
super.updateModelMatrix();
this.setVisibleSize();
this.matrices.view.shouldUpdate = true;
this.shouldUpdateViewMatrices();
}
/**
* Update our world matrix and tell our view matrix to update as well
*/
updateWorldMatrix() {
super.updateWorldMatrix();
this.matrices.view.shouldUpdate = true;
this.shouldUpdateViewMatrices();
}
/**
* Callback to run when the camera {@link modelMatrix | model matrix} has been updated
Expand All @@ -142,7 +162,7 @@ class Camera extends Object3D {
fov = Math.max(1, Math.min(fov ?? this.fov, 179));
if (fov !== this.fov) {
__privateSet(this, _fov, fov);
this.shouldUpdateProjectionMatrix();
this.shouldUpdateProjectionMatrices();
}
this.setVisibleSize();
this.setCSSPerspective();
Expand All @@ -161,7 +181,7 @@ class Camera extends Object3D {
near = Math.max(near ?? this.near, 0.01);
if (near !== this.near) {
__privateSet(this, _near, near);
this.shouldUpdateProjectionMatrix();
this.shouldUpdateProjectionMatrices();
}
}
/**
Expand All @@ -178,7 +198,7 @@ class Camera extends Object3D {
far = Math.max(far ?? this.far, this.near + 1);
if (far !== this.far) {
__privateSet(this, _far, far);
this.shouldUpdateProjectionMatrix();
this.shouldUpdateProjectionMatrices();
}
}
/**
Expand All @@ -201,7 +221,7 @@ class Camera extends Object3D {
*/
setSize({ width, height }) {
if (width !== this.size.width || height !== this.size.height) {
this.shouldUpdateProjectionMatrix();
this.shouldUpdateProjectionMatrices();
}
this.size.width = width;
this.size.height = height;
Expand Down
60 changes: 57 additions & 3 deletions dist/esm/core/meshes/mixins/ProjectedMeshBaseMixin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import default_normal_fsWgsl from '../../shaders/chunks/default_normal_fs.wgsl.m

const defaultProjectedMeshParams = {
// frustum culling and visibility
frustumCulling: true,
frustumCulling: "AABB",
DOMFrustumMargins: {
top: 0,
right: 0,
Expand Down Expand Up @@ -232,12 +232,66 @@ function ProjectedMeshBaseMixin(Base) {
}
/* RENDER */
/**
* Check if the Mesh lies inside the {@link camera} view frustum or not.
* Get the geometry bounding sphere in clip space.
* @readonly
*/
get clipSpaceBoundingSphere() {
const { center, radius, min, max } = this.geometry.boundingBox;
const translation = this.worldMatrix.getTranslation();
const maxWorldRadius = radius * this.worldMatrix.getMaxScaleOnAxis();
const cMin = center.clone().add(translation);
cMin.z += min.z;
const cMax = center.clone().add(translation);
cMax.z += max.z;
const sMin = cMin.clone();
sMin.y += maxWorldRadius;
const sMax = cMax.clone();
sMax.y += maxWorldRadius;
cMin.applyMat4(this.camera.viewProjectionMatrix);
cMax.applyMat4(this.camera.viewProjectionMatrix);
sMin.applyMat4(this.camera.viewProjectionMatrix);
sMax.applyMat4(this.camera.viewProjectionMatrix);
const rMin = cMin.distance(sMin);
const rMax = cMax.distance(sMax);
const rectMin = {
xMin: cMin.x - rMin,
xMax: cMin.x + rMin,
yMin: cMin.y - rMin,
yMax: cMin.y + rMin
};
const rectMax = {
xMin: cMax.x - rMax,
xMax: cMax.x + rMax,
yMin: cMax.y - rMax,
yMax: cMax.y + rMax
};
const rect = {
xMin: Math.min(rectMin.xMin, rectMax.xMin),
yMin: Math.min(rectMin.yMin, rectMax.yMin),
xMax: Math.max(rectMin.xMax, rectMax.xMax),
yMax: Math.max(rectMin.yMax, rectMax.yMax)
};
const sphereCenter = cMax.add(cMin).multiplyScalar(0.5).clone();
sphereCenter.x = (rect.xMax + rect.xMin) / 2;
sphereCenter.y = (rect.yMax + rect.yMin) / 2;
const sphereRadius = Math.max(rect.xMax - rect.xMin, rect.yMax - rect.yMin);
return {
center: sphereCenter,
radius: sphereRadius
};
}
/**
* Check if the Mesh lies inside the {@link camera} view frustum or not using the test defined by {@link frustumCulling}.
*/
checkFrustumCulling() {
if (this.matricesNeedUpdate) {
if (this.domFrustum && this.frustumCulling) {
this.domFrustum.computeProjectedToDocumentCoords();
if (this.frustumCulling === "sphere") {
this.domFrustum.setDocumentCoordsFromClipSpaceSphere(this.clipSpaceBoundingSphere);
} else {
this.domFrustum.setDocumentCoordsFromClipSpaceAABB();
}
this.domFrustum.intersectsContainer();
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions dist/esm/core/renderers/GPUCameraRenderer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,15 @@ class GPUCameraRenderer extends GPURenderer {
this.camera.position.copy(position);
}
/**
* Call our {@link GPURenderer#resizeObjects | GPURenderer resizeObjects method} and resize our {@link camera} as well
* Resize our {@link GPUCameraRenderer} and resize our {@link camera} before anything else.
* @param rectBBox - the optional new {@link canvas} {@link RectBBox} to set
*/
resizeObjects() {
resize(rectBBox = null) {
this.setSize(rectBBox);
this.setPerspective();
super.resizeObjects();
this._onResizeCallback && this._onResizeCallback();
this.resizeObjects();
this._onAfterResizeCallback && this._onAfterResizeCallback();
}
/* RENDER */
/**
Expand Down
44 changes: 24 additions & 20 deletions dist/esm/extras/gltf/utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -242,13 +242,17 @@ const buildShaders = (meshDescriptor, shaderParameters = null) => {
}
const applyLightShading = (
/* wgsl */
`
lightContribution.ambient *= color.rgb * occlusion;
lightContribution.diffuse *= color.rgb * occlusion;
lightContribution.specular *= occlusion;
`
// apply color to ambient
lightContribution.ambient *= color.rgb;
// apply color based on metallic to diffuse
lightContribution.diffuse *= mix(color.rgb, vec3(0.0), vec3(metallic));
let totalLight: vec3f = lightContribution.ambient + lightContribution.diffuse + lightContribution.specular;
color = vec4(
lightContribution.ambient + lightContribution.diffuse + lightContribution.specular + emissive,
totalLight * occlusion + emissive,
color.a
);
`
Expand Down Expand Up @@ -348,34 +352,34 @@ const buildPBRShaders = (meshDescriptor, shaderParameters = null) => {
const pbrAdditionalFragmentHead = (
/* wgsl */
`
fn FresnelSchlick(cosTheta: f32, F0: vec3f) -> vec3f {
return F0 + (vec3(1.0) - F0) * pow(1.0 - cosTheta, 5.0);
fn FresnelSchlick(cosTheta: f32, f0: vec3f) -> vec3f {
return f0 + (vec3(1.0) - f0) * pow(1.0 - cosTheta, 5.0);
}
fn DistributionGGX(NdotH: f32, roughness: f32) -> f32 {
let a = roughness*roughness;
let a2 = a*a;
let NdotH2 = NdotH*NdotH;
let a: f32 = roughness * roughness;
let a2: f32 = a * a;
let NdotH2: f32 = NdotH * NdotH;
let num = a2;
let denom = (NdotH2 * (a2 - 1.0) + 1.0);
let num: f32 = a2;
let denom: f32 = (NdotH2 * (a2 - 1.0) + 1.0);
return num / (PI * denom * denom);
}
fn GeometrySchlickGGX(NdotV : f32, roughness : f32) -> f32 {
let r = (roughness + 1.0);
let k = (r*r) / 8.0;
fn GeometrySchlickGGX(NdotV : f32, roughness: f32) -> f32 {
let r: f32 = (roughness + 1.0);
let k: f32 = (r * r) / 8.0;
let num = NdotV;
let denom = NdotV * (1.0 - k) + k;
let num: f32 = NdotV;
let denom: f32 = NdotV * (1.0 - k) + k;
return num / denom;
}
fn GeometrySmith(NdotL: f32, NdotV: f32, roughness : f32) -> f32 {
let ggx2 = GeometrySchlickGGX(NdotV, roughness);
let ggx1 = GeometrySchlickGGX(NdotL, roughness);
fn GeometrySmith(NdotL: f32, NdotV: f32, roughness: f32) -> f32 {
let ggx2: f32 = GeometrySchlickGGX(NdotV, roughness);
let ggx1: f32 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
Expand Down
12 changes: 6 additions & 6 deletions dist/esm/math/Box3.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ class Box3 {
* Apply a {@link Mat4 | matrix} to a {@link Box3}
* Useful to apply a transformation {@link Mat4 | matrix} to a {@link Box3}
* @param matrix - {@link Mat4 | matrix} to use
* @returns - this {@link Box3} after {@link Mat4 | matrix} application
* @param transformedBox - {@link Box3 | transformed Box3} to set
* @returns - the {@link Box3 | transformed Box3} after {@link Mat4 | matrix} application
*/
applyMat4(matrix = new Mat4()) {
applyMat4(matrix = new Mat4(), transformedBox = new Box3()) {
if (this.isEmpty())
return this;
const corners = [];
Expand All @@ -92,12 +93,11 @@ class Box3 {
corners[6] = points[6].set(this.max.x, this.max.y, this.min.z).applyMat4(matrix);
corners[7] = points[7].set(this.max.x, this.max.y, this.max.z).applyMat4(matrix);
}
const transFormedBox = new Box3();
for (let i = 0, cornersCount = corners.length; i < cornersCount; i++) {
transFormedBox.min.min(corners[i]);
transFormedBox.max.max(corners[i]);
transformedBox.min.min(corners[i]);
transformedBox.max.max(corners[i]);
}
return transFormedBox;
return transformedBox;
}
}

Expand Down
Loading

0 comments on commit 7383c3d

Please sign in to comment.