Skip to content

Commit

Permalink
Make 3D model instance renderer dynamic and fix warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
4ian committed Sep 15, 2024
1 parent 5158d68 commit 5b4dfd5
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 88 deletions.
238 changes: 156 additions & 82 deletions Extensions/3D/JsExtension.js
Original file line number Diff line number Diff line change
Expand Up @@ -2504,9 +2504,9 @@ module.exports = {
const scaleY = height * (this._instance.isFlippedY() ? -1 : 1);
const scaleZ = depth * (this._instance.isFlippedZ() ? -1 : 1);
if (
scaleX !== this._threeObject.scale.width ||
scaleY !== this._threeObject.scale.height ||
scaleZ !== this._threeObject.scale.depth
scaleX !== this._threeObject.scale.x ||
scaleY !== this._threeObject.scale.y ||
scaleZ !== this._threeObject.scale.z
) {
this._threeObject.scale.set(scaleX, scaleY, scaleZ);
uvMappingDirty = true;
Expand Down Expand Up @@ -3023,6 +3023,17 @@ module.exports = {
}
}

const isSamePoint = (point1, point2) => {
if (!point1 && !point2) return true;
if (point1 && !point2) return false;
if (!point1 && point2) return false;
return (
point1[0] === point2[0] &&
point1[1] === point2[1] &&
point1[2] === point2[2]
);
};

const getPointForLocation = (location) => {
switch (location) {
case 'ModelOrigin':
Expand Down Expand Up @@ -3060,23 +3071,19 @@ module.exports = {
pixiResourcesLoader
);
const properties = associatedObjectConfiguration.getProperties();
this._defaultWidth = parseFloat(properties.get('width').getValue());
this._defaultHeight = parseFloat(properties.get('height').getValue());
this._defaultDepth = parseFloat(properties.get('depth').getValue());
const rotationX = parseFloat(properties.get('rotationX').getValue());
const rotationY = parseFloat(properties.get('rotationY').getValue());
const rotationZ = parseFloat(properties.get('rotationZ').getValue());
const keepAspectRatio =
properties.get('keepAspectRatio').getValue() === 'true';
const modelResourceName = properties
.get('modelResourceName')
.getValue();
this._originPoint = getPointForLocation(
properties.get('originLocation').getValue()
);
this._centerPoint = getPointForLocation(
properties.get('centerLocation').getValue()
);
this._defaultWidth = 1;
this._defaultHeight = 1;
this._defaultDepth = 1;
this._originalWidth = 1;
this._originalHeight = 1;
this._originalDepth = 1;
this._rotationX = 0;
this._rotationY = 0;
this._rotationZ = 0;
this._keepAspectRatio = false;

this._originPoint = null;
this._centerPoint = null;

this._pixiObject = new PIXI.Graphics();
this._pixiContainer.addChild(this._pixiObject);
Expand All @@ -3085,28 +3092,8 @@ module.exports = {
this._threeObject.rotation.order = 'ZYX';
this._threeGroup.add(this._threeObject);

this._pixiResourcesLoader
.get3DModel(project, modelResourceName)
.then((model3d) => {
const clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
model3d.scene
);
// This group hold the rotation defined by properties.
const threeObject = new THREE.Group();
threeObject.rotation.order = 'ZYX';
threeObject.add(clonedModel3D);
this._updateDefaultTransformation(
threeObject,
rotationX,
rotationY,
rotationZ,
this._defaultWidth,
this._defaultHeight,
this._defaultDepth,
keepAspectRatio
);
this._threeObject.add(threeObject);
});
this._threeModelGroup = null;
this._clonedModel3D = null;
}

getOriginX() {
Expand Down Expand Up @@ -3147,23 +3134,30 @@ module.exports = {
return this._centerPoint || this._modelOriginPoint;
}

_updateDefaultTransformation(
threeObject,
rotationX,
rotationY,
rotationZ,
originalWidth,
originalHeight,
originalDepth,
keepAspectRatio
) {
threeObject.rotation.set(
(rotationX * Math.PI) / 180,
(rotationY * Math.PI) / 180,
(rotationZ * Math.PI) / 180
_updateDefaultTransformation() {
if (!this._clonedModel3D) return; // Model is not ready - nothing to do.

if (this._threeModelGroup) {
// Remove any previous container as we will recreate it just below
this._threeObject.clear();
}
// This group hold the rotation defined by properties.
// Always restart from a new group to avoid miscomputing bounding boxes/sizes.
this._threeModelGroup = new THREE.Group();
this._threeModelGroup.rotation.order = 'ZYX';
this._threeModelGroup.add(this._clonedModel3D);

const properties = this._associatedObjectConfiguration.getProperties();

this._threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
);
this._threeModelGroup.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(
this._threeModelGroup
);
threeObject.updateMatrixWorld(true);
const boundingBox = new THREE.Box3().setFromObject(threeObject);

const shouldKeepModelOrigin = !this._originPoint;
if (shouldKeepModelOrigin) {
Expand All @@ -3190,7 +3184,7 @@ module.exports = {
// Center the model.
const centerPoint = this._centerPoint;
if (centerPoint) {
threeObject.position.set(
this._threeModelGroup.position.set(
-(boundingBox.min.x + modelWidth * centerPoint[0]),
// The model is flipped on Y axis.
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
Expand All @@ -3199,11 +3193,11 @@ module.exports = {
}

// Rotate the model.
threeObject.scale.set(1, 1, 1);
threeObject.rotation.set(
(rotationX * Math.PI) / 180,
(rotationY * Math.PI) / 180,
(rotationZ * Math.PI) / 180
this._threeModelGroup.scale.set(1, 1, 1);
this._threeModelGroup.rotation.set(
(this._rotationX * Math.PI) / 180,
(this._rotationY * Math.PI) / 180,
(this._rotationZ * Math.PI) / 180
);

// Stretch the model in a 1x1x1 cube.
Expand All @@ -3215,72 +3209,152 @@ module.exports = {
// Flip on Y because the Y axis is on the opposite side of direct basis.
// It avoids models to be like a mirror refection.
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
threeObject.updateMatrix();
threeObject.applyMatrix4(scaleMatrix);
this._threeModelGroup.updateMatrix();
this._threeModelGroup.applyMatrix4(scaleMatrix);

if (keepAspectRatio) {
if (this._keepAspectRatio) {
// Reduce the object dimensions to keep aspect ratio.
const widthRatio =
modelWidth < epsilon
? Number.POSITIVE_INFINITY
: originalWidth / modelWidth;
: this._originalWidth / modelWidth;
const heightRatio =
modelHeight < epsilon
? Number.POSITIVE_INFINITY
: originalHeight / modelHeight;
: this._originalHeight / modelHeight;
const depthRatio =
modelDepth < epsilon
? Number.POSITIVE_INFINITY
: originalDepth / modelDepth;
: this._originalDepth / modelDepth;
const minScaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
if (!Number.isFinite(minScaleRatio)) {
this._defaultWidth = modelWidth;
this._defaultHeight = modelHeight;
this._defaultDepth = modelDepth;
} else {
if (widthRatio === minScaleRatio) {
this._defaultWidth = originalWidth;
this._defaultWidth = this._originalWidth;
this._defaultHeight = Rendered3DInstance.applyRatio({
oldReferenceValue: modelWidth,
newReferenceValue: originalWidth,
newReferenceValue: this._originalWidth,
valueToApplyTo: modelHeight,
});
this._defaultDepth = Rendered3DInstance.applyRatio({
oldReferenceValue: modelWidth,
newReferenceValue: originalWidth,
newReferenceValue: this._originalWidth,
valueToApplyTo: modelDepth,
});
} else if (heightRatio === minScaleRatio) {
this._defaultWidth = Rendered3DInstance.applyRatio({
oldReferenceValue: modelHeight,
newReferenceValue: originalHeight,
newReferenceValue: this._originalHeight,
valueToApplyTo: modelWidth,
});

this._defaultHeight = originalHeight;
this._defaultHeight = this._originalHeight;
this._defaultDepth = Rendered3DInstance.applyRatio({
oldReferenceValue: modelHeight,
newReferenceValue: originalHeight,
newReferenceValue: this._originalHeight,
valueToApplyTo: modelDepth,
});
} else {
this._defaultWidth = Rendered3DInstance.applyRatio({
oldReferenceValue: modelDepth,
newReferenceValue: originalDepth,
newReferenceValue: this._originalDepth,
valueToApplyTo: modelWidth,
});
this._defaultHeight = Rendered3DInstance.applyRatio({
oldReferenceValue: modelDepth,
newReferenceValue: originalDepth,
newReferenceValue: this._originalDepth,
valueToApplyTo: modelHeight,
});
this._defaultDepth = originalDepth;
this._defaultDepth = this._originalDepth;
}
}
}

this._threeObject.add(this._threeModelGroup);
}

updateThreeObject() {
const properties = this._associatedObjectConfiguration.getProperties();

let defaultTransformationDirty = false;

const originalWidth = parseFloat(properties.get('width').getValue());
const originalHeight = parseFloat(properties.get('height').getValue());
const originalDepth = parseFloat(properties.get('depth').getValue());
if (
this._originalWidth !== originalWidth ||
this._originalHeight !== originalHeight ||
this._originalDepth !== originalDepth
) {
this._originalWidth = originalWidth;
this._originalHeight = originalHeight;
this._originalDepth = originalDepth;
defaultTransformationDirty = true;
}

const rotationX = parseFloat(properties.get('rotationX').getValue());
const rotationY = parseFloat(properties.get('rotationY').getValue());
const rotationZ = parseFloat(properties.get('rotationZ').getValue());
if (
this._rotationX !== rotationX ||
this._rotationY !== rotationY ||
this._rotationZ !== rotationZ
) {
this._rotationX = rotationX;
this._rotationY = rotationY;
this._rotationZ = rotationZ;
defaultTransformationDirty = true;
}

const keepAspectRatio =
properties.get('keepAspectRatio').getValue() === 'true';
if (this._keepAspectRatio !== keepAspectRatio) {
this._keepAspectRatio = keepAspectRatio;
defaultTransformationDirty = true;
}

const originPoint = getPointForLocation(
properties.get('originLocation').getValue()
);
if (!isSamePoint(originPoint, this._originPoint)) {
this._originPoint = originPoint;
defaultTransformationDirty = true;
}

const centerPoint = getPointForLocation(
properties.get('centerLocation').getValue()
);
if (!isSamePoint(centerPoint, this._centerPoint)) {
this._centerPoint = centerPoint;
defaultTransformationDirty = true;
}

if (defaultTransformationDirty) this._updateDefaultTransformation();

const modelResourceName = properties
.get('modelResourceName')
.getValue();
if (this._modelResourceName !== modelResourceName) {
this._modelResourceName = modelResourceName;

this._pixiResourcesLoader
.get3DModel(this._project, modelResourceName)
.then((model3d) => {
this._clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
model3d.scene
);

this._updateDefaultTransformation();
});
}

this._updateThreeObjectPosition();
}

_updateThreeObjectPosition() {
const width = this.getWidth();
const height = this.getHeight();
const depth = this.getDepth();
Expand All @@ -3304,9 +3378,9 @@ module.exports = {
const scaleZ = depth * (this._instance.isFlippedZ() ? -1 : 1);

if (
scaleX !== this._threeObject.scale.width ||
scaleY !== this._threeObject.scale.height ||
scaleZ !== this._threeObject.scale.depth
scaleX !== this._threeObject.scale.x ||
scaleY !== this._threeObject.scale.y ||
scaleZ !== this._threeObject.scale.z
) {
this._threeObject.scale.set(scaleX, scaleY, scaleZ);
}
Expand Down
2 changes: 2 additions & 0 deletions newIDE/app/src/CompactPropertiesEditor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ const CompactPropertiesEditor = ({
const { setValue } = field;
compactSelectField = (
<CompactSelectField
key={field.name}
value={getFieldValue({ instances, field })}
id={field.name}
onChange={(newValue: string) => {
Expand All @@ -635,6 +636,7 @@ const CompactPropertiesEditor = ({
const { setValue } = field;
compactSelectField = (
<CompactSelectField
key={field.name}
value={getFieldValue({
instances,
field,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ export const CompactObjectPropertiesEditor = ({
.getObjectAt(i);
return (
<CollapsibleSubPanel
key={i}
renderContent={() => (
<ChildObjectPropertiesEditor
key={i}
Expand Down Expand Up @@ -341,6 +342,7 @@ export const CompactObjectPropertiesEditor = ({

return (
<CollapsibleSubPanel
key={behavior.ptr}
renderContent={() => (
<CompactBehaviorPropertiesEditor
project={project}
Expand Down Expand Up @@ -468,6 +470,7 @@ export const CompactObjectPropertiesEditor = ({

return (
<CollapsibleSubPanel
key={effect.ptr}
renderContent={() => (
<ColumnStackLayout expand noOverflowParent>
<CompactSelectField
Expand Down
Loading

0 comments on commit 5b4dfd5

Please sign in to comment.