Skip to content

Commit

Permalink
feat(visualizer): randomize sinusoid amplitudes (#1169)
Browse files Browse the repository at this point in the history
* feat(visualizer): randomize sinusoidal period times

* chore: remove comments

* feat(visualizer): randomize sinusoid amplitudes

* refactor: rename HALF_PERIOD constants to PERIOD

---------

Co-authored-by: Mario <[email protected]>
  • Loading branch information
VmMad and msarcev authored Feb 22, 2024
1 parent 0c162ae commit 3d3bb50
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 28 deletions.
18 changes: 12 additions & 6 deletions client/src/features/visualizer-threejs/Emitter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { RefObject, Dispatch, SetStateAction, useEffect, useRef, useLayou
import * as THREE from "three";
import { useConfigStore, useTangleStore } from "./store";
import { useRenderTangle } from "./useRenderTangle";
import { getTangleDistances, getEmitterPositions, generateRandomPeriods } from "./utils";
import { getTangleDistances, getEmitterPositions, generateRandomPeriods, generateRandomAmplitudes } from "./utils";
import { CanvasElement } from "./enums";
import useVisualizerTimer from "~/helpers/nova/hooks/useVisualizerTimer";
import { EMITTER_DEPTH, EMITTER_HEIGHT, EMITTER_WIDTH } from "./constants";
Expand All @@ -30,15 +30,20 @@ const Emitter: React.FC<EmitterProps> = ({ setRunListeners, emitterRef }: Emitte

const sinusoidPeriodsSum = useConfigStore((state) => state.sinusoidPeriodsSum);
const setSinusoidPeriodsSum = useConfigStore((state) => state.setSinusoidPeriodsSum);
const randomizedSinusoidPeriods = useConfigStore((state) => state.sinusoidRandomPeriods);
const setRandomizedSinusoidPeriods = useConfigStore((state) => state.setSinusoidRandomPeriods);
const sinusoidRandomPeriods = useConfigStore((state) => state.sinusoidRandomPeriods);
const setSinusoidRandomPeriods = useConfigStore((state) => state.setSinusoidRandomPeriods);

const randomSinusoidAmplitudes = useConfigStore((state) => state.randomSinusoidAmplitudes);
const setRandomSinusoidAmplitudes = useConfigStore((state) => state.setRandomSinusoidAmplitudes);

const tangleWrapperRef = useRef<THREE.Mesh | null>(null);

useLayoutEffect(() => {
const { periods, sum: periodsSum } = generateRandomPeriods();
setRandomizedSinusoidPeriods(periods);
const amplitudes = generateRandomAmplitudes();
setSinusoidRandomPeriods(periods);
setSinusoidPeriodsSum(periodsSum);
setRandomSinusoidAmplitudes(amplitudes);
}, []);

useEffect(() => {
Expand All @@ -65,8 +70,9 @@ const Emitter: React.FC<EmitterProps> = ({ setRunListeners, emitterRef }: Emitte
const currentAnimationTime = getVisualizerTimeDiff();
const { x, y } = getEmitterPositions({
currentAnimationTime,
periods: randomizedSinusoidPeriods,
periods: sinusoidRandomPeriods,
periodsSum: sinusoidPeriodsSum,
sinusoidAmplitudes: randomSinusoidAmplitudes,
});

if (isPlaying) {
Expand Down Expand Up @@ -99,7 +105,7 @@ const Emitter: React.FC<EmitterProps> = ({ setRunListeners, emitterRef }: Emitte
{/* Emitter Mesh */}
<mesh ref={emitterRef} name={CanvasElement.EmitterMesh} position={[0, 0, 0]}>
<boxGeometry args={[EMITTER_WIDTH, EMITTER_HEIGHT, EMITTER_DEPTH]} />
<meshPhongMaterial transparent opacity={0} />
<meshPhongMaterial transparent opacity={1} />
</mesh>
</>
);
Expand Down
2 changes: 2 additions & 0 deletions client/src/features/visualizer-threejs/VisualizerInstance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const VisualizerInstance: React.FC<RouteComponentProps<VisualizerRouteProps>> =

const sinusoidPeriodsSum = useConfigStore((s) => s.sinusoidPeriodsSum);
const sinusoidRandomPeriods = useConfigStore((s) => s.sinusoidRandomPeriods);
const sinusoidRandomAmplitudes = useConfigStore((s) => s.randomSinusoidAmplitudes);

const selectedFeedItem: TSelectFeedItemNova = clickedInstanceId ? blockMetadata.get(clickedInstanceId) ?? null : null;
const resetConfigState = useTangleStore((s) => s.resetConfigState);
Expand Down Expand Up @@ -205,6 +206,7 @@ const VisualizerInstance: React.FC<RouteComponentProps<VisualizerRouteProps>> =
currentAnimationTime,
periods: sinusoidRandomPeriods,
periodsSum: sinusoidPeriodsSum,
sinusoidAmplitudes: sinusoidRandomAmplitudes,
});
const targetPosition = getBlockTargetPosition(initPosition, bps);

Expand Down
4 changes: 2 additions & 2 deletions client/src/features/visualizer-threejs/blockPositions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export function getBlockTargetPosition(initPosition: IPos, bps: number): IPos {
return { x, y, z };
}

export function getBlockInitPosition({ currentAnimationTime, periods, periodsSum }: ISinusoidalPositionParams): IPos {
export function getBlockInitPosition({ currentAnimationTime, periods, periodsSum, sinusoidAmplitudes }: ISinusoidalPositionParams): IPos {
const { xTangleDistance } = getTangleDistances();
const { x: xEmitterPos, y, z } = getEmitterPositions({ currentAnimationTime, periods, periodsSum });
const { x: xEmitterPos, y, z } = getEmitterPositions({ currentAnimationTime, periods, periodsSum, sinusoidAmplitudes });
const x = xEmitterPos + xTangleDistance / 2;

return { x, y, z };
Expand Down
9 changes: 4 additions & 5 deletions client/src/features/visualizer-threejs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,11 @@ export const MAX_PREV_POINTS = 20;

export const EMITTER_X_POSITION_MULTIPLIER = 3;

export const MAX_SINUSOIDAL_AMPLITUDE = 200;
export const SINUSOIDAL_AMPLITUDE_ACCUMULATOR = 30;
export const INITIAL_SINUSOIDAL_AMPLITUDE = 80;
export const HALF_WAVE_PERIOD_SECONDS = 5;

/* Values for randomizing the tangle */
export const NUMBER_OF_RANDOM_PERIODS = 100;
export const MIN_SINUSOID_PERIOD = 5;
export const MAX_SINUSOID_PERIOD = 8;

export const NUMBER_OF_RANDOM_AMPLITUDES = 100;
export const MIN_SINUSOID_AMPLITUDE = 100;
export const MAX_SINUSOID_AMPLITUDE = 200;
1 change: 1 addition & 0 deletions client/src/features/visualizer-threejs/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export interface ITimeBasedPositionParams {
export interface ISinusoidalPositionParams extends ITimeBasedPositionParams {
periods: number[];
periodsSum: number;
sinusoidAmplitudes: number[];
}
14 changes: 14 additions & 0 deletions client/src/features/visualizer-threejs/store/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ interface ConfigState {
setSinusoidPeriodsSum: (totalPeriodsSum: number) => void;
sinusoidRandomPeriods: number[];
setSinusoidRandomPeriods: (randomizedPeriods: number[]) => void;

randomSinusoidAmplitudes: number[];
setRandomSinusoidAmplitudes: (randomizedAmplitudes: number[]) => void;
}

export const useConfigStore = create<ConfigState>((set) => ({
Expand Down Expand Up @@ -96,4 +99,15 @@ export const useConfigStore = create<ConfigState>((set) => ({
sinusoidRandomPeriods: randomizedPeriods,
}));
},

/**
* Randomized amplitudes for the tangle.
*/
randomSinusoidAmplitudes: [],
setRandomSinusoidAmplitudes: (randomizedAmplitudes) => {
set((state) => ({
...state,
randomSinusoidAmplitudes: randomizedAmplitudes,
}));
},
}));
67 changes: 52 additions & 15 deletions client/src/features/visualizer-threejs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import {
MAX_POINT_RETRIES,
MAX_BLOCK_INSTANCES,
EMITTER_SPEED_MULTIPLIER,
MAX_SINUSOIDAL_AMPLITUDE,
CAMERA_X_AXIS_MOVEMENT,
CAMERA_Y_AXIS_MOVEMENT,
CAMERA_X_OFFSET,
CAMERA_Y_OFFSET,
SINUSOIDAL_AMPLITUDE_ACCUMULATOR,
INITIAL_SINUSOIDAL_AMPLITUDE,
NUMBER_OF_RANDOM_PERIODS,
MIN_SINUSOID_PERIOD,
MAX_SINUSOID_PERIOD,
NUMBER_OF_RANDOM_AMPLITUDES,
MIN_SINUSOID_AMPLITUDE,
MAX_SINUSOID_AMPLITUDE,
} from "./constants";
import type { ICameraAngles, ISinusoidalPositionParams, IThreeDimensionalPosition } from "./interfaces";

Expand Down Expand Up @@ -193,7 +193,7 @@ export function getTangleDistances(): {
const maxXDistance = MAX_BLOCK_DISTANCE;

/* Max Y Distance will be multiplied by 2 to position blocks in the negative and positive Y axis */
const maxYDistance = MAX_TANGLE_RADIUS * 2 + MAX_SINUSOIDAL_AMPLITUDE * 2;
const maxYDistance = MAX_TANGLE_RADIUS * 2 + MAX_SINUSOID_AMPLITUDE * 2;

/* TODO: add sinusoidal distances */

Expand Down Expand Up @@ -237,16 +237,18 @@ export function getCameraAngles(): ICameraAngles {
* considering random periods.
* @returns the sinusoidal position
*/
export function calculateSinusoidalAmplitude({ currentAnimationTime, periods, periodsSum }: ISinusoidalPositionParams): number {
export function calculateSinusoidalAmplitude({
currentAnimationTime,
periods,
periodsSum,
sinusoidAmplitudes,
}: ISinusoidalPositionParams): number {
const elapsedTime = currentAnimationTime % periodsSum;
const { period, accumulatedTime } = getCurrentPeriodValues(currentAnimationTime, periods, periodsSum);
const { index, period, accumulatedTime } = getCurrentPeriodValues(currentAnimationTime, periods, periodsSum);

const startTimeOfCurrentPeriod = accumulatedTime - period;
const timeInCurrentPeriod = elapsedTime - startTimeOfCurrentPeriod;

const currentWaveCount = Math.floor(elapsedTime / period);
const accumulatedAmplitude = currentWaveCount * SINUSOIDAL_AMPLITUDE_ACCUMULATOR;
const currentAmplitude = Math.min(INITIAL_SINUSOIDAL_AMPLITUDE + accumulatedAmplitude, MAX_SINUSOIDAL_AMPLITUDE);
const currentAmplitude = sinusoidAmplitudes[index];

const yPosition = currentAmplitude * Math.sin((2 * Math.PI * timeInCurrentPeriod) / period);

Expand All @@ -265,9 +267,14 @@ export function calculateEmitterPositionX(currentAnimationTime: number): number
* Calculates the emitter position based on the current animation time.
* @returns the emitter X,Y,Z positions
*/
export function getEmitterPositions({ currentAnimationTime, periods, periodsSum }: ISinusoidalPositionParams): IThreeDimensionalPosition {
export function getEmitterPositions({
currentAnimationTime,
periods,
periodsSum,
sinusoidAmplitudes,
}: ISinusoidalPositionParams): IThreeDimensionalPosition {
const x = calculateEmitterPositionX(currentAnimationTime);
const y = calculateSinusoidalAmplitude({ currentAnimationTime, periods, periodsSum });
const y = calculateSinusoidalAmplitude({ currentAnimationTime, periods, periodsSum, sinusoidAmplitudes });
return { x, y, z: 0 };
}

Expand All @@ -293,18 +300,48 @@ export function generateRandomPeriods(): { periods: number[]; sum: number } {
type PeriodResult = {
period: number;
accumulatedTime: number;
index: number;
};

function getCurrentPeriodValues(animationTime: number, periods: number[], totalSum: number): PeriodResult {
const effectiveTime = animationTime % totalSum;

let accumulatedTime = 0;

for (let i = 0; i < periods.length; i++) {
accumulatedTime += periods[i];
const period = periods[i];
accumulatedTime += period;
if (effectiveTime < accumulatedTime) {
return { period: periods[i], accumulatedTime };
return { index: i, period, accumulatedTime };
}
}

return { period: periods[0], accumulatedTime: 0 };
return { index: 0, period: periods[0], accumulatedTime: 0 };
}

function getNextAmplitudeWithVariation(currentAmplitude: number = 0): number {
const variation = (2 * MIN_SINUSOID_AMPLITUDE) / 3;
const randomAmplitudeVariation = randomNumberFromInterval(-variation, variation);

let newAmplitude = currentAmplitude + randomAmplitudeVariation;

if (newAmplitude > MAX_SINUSOID_AMPLITUDE) {
newAmplitude = currentAmplitude - Math.abs(randomAmplitudeVariation);
} else if (newAmplitude < MIN_SINUSOID_AMPLITUDE) {
newAmplitude = currentAmplitude + Math.abs(randomAmplitudeVariation);
}

newAmplitude = Math.max(MIN_SINUSOID_AMPLITUDE, Math.min(newAmplitude, MAX_SINUSOID_AMPLITUDE));

return newAmplitude;
}

export function generateRandomAmplitudes(): number[] {
const amplitudes: number[] = [];
let currentAmplitude: number = 0;
for (let i = 0; i < NUMBER_OF_RANDOM_AMPLITUDES; i++) {
currentAmplitude = getNextAmplitudeWithVariation(currentAmplitude);
amplitudes.push(currentAmplitude);
}
return amplitudes;
}

0 comments on commit 3d3bb50

Please sign in to comment.