Skip to content

Commit

Permalink
feat: camera trasition to animation
Browse files Browse the repository at this point in the history
  • Loading branch information
Neosoulink committed Dec 20, 2023
1 parent d56bf68 commit 6ab8b67
Show file tree
Hide file tree
Showing 18 changed files with 390 additions and 176 deletions.
6 changes: 2 additions & 4 deletions src/experiences/blueprints/Scene.blueprint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ export abstract class SceneBlueprint
protected readonly _appCamera = this._experience.app.camera;
protected readonly _Loader = this._experience.loader;
protected readonly _modelMeshes: { [name: string]: Mesh | undefined } = {};

protected _modelChildrenTextures: ModelChildrenTextures[];
protected _model?: GLTF;

public modelScene?: Group;
public cameraPath: CatmullRomCurve3;
public readonly eventListNames = {
constructed: "constructed",
destructed: "destructed",
};

constructor(_: SceneBlueprintProps) {
super();
Expand Down
8 changes: 4 additions & 4 deletions src/experiences/config/Common.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export abstract class CommonConfig {
static readonly ASSET_DIR = "/";
static readonly GSAP_ANIMATION_DURATION = 3;
static readonly GSAP_ANIMATION_DURATION = 2;
static readonly GSAP_ANIMATION_EASE =
"M0,0 C0.001,0.001 0.002,0.003 0.003,0.004 0.142,0.482 0.284,0.75 0.338,0.836 0.388,0.924 0.504,1 1,1 ";
"M0,0 C0.001,0.001 0.002,0.003 0.003,0.004 0.142,0.482 0.284,0.75 0.338,0.836 0.388,0.924 0.504,1 1,1";
static readonly HOME_DOM_REF = "home-three-app";
static readonly DEBUG = (() => {
try {
Expand All @@ -13,14 +13,14 @@ export abstract class CommonConfig {
})();
static readonly FIXED_WINDOW_HEIGHT = (() => {
try {
return window.outerHeight
return window.outerHeight;
} catch (_) {
return 0;
}
})();
static readonly FIXED_WINDOW_WIDTH = (() => {
try {
return window.outerWidth
return window.outerWidth;
} catch (_) {
return 0;
}
Expand Down
86 changes: 67 additions & 19 deletions src/experiences/pages/Home/Camera.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PerspectiveCamera, Vector3 } from "three";
import GSAP from "gsap";
import gsap from "gsap";

// EXPERIENCES
import HomeExperience from ".";
Expand All @@ -24,6 +24,8 @@ export class Camera extends ExperienceBasedBlueprint {
protected readonly _experience = new HomeExperience();
protected readonly _appCamera = this._experience.app.camera;
protected readonly _appDebug = this._experience.app.debug;
protected readonly _timeline = gsap.timeline();
protected _lookAtPosition = new Vector3();
protected _currentCameraIndex = 0;
protected _prevCameraProps = {
fov: 0,
Expand All @@ -49,8 +51,6 @@ export class Camera extends ExperienceBasedBlueprint {
: new PerspectiveCamera())(),
];

public lookAtPosition = new Vector3();

constructor() {
super();
}
Expand All @@ -59,7 +59,15 @@ export class Camera extends ExperienceBasedBlueprint {
return this._currentCameraIndex;
}

construct() {
public get lookAtPosition() {
return this._lookAtPosition.clone();
}

public get timeline() {
return this._timeline;
}

public construct() {
if (!Debug.enable && this._appDebug?.cameraHelper) {
this._experience.app.scene.remove(this._appDebug?.cameraHelper);
this._appDebug?.cameraHelper?.remove();
Expand All @@ -77,28 +85,23 @@ export class Camera extends ExperienceBasedBlueprint {
far: this._appCamera.instance.far,
};

if (this._appDebug?.cameraControls) {
this._appDebug.cameraControls.target =
this._experience.world?.manager?.initialLookAtPosition ?? new Vector3();
}

this.emit(CONSTRUCTED);
}

destruct() {
public destruct() {
this.emit(DESTRUCTED);
}

cameraZoomIn() {
public cameraZoomIn() {
if (this._experience.app?.camera.instance instanceof PerspectiveCamera)
GSAP.to(this._experience.app?.camera.instance, {
this._timeline.to(this._experience.app?.camera.instance, {
fov: 25,
});
}

cameraZoomOut() {
public cameraZoomOut() {
if (this._experience.app?.camera.instance instanceof PerspectiveCamera)
GSAP.to(this._experience.app?.camera.instance, {
this._timeline.to(this._experience.app?.camera.instance, {
fov: this._experience.camera?.initialCameraFov ?? 0,
});
}
Expand Down Expand Up @@ -152,25 +155,70 @@ export class Camera extends ExperienceBasedBlueprint {
}

/**
* Set the camera look at position
* @param v3 Vector 3 position where the the camera should look at
* Set the camera look at position.
* @param v3 The {@link Vector3} position where the the camera will look at.
*/
setCameraLookAt(v3: THREE.Vector3) {
this._appCamera?.instance?.lookAt(v3);

if (this._appDebug?.cameraControls)
this._appDebug.cameraControls.target = v3;

this.lookAtPosition = v3;
this._lookAtPosition = v3;
}

update() {}

/** Correct the aspect ration of the camera. */
public correctAspect() {
if (!(this._appCamera.instance instanceof PerspectiveCamera)) return;

this._appCamera.instance.fov = this.initialCameraFov;
this._appCamera.instance.far = 500;
this._appCamera.resize();
}

/**
* Move the camera position with transition from
* the origin position to the passed position and,
* update the lookAt position with the passed lookAt position.
*
* @param toPosition The new camera position.
* @param lookAt Where the camera will look at.
*/
public updateCameraPosition(
toPosition = new Vector3(),
lookAt = new Vector3(),
onStart: gsap.Callback = () => {},
onUpdate: gsap.Callback = () => {},
onComplete: gsap.Callback = () => {}
) {
if (!this._experience.app?.camera.instance) return this._timeline;

const lookAtA = this._lookAtPosition.clone();
const lookAtB = lookAt.clone();

return this._timeline.to(this._experience.app.camera.instance.position, {
x: toPosition.x,
y: toPosition.y,
z: toPosition.z,
duration: Config.GSAP_ANIMATION_DURATION,
ease: Config.GSAP_ANIMATION_EASE,
onStart: () => {
gsap.to(lookAtA, {
x: lookAtB.x,
y: lookAtB.y,
z: lookAtB.z,
duration: Config.GSAP_ANIMATION_DURATION * 0.55,
ease: Config.GSAP_ANIMATION_EASE,
onUpdate: () => {
this?.setCameraLookAt(lookAtA);
},
});
onStart();
},
onUpdate,
onComplete,
});
}

public update() {}
}
95 changes: 95 additions & 0 deletions src/experiences/pages/Home/Composer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
EffectComposer,
Pass,
} from "three/examples/jsm/postprocessing/EffectComposer";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { OutputPass } from "three/examples/jsm/postprocessing/OutputPass.js";

// EXPERIENCES
import HomeExperience from ".";

// BLUEPRINTS
import { ExperienceBasedBlueprint } from "~/experiences/blueprints/ExperienceBased.blueprint";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";
import { Vector3 } from "three";

export class Composer extends ExperienceBasedBlueprint {
protected readonly _experience = new HomeExperience();
protected readonly _appRender = this._experience.app.renderer;
protected readonly _appCamera = this._experience.app.camera;
protected readonly _renderer = this._experience.renderer;
protected readonly _appSizes = this._experience.app.sizes;
protected readonly _passes: { [name: string]: Pass } = {};
protected _effect?: EffectComposer;
protected _renderPass?: RenderPass;
protected _outputPass?: OutputPass;
protected onResize?: () => unknown;

public get effect() {
return this._effect;
}

public construct(): void {
this._effect = new EffectComposer(this._appRender.instance);
this._effect.setPixelRatio(this._appSizes.pixelRatio);
this._effect.setSize(this._appSizes.width, this._appSizes.height);

this.onResize = () => {
this._effect?.setPixelRatio(this._appSizes.pixelRatio);
this._effect?.setSize(this._appSizes.width, this._appSizes.height);
};
this._appSizes.on("resize", this.onResize);
}

public destruct(): void {
this.onResize && this._appSizes.off("resize", this.onResize);
this._effect?.dispose();
this._effect = undefined;
}

public addPass(key: string, pass: Pass) {
if (!this._effect?.passes.length) {
if (this._appCamera.instance) {
this._renderPass = new RenderPass(
this._experience.app.scene,
this._appCamera.instance
);
this._effect?.addPass(this._renderPass);
}

this._outputPass = new OutputPass();
this._effect?.addPass(this._outputPass);
}

this._passes[key] = pass;
this._effect?.addPass(this._passes[key]);
}

public removePass(key: string) {
if (!this._passes[key]) return;

this._effect?.removePass(this._passes[key]);
this._passes[key].dispose();
delete this._passes[key];

if (Object.keys(this._passes).length) return;
this._renderPass && this._effect?.removePass(this._renderPass);
this._outputPass && this._effect?.removePass(this._outputPass);
}

public update(): void {
if (!this._effect?.passes.length) {
this._appRender.enabled = true;
return;
}
this._appRender.enabled = false;

this._appRender.instance.setViewport(
0,
0,
this._appSizes.width,
this._appSizes.height
);
this._effect.render();
}
}
12 changes: 0 additions & 12 deletions src/experiences/pages/Home/Debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,6 @@ export default class Debug extends ExperienceBasedBlueprint {
)
.name("Toggle auto camera animation");

this._gui
.add(
{
fn: () => {
const WorldManager = this._experience.world?.manager;
if (WorldManager) WorldManager.nextScene();
},
},
"fn"
)
.name("Next Scene");

this._experience.app.scene.add(
this._cameraCurvePathLine,
this.cameraLookAtPointIndicator
Expand Down
5 changes: 5 additions & 0 deletions src/experiences/pages/Home/Loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ export default class Loader extends ExperienceBasedBlueprint {
type: "texture",
path: "/3d_models/isometric_room/scene_container_baked_texture.jpg",
},
{
name: "noises_texture",
type: "texture",
path: "/textures/noises.png",
},
]);
}

Expand Down
24 changes: 23 additions & 1 deletion src/experiences/pages/Home/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default class Renderer extends ExperienceBasedBlueprint {
corners: PortalMeshCorners;
};
} = {};
protected readonly beforeRenderUpdateCallbacks: {
[key: string]: () => unknown;
} = {};
protected _currentRenderTarget = this._appRendererInstance.getRenderTarget();
protected _currentXrEnabled = this._appRendererInstance.xr.enabled;
protected _currentShadowAutoUpdate =
Expand Down Expand Up @@ -70,7 +73,7 @@ export default class Renderer extends ExperienceBasedBlueprint {
})();

~(() => {
this._appRenderer.beforeRenderUpdate = () => {
this.addBeforeRenderUpdateCallBack(Renderer.name, () => {
if (!Object.keys(this._renderPortalAssets).length) return;

Object.keys(this._renderPortalAssets).forEach((key: string) => {
Expand All @@ -97,6 +100,16 @@ export default class Renderer extends ExperienceBasedBlueprint {
);
}
});
});
})();

~(() => {
this._appRenderer.beforeRenderUpdate = () => {
Object.keys(this.beforeRenderUpdateCallbacks).forEach(
(key) =>
this.beforeRenderUpdateCallbacks[key] &&
this.beforeRenderUpdateCallbacks[key]()
);
};
})();
}
Expand Down Expand Up @@ -185,4 +198,13 @@ export default class Renderer extends ExperienceBasedBlueprint {
if (this._renderPortalAssets[portalName])
delete this._renderPortalAssets[portalName];
}

public addBeforeRenderUpdateCallBack(key: string, callback: () => unknown) {
this.beforeRenderUpdateCallbacks[key] = callback;
}

public removeBeforeRenderUpdateCallBack(key: string) {
if (this.beforeRenderUpdateCallbacks[key])
delete this.beforeRenderUpdateCallbacks[key];
}
}
Loading

0 comments on commit 6ab8b67

Please sign in to comment.