Skip to content

Commit

Permalink
- rename easing expressions for consitency
Browse files Browse the repository at this point in the history
- add warning to scene loader when camera path is not specified
- add actor/easing
- add actor/fit
- add actor/setObjectPolarTransform
- fix lerp in actor/setObjectAttribute
  • Loading branch information
frading committed Jul 17, 2022
1 parent e6fb19f commit 6325743
Show file tree
Hide file tree
Showing 29 changed files with 1,175 additions and 212 deletions.
42 changes: 42 additions & 0 deletions src/core/PolarTransform.ts
@@ -0,0 +1,42 @@
import {Vector3, Quaternion, Object3D, Matrix4, MathUtils} from 'three';

export interface PolarTransformMatrixParams {
center: Vector3;
longitude: number;
latitude: number;
depth: number;
}

const POLAR_TRANSFORM_AXIS_VERTICAL = new Vector3(0, 1, 0);
const POLAR_TRANSFORM_AXIS_HORIZONTAL = new Vector3(-1, 0, 0);

const centerMatrix = new Matrix4();
const longitudeMatrix = new Matrix4();
const latitudeMatrix = new Matrix4();
const depthMatrix = new Matrix4();
const decomposed = {
t: new Vector3(),
q: new Quaternion(),
s: new Vector3(),
};

export class CorePolarTransform {
static matrix(params: PolarTransformMatrixParams, target: Matrix4) {
centerMatrix.identity();
longitudeMatrix.identity();
latitudeMatrix.identity();
depthMatrix.identity();
centerMatrix.makeTranslation(params.center.x, params.center.y, params.center.z);
longitudeMatrix.makeRotationAxis(POLAR_TRANSFORM_AXIS_VERTICAL, MathUtils.degToRad(params.longitude));
latitudeMatrix.makeRotationAxis(POLAR_TRANSFORM_AXIS_HORIZONTAL, MathUtils.degToRad(params.latitude));
depthMatrix.makeTranslation(0, 0, params.depth);
target.copy(centerMatrix).multiply(longitudeMatrix).multiply(latitudeMatrix).multiply(depthMatrix);
}
static applyMatrixToObject(object: Object3D, matrix: Matrix4) {
matrix.decompose(decomposed.t, decomposed.q, decomposed.s);
object.position.copy(decomposed.t);
object.quaternion.copy(decomposed.q);
object.scale.copy(decomposed.s);
object.updateMatrix();
}
}
57 changes: 57 additions & 0 deletions src/core/animation/Keyframe.ts
@@ -0,0 +1,57 @@
import {Vector2Like} from './../../types/GlobalTypes';
import {CubicBezierCurve, Vector2} from 'three';
export interface KeyframeData {
pos: number;
value: number;
tan: Vector2Like;
}
export type ChannelData = KeyframeData[];
export interface ChannelsData {
[Key: string]: ChannelData;
}

const tmp = new Vector2();
// const tmp2 = new Vector2();
export function cubicBezierCurveFromKeyframes(unsortedKeyframes: KeyframeData[]): CubicBezierCurve[] {
const list: CubicBezierCurve[] = [];
if (unsortedKeyframes.length < 2) {
return list;
}
const keyframes = unsortedKeyframes.sort((k1, k2) => k1.pos - k2.pos);

for (let i = 0; i < keyframes.length - 1; i++) {
const currentKeyframe = keyframes[i];
const nextKeyframe = keyframes[i + 1];
// p0
const p0 = new Vector2(currentKeyframe.pos, currentKeyframe.value);
// p1
tmp.set(currentKeyframe.tan.x, currentKeyframe.tan.y);
const p1 = new Vector2(currentKeyframe.pos, currentKeyframe.value).add(tmp);
// p2
tmp.set(nextKeyframe.tan.x, nextKeyframe.tan.y);
const p2 = new Vector2(nextKeyframe.pos, nextKeyframe.value).sub(tmp);
// p3
const p3 = new Vector2(nextKeyframe.pos, nextKeyframe.value);
// curve
const curve = new CubicBezierCurve(p0, p1, p2, p3);
list.push(curve);
}
return list;
}

export function getPointFromCurves(t: number, curves: CubicBezierCurve[], target: Vector2) {
let selectedCurve: CubicBezierCurve | undefined;
for (let curve of curves) {
if (t <= curve.v3.x) {
selectedCurve = curve;
break;
}
}
if (selectedCurve == null) {
return 0;
}
const minT = selectedCurve.v0.x;
const maxT = selectedCurve.v3.x;
const remappedT = (t - minT) / (maxT - minT);
selectedCurve.getPoint(remappedT, target);
}
22 changes: 22 additions & 0 deletions src/core/geometry/Attribute.ts
Expand Up @@ -3,8 +3,11 @@ import {Vector3} from 'three';
import {Vector4} from 'three';
import {BufferAttribute} from 'three';
import {AttribValue, PolyDictionary} from '../../types/GlobalTypes';
import {ArrayUtils} from '../ArrayUtils';
import {CoreString} from '../String';
import {CoreType} from '../Type';
import {AttribSize} from './Constant';
import {GroupString} from './Group';

export enum Attribute {
POINT_INDEX = 'ptnum',
Expand Down Expand Up @@ -108,4 +111,23 @@ export class CoreAttribute {
}
return 0;
}
static attribNamesMatchingMask(masksString: GroupString, existingAttribNames: string[]) {
const masks = CoreString.attribNames(masksString);

const matchingAttribNames: string[] = [];
for (const mask of masks) {
for (const attribName of existingAttribNames) {
if (CoreString.matchMask(attribName, mask)) {
matchingAttribNames.push(attribName);
} else {
const remapped = CoreAttribute.remapName(mask);
if (attribName == remapped) {
matchingAttribNames.push(attribName);
}
}
}
}

return ArrayUtils.uniq(matchingAttribNames);
}
}
19 changes: 5 additions & 14 deletions src/core/geometry/Geometry.ts
Expand Up @@ -19,7 +19,6 @@ import {CoreAttributeData} from './AttributeData';
import {CoreType} from '../Type';
import {ArrayUtils} from '../ArrayUtils';
import {ObjectUtils} from '../ObjectUtils';
import {CoreString} from '../String';
import {GroupString} from './Group';

const IS_INSTANCE_KEY = 'isInstance';
Expand Down Expand Up @@ -112,19 +111,11 @@ export class CoreGeometry {
attribNames(): string[] {
return CoreGeometry.attribNames(this._geometry);
}
static attribNamesMatchingMask(geometry: BufferGeometry, masks_string: GroupString) {
const masks = CoreString.attribNames(masks_string);

const matching_attrib_names: string[] = [];
for (let attrib_name of this.attribNames(geometry)) {
for (let mask of masks) {
if (CoreString.matchMask(attrib_name, mask)) {
matching_attrib_names.push(attrib_name);
}
}
}

return ArrayUtils.uniq(matching_attrib_names);
static attribNamesMatchingMask(geometry: BufferGeometry, masksString: GroupString) {
return CoreAttribute.attribNamesMatchingMask(masksString, this.attribNames(geometry));
}
attribNamesMatchingMask(masksString: GroupString) {
return CoreGeometry.attribNamesMatchingMask(this._geometry, masksString);
}

attribSizes() {
Expand Down
20 changes: 2 additions & 18 deletions src/core/geometry/Group.ts
Expand Up @@ -420,24 +420,8 @@ export class CoreGroup {
}
}

attribNamesMatchingMask(masks_string: GroupString) {
const masks = CoreString.attribNames(masks_string);

const matching_attrib_names: string[] = [];
for (let mask of masks) {
for (let attrib_name of this.attribNames()) {
if (CoreString.matchMask(attrib_name, mask)) {
matching_attrib_names.push(attrib_name);
} else {
const remapped = CoreAttribute.remapName(mask);
if (attrib_name == remapped) {
matching_attrib_names.push(attrib_name);
}
}
}
}

return ArrayUtils.uniq(matching_attrib_names);
attribNamesMatchingMask(masksString: GroupString) {
return CoreAttribute.attribNamesMatchingMask(masksString, this.attribNames());
}

attribSizes() {
Expand Down
76 changes: 56 additions & 20 deletions src/core/math/Easing.ts
Expand Up @@ -4,23 +4,59 @@
// const ease_on = function(t:number, power:number){return 1 - Math.abs(Math.pow(t-1, power))}
// const ease_ion = function(t:number, power:number){return t<.5 ? ease_i(power)(t*2)/2 : ease_o(power)(t*2 - 1)/2+0.5}

const ease_i = function (power: number) {
const easeI = function (power: number) {
return function (t: number) {
return Math.pow(t, power);
};
};
const ease_o = function (power: number) {
const easeO = function (power: number) {
return function (t: number) {
return 1 - Math.abs(Math.pow(t - 1, power));
};
};
const ease_io = function (power: number) {
const easeIO = function (power: number) {
return function (t: number) {
return t < 0.5 ? ease_i(power)(t * 2) / 2 : ease_o(power)(t * 2 - 1) / 2 + 0.5;
return t < 0.5 ? easeI(power)(t * 2) / 2 : easeO(power)(t * 2 - 1) / 2 + 0.5;
};
};

export const Easing = {
type EasingFunction = (num: number) => number;
export interface EasingDictionary {
easeI2: EasingFunction;
easeO2: EasingFunction;
easeIO2: EasingFunction;
easeI3: EasingFunction;
easeO3: EasingFunction;
easeIO3: EasingFunction;
easeI4: EasingFunction;
easeO4: EasingFunction;
easeIO4: EasingFunction;
easeSinI: EasingFunction;
easeSinO: EasingFunction;
easeSinIO: EasingFunction;
easeElasticI: EasingFunction;
easeElasticO: EasingFunction;
easeElasticIO: EasingFunction;
}
export const EASING_NAMES: Array<keyof EasingDictionary> = [
'easeI2',
'easeO2',
'easeIO2',
'easeI3',
'easeO3',
'easeIO3',
'easeI4',
'easeO4',
'easeIO4',
'easeSinI',
'easeSinO',
'easeSinIO',
'easeElasticI',
'easeElasticO',
'easeElasticIO',
];

export const Easing: EasingDictionary = {
// linear: ease_io(1),

// ease_i: function (t: number, power: number) {
Expand All @@ -33,41 +69,41 @@ export const Easing = {
// return ease_io(power)(t);
// },

ease_i2: ease_i(2),
ease_o2: ease_o(2),
ease_io2: ease_io(2),
easeI2: easeI(2),
easeO2: easeO(2),
easeIO2: easeIO(2),

ease_i3: ease_i(3),
ease_o3: ease_o(3),
ease_io3: ease_io(3),
easeI3: easeI(3),
easeO3: easeO(3),
easeIO3: easeIO(3),

ease_i4: ease_i(4),
ease_o4: ease_o(4),
ease_io4: ease_io(4),
easeI4: easeI(4),
easeO4: easeO(4),
easeIO4: easeIO(4),
// easeInQuart: EaseIn(4),
// easeOutQuart: EaseOut(4),
// easeInOutQuart: EaseInOut(4),
// easeInQuint: EaseIn(5),
// easeOutQuint: EaseOut(5),
// easeInOutQuint: EaseInOut(5)

ease_i_sin: function (t: number) {
easeSinI: function (t: number) {
return 1 + Math.sin((Math.PI / 2) * t - Math.PI / 2);
},
ease_o_sin: function (t: number) {
easeSinO: function (t: number) {
return Math.sin((Math.PI / 2) * t);
},
ease_io_sin: function (t: number) {
easeSinIO: function (t: number) {
return (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;
},

ease_i_elastic: function (t: number) {
easeElasticI: function (t: number) {
return t == 0 ? 0 : (0.04 - 0.04 / t) * Math.sin(25 * t) + 1;
},
ease_o_elastic: function (t: number) {
easeElasticO: function (t: number) {
return t == 1 ? 1 : ((0.04 * t) / --t) * Math.sin(25 * t);
},
ease_io_elastic: function (t: number) {
easeElasticIO: function (t: number) {
return t == 0.5
? 0
: (t -= 0.5) < 0
Expand Down
30 changes: 15 additions & 15 deletions src/engine/expressions/traversers/FunctionGenerator.ts
Expand Up @@ -108,21 +108,21 @@
*
* And the following are alias to the [Polygonjs Easing](https://github.com/polygonjs/polygonjs-engine/blob/master/src/core/math/Easing.ts) module:
*
* - `ease_i2( number )`, is a shortcut for `ease_i( number, 2 )`
* - `ease_o2( number )`, is a shortcut for `ease_o( number, 2 )`
* - `ease_io2( number )`, is a shortcut for `ease_io( number, 2 )`
* - `ease_i3( number )`, is a shortcut for `ease_i( number, 3 )`
* - `ease_o3( number )`, is a shortcut for `ease_o( number, 3 )`
* - `ease_io3( number )`, is a shortcut for `ease_io( number, 3 )`
* - `ease_i4( number )`, is a shortcut for `ease_i( number, 4 )`
* - `ease_o4( number )`, is a shortcut for `ease_o( number, 4 )`
* - `ease_io4( number )`, is a shortcut for` ease_io( number, 4 )`
* - `ease_i_sin( number )`
* - `ease_o_sin( number )`
* - `ease_io_sin( number )`
* - `ease_i_elastic( number )`
* - `ease_o_elastic( number )`
* - `ease_io_elastic( number )`
* - `easeI2( number )`, is a shortcut for `ease_i( number, 2 )`
* - `easeO2( number )`, is a shortcut for `ease_o( number, 2 )`
* - `easeIO2( number )`, is a shortcut for `ease_io( number, 2 )`
* - `easeI3( number )`, is a shortcut for `ease_i( number, 3 )`
* - `easeO3( number )`, is a shortcut for `ease_o( number, 3 )`
* - `easeIO3( number )`, is a shortcut for `ease_io( number, 3 )`
* - `easeI4( number )`, is a shortcut for `ease_i( number, 4 )`
* - `easeO4( number )`, is a shortcut for `ease_o( number, 4 )`
* - `easeIO4( number )`, is a shortcut for` ease_io( number, 4 )`
* - `easeSinI( number )`
* - `easeSinO( number )`
* - `easeSinIO( number )`
* - `easeElasticI( number )`
* - `easeElasticO( number )`
* - `easeElasticIO( number )`
*
*
* ## String expressions:
Expand Down
6 changes: 4 additions & 2 deletions src/engine/io/player/Scene.ts
Expand Up @@ -59,6 +59,7 @@ export class ScenePlayerImporter {
private _viewer: BaseViewerType | undefined;
private _onLoadCompleteCalled = false;
private _onCameraCreatorNodeLoadedResolve: OnCameraCreatorNodeLoadedResolve | undefined;
private _progress = 0;
// private _cameraCreatorNode: BaseNodeType | null = null;
constructor(private options: SceneDataImportOptions) {}

Expand Down Expand Up @@ -139,6 +140,8 @@ export class ScenePlayerImporter {
const progressRatio = PROGRESS_RATIO.nodes;
const onProgress = (_ratio: number, args: OnProgressArguments) => {
const progress = progressRatio.start + progressRatio.mult * _ratio;
this._progress = progress;

if (this.options.onProgress) {
this.options.onProgress(progress, args);
}
Expand Down Expand Up @@ -183,10 +186,9 @@ export class ScenePlayerImporter {
scene.camerasController.onCameraObjectsUpdated(async () => {
const camera = await scene.camerasController.mainCamera({
findAnyCamera: false,
printWarning: false,
printCameraNotFoundError: this._progress >= 1, // we display a warning if progress is 1
cameraMaskOverride: this.options.cameraMaskOverride,
});
// if we do not find the camera object, we need to
if (camera) {
if (this._onCameraCreatorNodeLoadedResolve) {
this._onCameraCreatorNodeLoadedResolve();
Expand Down

0 comments on commit 6325743

Please sign in to comment.