mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-21 01:25:32 -04:00
18cd4f9110
- These are advanced expressions mostly useful for extensions manipulating objects in 3D space.
275 lines
7.1 KiB
TypeScript
275 lines
7.1 KiB
TypeScript
namespace gdjs {
|
|
export interface PixiImageManager {
|
|
_threeAnimationFrameTextureManager: ThreeAnimationFrameTextureManager;
|
|
}
|
|
/**
|
|
* The renderer for a {@link gdjs.CustomRuntimeObject3D} using Three.js.
|
|
* @category Renderers > Custom Object 3D
|
|
*/
|
|
export class CustomRuntimeObject3DRenderer
|
|
implements gdjs.RuntimeInstanceContainerRenderer
|
|
{
|
|
_object: gdjs.CustomRuntimeObject3D;
|
|
_instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer;
|
|
_isContainerDirty: boolean = true;
|
|
_threeGroup: THREE.Group;
|
|
private _basis: Basis | null = null;
|
|
private static matrix4: THREE.Matrix4 | null = null;
|
|
|
|
constructor(
|
|
object: gdjs.CustomRuntimeObject3D,
|
|
instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer,
|
|
parent: gdjs.RuntimeInstanceContainer
|
|
) {
|
|
this._object = object;
|
|
this._instanceContainer = instanceContainer;
|
|
|
|
this._threeGroup = new THREE.Group();
|
|
this._threeGroup.rotation.order = 'ZYX';
|
|
//@ts-ignore
|
|
this._threeGroup.gdjsRuntimeObject = object;
|
|
|
|
const layer = parent.getLayer('');
|
|
if (layer) {
|
|
layer.getRenderer().add3DRendererObject(this._threeGroup);
|
|
}
|
|
}
|
|
|
|
get3DRendererObject(): THREE.Object3D {
|
|
return this._threeGroup;
|
|
}
|
|
|
|
getRendererObject() {
|
|
return null;
|
|
}
|
|
|
|
reinitialize(
|
|
object: gdjs.CustomRuntimeObject3D,
|
|
parent: gdjs.RuntimeInstanceContainer
|
|
) {
|
|
this._object = object;
|
|
this._isContainerDirty = true;
|
|
this._threeGroup.clear();
|
|
}
|
|
|
|
_updateThreeGroup() {
|
|
const threeObject3D = this.get3DRendererObject();
|
|
|
|
const scaleX = this._object.getScaleX();
|
|
const scaleY = this._object.getScaleY();
|
|
const scaleZ = this._object.getScaleZ();
|
|
const pivotX = this._object.getUnscaledCenterX() * scaleX;
|
|
const pivotY = this._object.getUnscaledCenterY() * scaleY;
|
|
const pivotZ = this._object.getUnscaledCenterZ() * scaleZ;
|
|
|
|
threeObject3D.rotation.set(
|
|
gdjs.toRad(this._object.getRotationX()),
|
|
gdjs.toRad(this._object.getRotationY()),
|
|
gdjs.toRad(this._object.angle)
|
|
);
|
|
|
|
threeObject3D.position.set(
|
|
this._object.isFlippedX() ? pivotX : -pivotX,
|
|
this._object.isFlippedY() ? pivotY : -pivotY,
|
|
this._object.isFlippedZ() ? pivotZ : -pivotZ
|
|
);
|
|
threeObject3D.position.applyEuler(threeObject3D.rotation);
|
|
threeObject3D.position.x += this._object.getX() + pivotX;
|
|
threeObject3D.position.y += this._object.getY() + pivotY;
|
|
threeObject3D.position.z += this._object.getZ() + pivotZ;
|
|
|
|
threeObject3D.scale.set(
|
|
this._object.isFlippedX() ? -scaleX : scaleX,
|
|
this._object.isFlippedY() ? -scaleY : scaleY,
|
|
this._object.isFlippedZ() ? -scaleZ : scaleZ
|
|
);
|
|
|
|
threeObject3D.visible = !this._object.hidden;
|
|
|
|
this._isContainerDirty = false;
|
|
}
|
|
|
|
/**
|
|
* Call this to make sure the object is ready to be rendered.
|
|
*/
|
|
ensureUpToDate() {
|
|
if (this._isContainerDirty) {
|
|
this._updateThreeGroup();
|
|
}
|
|
}
|
|
|
|
update(): void {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updateX(): void {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updateY(): void {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updateAngle(): void {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updatePosition() {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updateRotation() {
|
|
this._isContainerDirty = true;
|
|
if (this._basis) {
|
|
this._basis.isDirty = true;
|
|
}
|
|
}
|
|
|
|
updateSize() {
|
|
this._isContainerDirty = true;
|
|
}
|
|
|
|
updateVisibility(): void {
|
|
this._threeGroup.visible = !this._object.hidden;
|
|
}
|
|
|
|
updateOpacity(): void {
|
|
// Opacity is not handled by 3D custom objects.
|
|
}
|
|
|
|
setLayerIndex(layer: gdjs.RuntimeLayer, index: float): void {
|
|
// Layers are not handled for 3D custom objects.
|
|
}
|
|
|
|
getForwardX(): float {
|
|
return this.getBasis().forwardX;
|
|
}
|
|
|
|
getForwardY(): float {
|
|
return this.getBasis().forwardY;
|
|
}
|
|
|
|
getForwardZ(): float {
|
|
return this.getBasis().forwardZ;
|
|
}
|
|
|
|
getUpX(): float {
|
|
return this.getBasis().upX;
|
|
}
|
|
|
|
getUpY(): float {
|
|
return this.getBasis().upY;
|
|
}
|
|
|
|
getUpZ(): float {
|
|
return this.getBasis().upZ;
|
|
}
|
|
|
|
getRightX(): float {
|
|
return this.getBasis().rightX;
|
|
}
|
|
|
|
getRightY(): float {
|
|
return this.getBasis().rightY;
|
|
}
|
|
|
|
getRightZ(): float {
|
|
return this.getBasis().rightZ;
|
|
}
|
|
|
|
private getBasis(): Basis {
|
|
if (!this._basis) {
|
|
this._basis = new Basis();
|
|
}
|
|
if (!this._basis.isDirty) {
|
|
return this._basis;
|
|
}
|
|
|
|
const threeObject3D = this.get3DRendererObject();
|
|
// Make sure the rotation is up to date.
|
|
threeObject3D.rotation.set(
|
|
gdjs.toRad(this._object.getRotationX()),
|
|
gdjs.toRad(this._object.getRotationY()),
|
|
gdjs.toRad(this._object.angle)
|
|
);
|
|
|
|
let rotationMatrix = gdjs.CustomRuntimeObject3DRenderer.matrix4;
|
|
if (!rotationMatrix) {
|
|
rotationMatrix = new THREE.Matrix4();
|
|
gdjs.CustomRuntimeObject3DRenderer.matrix4 = rotationMatrix;
|
|
}
|
|
rotationMatrix.makeRotationFromEuler(threeObject3D.rotation);
|
|
const elements = rotationMatrix.elements;
|
|
|
|
this._basis.forwardX = elements[0];
|
|
this._basis.forwardY = elements[1];
|
|
this._basis.forwardZ = elements[2];
|
|
|
|
this._basis.rightX = -elements[4];
|
|
this._basis.rightY = -elements[5];
|
|
this._basis.rightZ = -elements[6];
|
|
|
|
this._basis.upX = elements[8];
|
|
this._basis.upY = elements[9];
|
|
this._basis.upZ = elements[10];
|
|
|
|
return this._basis;
|
|
}
|
|
|
|
static getAnimationFrameTextureManager(
|
|
imageManager: gdjs.PixiImageManager
|
|
): ThreeAnimationFrameTextureManager {
|
|
if (!imageManager._threeAnimationFrameTextureManager) {
|
|
imageManager._threeAnimationFrameTextureManager =
|
|
new ThreeAnimationFrameTextureManager(imageManager);
|
|
}
|
|
return imageManager._threeAnimationFrameTextureManager;
|
|
}
|
|
}
|
|
|
|
class ThreeAnimationFrameTextureManager
|
|
implements gdjs.AnimationFrameTextureManager<THREE.Material>
|
|
{
|
|
private _imageManager: gdjs.PixiImageManager;
|
|
|
|
constructor(imageManager: gdjs.PixiImageManager) {
|
|
this._imageManager = imageManager;
|
|
}
|
|
|
|
getAnimationFrameTexture(imageName: string) {
|
|
return this._imageManager.getThreeMaterial(imageName, {
|
|
useTransparentTexture: true,
|
|
forceBasicMaterial: true,
|
|
vertexColors: false,
|
|
});
|
|
}
|
|
|
|
getAnimationFrameWidth(material: THREE.Material) {
|
|
const map = (
|
|
material as THREE.MeshBasicMaterial | THREE.MeshStandardMaterial
|
|
).map;
|
|
return map ? map.image.width : 0;
|
|
}
|
|
|
|
getAnimationFrameHeight(material: THREE.Material) {
|
|
const map = (
|
|
material as THREE.MeshBasicMaterial | THREE.MeshStandardMaterial
|
|
).map;
|
|
return map ? map.image.height : 0;
|
|
}
|
|
}
|
|
|
|
class Basis {
|
|
isDirty = true;
|
|
forwardX: float = 0;
|
|
forwardY: float = 0;
|
|
forwardZ: float = 0;
|
|
upX: float = 0;
|
|
upY: float = 0;
|
|
upZ: float = 0;
|
|
rightX: float = 0;
|
|
rightY: float = 0;
|
|
rightZ: float = 0;
|
|
}
|
|
}
|