Skip to content

Commit

Permalink
completely 100% fixed Model loading bugs and collider fit issues (#581)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelthatsit authored Apr 12, 2024
1 parent 056fd9d commit 4e0641c
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 63 deletions.
8 changes: 4 additions & 4 deletions dist/mr.js

Large diffs are not rendered by default.

Binary file added samples/examples-assets/models/tiledesert001.glb
Binary file not shown.
2 changes: 1 addition & 1 deletion samples/examples/models.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body >
<mr-app> <!-- orbital="true" stats="true">-->
<mr-app debug="true"> <!--stats="true">-->
<mr-panel id="panel" class="layout" data-comp-anchor="type: fixed;">
<mr-div id="navbar">
<mr-a href="https://mrjs.io" class="mrjs">
Expand Down
108 changes: 79 additions & 29 deletions samples/examples/physics.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,99 @@
</head>
<body >
<mr-app orbital="true" debug="true">

<mr-model id="baseline" src="../examples-assets/models/tiledesert001.glb"
style="scale: 0.1;"
data-comp-animation="clip: 1; action: play;"
data-position="-0.125 0.125 0"></mr-model>
<mr-test></mr-test>
</mr-app>
<script>
let width = 2
let height = 2
let depth = 2

let scale = 0.25

let app = document.querySelector('mr-app')

for(let x = -width / 2; x < width / 2; x++) {
for(let y = 0; y < height; y++) {
for(let z = -depth / 2; z < depth / 2; z++) {
let model = document.createElement('mr-model')
app.appendChild(model)
model.src = "../examples-assets/models/animation_koifish.glb"
model.components.set('animation', {
clip: 1,
action: 'play'
})

model.onLoad = () => {
modelLoaded(model)
}

model.addEventListener('hoverstart', hover)
model.addEventListener('hoverend', hover)
class MRTest extends MREntity {
constructor() {
super()
this.gridWidth = 2
this.gridHeight = 2
this.gridDepth = 1

model.addEventListener('touchstart', click)
model.addEventListener('touchend', click)
this.modScale = 0.25
}

model.dataset.position = `${x * scale} ${y * scale} ${z * scale}`
connected() {
let fischCount = 0

for(let x = -this.gridWidth / 2; x < this.gridWidth / 2; x++) {
for(let y = 0; y < this.gridHeight; y++) {
for(let z = 0; z < this.gridDepth; z++) {
let model = document.createElement('mr-model')
let label = document.createElement('mr-text')

fischCount += 1
this.appendChild(label)

model.dataset.position = `${x * this.modScale} ${y * this.modScale} ${z * this.modScale}`
label.dataset.position = `${x * this.modScale} ${y * this.modScale + 0.1} ${z * this.modScale}`

model.onLoad = () => {
modelLoaded(model)
}

switch(fischCount) {
case 1:
model.id = 'setAtrr_after'
label.innerText = 'set after'
this.appendChild(model)
model.setAttribute('src', "../examples-assets/models/animation_koifish.glb")
break
case 2:
model.id = 'setAtrr_before'
label.innerText = 'set before'
model.setAttribute('src', "../examples-assets/models/animation_koifish.glb")
this.appendChild(model)
break
case 3:
model.id = 'setSrc_after'
label.innerText = 'src after'
this.appendChild(model)
model.src = "../examples-assets/models/animation_koifish.glb"
break
case 4:
model.id = 'setSrc_before'
label.innerText = 'src before'
model.src = "../examples-assets/models/animation_koifish.glb"
this.appendChild(model)
break

}

model.components.set('animation', {
clip: 1,
action: 'play'
})

model.addEventListener('hoverstart', hover)
model.addEventListener('hoverend', hover)

model.addEventListener('touchstart', click)
model.addEventListener('touchend', click)

}
}
}
}
}

customElements.get('mr-test') || customElements.define('mr-test', MRTest);


function hover(e) {
e.target.hoverMesh.visible = !e.target.hoverMesh.visible
}

function click(e) {
e.target.touchMesh.visible = !e.target.touchMesh.visible
console.log(e.target.touchMesh);

e.target.touchMesh.visible = true
}

let tempBox = new THREE.Box3()
Expand Down
2 changes: 1 addition & 1 deletion src/core/MREntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ export class MREntity extends MRElement {
this.onHover(event);
});

this.addEventListener('child-updated', (event) => {
this.addEventListener('entityupdated', (event) => {
this.triggerGeometryStyleUpdate();
this.triggerMaterialStyleUpdate();
});
Expand Down
4 changes: 2 additions & 2 deletions src/core/componentSystems/GeometryStyleSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class GeometryStyleSystem extends MRSystem {
if (changed) {
// TODO - TBH i think this is only needed for scale, but just in case others use changed
// width/height for anything else, and update is required for children as well
entity.dispatchEvent(new CustomEvent('child-updated', { bubbles: true }));
entity.dispatchEvent(new CustomEvent('entityupdated', { bubbles: true }));
}
}

Expand All @@ -81,7 +81,7 @@ export class GeometryStyleSystem extends MRSystem {
if (changed) {
// TODO - TBH i think this is only needed for scale, but just in case others use changed
// width/height for anything else, and update is required for children as well
entity.dispatchEvent(new CustomEvent('child-updated', { bubbles: true }));
entity.dispatchEvent(new CustomEvent('entityupdated', { bubbles: true }));
}
}
// For this system, since we have the 'per entity' and 'per scene event' update calls,
Expand Down
43 changes: 32 additions & 11 deletions src/core/componentSystems/PhysicsSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class PhysicsSystem extends MRSystem {
this.tempWorldScale = new THREE.Vector3();
this.tempBBox = new THREE.Box3();
this.tempSize = new THREE.Vector3();
this.tempCenter = new THREE.Vector3();

//for oriented BBox
this.savedQuaternion = new THREE.Quaternion();
Expand Down Expand Up @@ -76,6 +77,9 @@ export class PhysicsSystem extends MRSystem {
* @param {Event} e - the event generated by the entity
*/
entityEventUpdate = (e) => {
if (!e.target.physics.body) {
return;
}
if (e.target instanceof MRModelEntity) {
this.updateSimpleBody(e.target);
} else if (e.target instanceof MRDivEntity) {
Expand Down Expand Up @@ -116,7 +120,13 @@ export class PhysicsSystem extends MRSystem {
if (entity instanceof MRDivEntity) {
this.initPhysicsBody(entity);
this.registry.add(entity);
entity.addEventListener('modelchange', this.entityEventUpdate);
entity.addEventListener('modelchange', (e) => {
this.entityEventUpdate(e);
});

entity.addEventListener('entityupdated', (e) => {
this.entityEventUpdate(e);
});
}
}

Expand All @@ -136,18 +146,19 @@ export class PhysicsSystem extends MRSystem {
* @param {MREntity} entity - the entity being updated
*/
initPhysicsBody(entity) {
const rigidBodyDesc = mrjsUtils.physics.RAPIER.RigidBodyDesc.fixed();
entity.physics.body = mrjsUtils.physics.world.createRigidBody(rigidBodyDesc);
entity.object3D.getWorldPosition(this.tempWorldPosition);
entity.object3D.getWorldQuaternion(this.tempWorldQuaternion);
entity.physics.body.setTranslation(...this.tempWorldPosition, true);
entity.physics.body.setRotation(this.tempWorldQuaternion, true);
// TODO: we should find a way to consolidate these 2, UI and Model are created in slightly different ways
// and model will get more complex as we add convexMesh support
if (entity instanceof MRModelEntity) {
this.initSimpleBody(entity);
} else if (entity instanceof MRDivEntity) {
this.initUIEntityBody(entity);
}

entity.object3D.getWorldPosition(this.tempWorldPosition);
entity.object3D.getWorldQuaternion(this.tempWorldQuaternion);
entity.physics.body.setTranslation(...this.tempWorldPosition, true);
entity.physics.body.setRotation(this.tempWorldQuaternion, true);
}

/**
Expand Down Expand Up @@ -205,15 +216,21 @@ export class PhysicsSystem extends MRSystem {
entity.physics.halfExtents.copy(this.tempSize);
entity.physics.halfExtents.divideScalar(2);

const rigidBodyDesc = mrjsUtils.physics.RAPIER.RigidBodyDesc.fixed();
entity.physics.body = mrjsUtils.physics.world.createRigidBody(rigidBodyDesc);

let colliderDesc = mrjsUtils.physics.RAPIER.ColliderDesc.cuboid(...entity.physics.halfExtents);
colliderDesc.setCollisionGroups(mrjsUtils.physics.CollisionGroups.UI);

this.tempBBox.getCenter(this.tempCenter);
entity.object3D.getWorldPosition(this.tempWorldPosition);
this.tempCenter.subVectors(this.tempCenter, this.tempWorldPosition);

colliderDesc.setTranslation(...this.tempCenter);

entity.physics.collider = mrjsUtils.physics.world.createCollider(colliderDesc, entity.physics.body);
mrjsUtils.physics.COLLIDER_ENTITY_MAP[entity.physics.collider.handle] = entity;

entity.physics.collider.setActiveCollisionTypes(mrjsUtils.physics.RAPIER.ActiveCollisionTypes.DEFAULT | mrjsUtils.physics.RAPIER.ActiveCollisionTypes.KINEMATIC_FIXED);
entity.physics.collider.setActiveEvents(mrjsUtils.physics.RAPIER.ActiveEvents.COLLISION_EVENTS);

mrjsUtils.physics.COLLIDER_ENTITY_MAP[entity.physics.collider.handle] = entity;
}

/**
Expand Down Expand Up @@ -340,8 +357,12 @@ export class PhysicsSystem extends MRSystem {

entity.physics.halfExtents.copy(this.tempSize);
entity.physics.halfExtents.divideScalar(2);

entity.physics.collider.setHalfExtents(entity.physics.halfExtents);

this.tempBBox.getCenter(this.tempCenter);
entity.object3D.getWorldPosition(this.tempWorldPosition);
this.tempCenter.subVectors(this.tempCenter, this.tempWorldPosition);
entity.physics.collider.setTranslationWrtParent({ ...this.tempCenter });
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/core/entities/MRImageEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class MRImageEntity extends MRMediaEntity {
// passed through MRMediaEntity directly is undefined since it is not
// a direct element for users. So we do the if-check here and then
// follow the same as the parent's functionality.
if (mutation.type != 'attributes' && mutation.attributeName == 'src') {
if (mutation.type == 'attributes' && mutation.attributeName == 'src') {
super.mutated();
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/entities/MRMediaEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export class MRMediaEntity extends MRDivEntity {
mutated(mutation) {
super.mutated();

if (mutation.type != 'attributes' && mutation.attributeName == 'src') {
if (mutation.type == 'attributes' && mutation.attributeName == 'src') {
this.media.setAttribute('src', this.getAttribute('src'));
this.computeObjectFitDimensions();
this.loadMediaTexture();
Expand Down
49 changes: 36 additions & 13 deletions src/core/entities/MRModelEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export class MRModelEntity extends MRDivEntity {

this.ignoreStencil = true;
this.object3D.name = 'model';

// TODO: replace with single status enum.
this.loading = false;
this.loaded = false;

Expand Down Expand Up @@ -57,10 +59,24 @@ export class MRModelEntity extends MRDivEntity {
* and none of the above class extensions for Model have it as a defined property.
*/
set src(value) {
let url = mrjsUtils.html.resolvePath(value);
if (this.#src != url) {
this.#src = url;
this.setAttribute('src', url);
if (this.#src != value) {
this.#src = value;
if (this.#src != this.getAttribute('src')) {
this.setAttribute('src', value);
}
}
}

/**
* @function
* @description Callback function of MREntity - Updates the media's cover,fill,etc based on the mutation request.
* @param {object} mutation - the update/change/mutation to be handled.
*/
mutated(mutation) {
super.mutated();

if (mutation.type == 'attributes' && mutation.attributeName == 'src') {
this.src = this.getAttribute('src');
if (!this.loading) {
this.loadModel();
}
Expand All @@ -76,20 +92,20 @@ export class MRModelEntity extends MRDivEntity {

const extension = this.src.slice(((this.src.lastIndexOf('.') - 1) >>> 0) + 2);

let modelChange = false;
let modelChanged = false;
if (this.modelObj) {
this.modelObj.visible = false;
while (this.modelObj.parent) {
this.modelObj.removeFromParent();
}

this.modelObj = null;

modelChange = true;
modelChanged = true;
}

try {
const result = await mrjsUtils.model.loadModel(this.src, extension);
let url = mrjsUtils.html.resolvePath(this.src);
const result = await mrjsUtils.model.loadModel(url, extension);

// Handle the different formats of the loaded result
this.modelObj =
Expand All @@ -110,8 +126,6 @@ export class MRModelEntity extends MRDivEntity {
this.modelObj.receiveShadow = true;
this.modelObj.renderOrder = 3;

this.loaded = true;

this.traverseObjects((object) => {
if (object.isMesh) {
object.renderOrder = 3;
Expand All @@ -124,7 +138,9 @@ export class MRModelEntity extends MRDivEntity {

this.loading = false;

if (modelChange) {
this.loaded = true;

if (this.isConnected && modelChanged) {
this.dispatchEvent(new CustomEvent('modelchange', { bubbles: true }));
}
} catch (error) {
Expand All @@ -138,9 +154,16 @@ export class MRModelEntity extends MRDivEntity {
* Includes loading up the model and associated data.
*/
async connected() {
this.#src = this.getAttribute('src') ? mrjsUtils.html.resolvePath(this.getAttribute('src')) : null;
this.src = this.getAttribute('src');
if (!this.src || this.loaded) {
return;
return new Promise((resolve) => {
const interval = setInterval(() => {
if (this.loaded) {
clearInterval(interval);
resolve();
}
}, 100);
});
}

if (!this.loading) {
Expand Down

0 comments on commit 4e0641c

Please sign in to comment.