Skip to content

Commit

Permalink
Port ref to shader inside react context to simplify usage of uniform …
Browse files Browse the repository at this point in the history
…hooks
  • Loading branch information
vhiribarren committed Dec 11, 2023
1 parent 11a5c6b commit 447032c
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 104 deletions.
32 changes: 7 additions & 25 deletions src/app/deformation/circle-grid/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"use client";

import fragmentShader from "./fragment.glsl";
import { useEffect, useState } from "react";
import { FragmentLogic, FragmentView } from "@/components/shaders/FragmentView";
import { NumberInput } from "@mantine/core";
import styles from "./page.module.css";
import { useFrame } from "@react-three/fiber";
import { useUniform, useUniformClock } from "@/components/shaders/uniforms";

const UNIFORMS = {
u_frequence: {
Expand All @@ -22,31 +21,14 @@ const UNIFORMS = {
},
};

function CircleGridControl({fragmentRef, controlUiTunnel}: FragmentLogic) {
function CircleGridControl({controlUiTunnel}: FragmentLogic) {

const [frequence, setFrequence] = useState<number | string>(UNIFORMS.u_frequence.value);
const [amplitude, setAmplitude] = useState<number | string>(UNIFORMS.u_amplitude.value);
const [speed, setSpeed] = useState<number | string>(UNIFORMS.u_speed.value);
const ControlUiTunnel = controlUiTunnel;

useEffect(() => {
if (fragmentRef.current?.uniforms) {
const uniforms = fragmentRef.current?.uniforms;
uniforms.u_frequence.value = frequence;
uniforms.u_amplitude.value = amplitude;
uniforms.u_speed.value = speed;
fragmentRef.current.render();
}
}, [frequence, amplitude, speed, fragmentRef]);
useUniformClock("u_time");
const [frequence, setFrequence] = useUniform("u_frequence", UNIFORMS.u_frequence.value);
const [amplitude, setAmplitude] = useUniform("u_amplitude", UNIFORMS.u_amplitude.value);
const [speed, setSpeed] = useUniform("u_speed",UNIFORMS.u_speed.value);

useFrame((state) => {
const { clock } = state;
if (fragmentRef.current?.uniforms) {
fragmentRef.current.uniforms.u_time.value = clock.elapsedTime;
}
});

// TODO: when click, trigger a pulse
const ControlUiTunnel = controlUiTunnel;

return (
<ControlUiTunnel>
Expand Down
8 changes: 4 additions & 4 deletions src/app/deformation/ripple/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ const UNIFORMS = {
function RippleControl({controlUiTunnel}: FragmentLogic) {

useUniformClock("u_time");
const [frequence, setFrequence] = useUniform("u_frequence", 20.0);
const [amplitude, setAmplitude] = useUniform("u_amplitude", 0.1);
const [decrease, setDecrease] = useUniform("u_decrease", 10.0);
const [speed, setSpeed] = useUniform("u_speed", 0.1);
const [frequence, setFrequence] = useUniform("u_frequence", UNIFORMS.u_frequence.value);
const [amplitude, setAmplitude] = useUniform("u_amplitude", UNIFORMS.u_amplitude.value);
const [decrease, setDecrease] = useUniform("u_decrease", UNIFORMS.u_decrease.value);
const [speed, setSpeed] = useUniform("u_speed",UNIFORMS.u_speed.value);

const ControlUiTunnel = controlUiTunnel;

Expand Down
28 changes: 8 additions & 20 deletions src/app/noise/value-noise/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";

import { useEffect, useState } from "react";
import { NumberInput } from "@mantine/core";
import fragmentShader from "./fragment.glsl";
import { FragmentLogic, FragmentView } from "@/components/shaders/FragmentView";
import styles from "./page.module.css";
import { useUniform } from "@/components/shaders/uniforms";

const UNIFORMS = {
u_freq_count: {
Expand All @@ -27,28 +27,16 @@ const UNIFORMS = {
},
};

function ValueNoiseControl({fragmentRef, controlUiTunnel}: FragmentLogic) {
function ValueNoiseControl({controlUiTunnel}: FragmentLogic) {

const [freqCount, setFreqCount] = useState<number | string>(UNIFORMS.u_freq_count.value);
const [freqBase, setFreqBase] = useState<number | string>(UNIFORMS.u_freq_base.value);
const [lacunarity, setLacunarity] = useState<number | string>(UNIFORMS.u_lacunarity.value);
const [gain, setGain] = useState<number | string>(UNIFORMS.u_gain.value);
const [shiftX, setShiftX] = useState<number | string>(UNIFORMS.u_shift_x.value);
const [shiftY, setShiftY] = useState<number | string>(UNIFORMS.u_shift_y.value);
const [freqCount, setFreqCount] = useUniform("u_freq_count", UNIFORMS.u_freq_count.value);
const [freqBase, setFreqBase] = useUniform("u_freq_base", UNIFORMS.u_freq_base.value);
const [lacunarity, setLacunarity] = useUniform("u_lacunarity", UNIFORMS.u_lacunarity.value);
const [gain, setGain] = useUniform("u_gain", UNIFORMS.u_gain.value);
const [shiftX, setShiftX] = useUniform("u_shift_x", UNIFORMS.u_shift_x.value);
const [shiftY, setShiftY] = useUniform("u_shift_y", UNIFORMS.u_shift_y.value);
const ControlUiTunnel = controlUiTunnel;

useEffect(() => {
if (fragmentRef?.current?.uniforms) {
fragmentRef.current.uniforms.u_freq_count.value = freqCount;
fragmentRef.current.uniforms.u_freq_base.value = freqBase;
fragmentRef.current.uniforms.u_lacunarity.value = lacunarity;
fragmentRef.current.uniforms.u_gain.value = gain;
fragmentRef.current.uniforms.u_shift_x.value = shiftX;
fragmentRef.current.uniforms.u_shift_y.value = shiftY;
fragmentRef.current.render();
}
}, [freqCount, freqBase, lacunarity, gain, shiftX, shiftY, fragmentRef]);

return (
<ControlUiTunnel>
<div className={styles.shaderControlWrapper}>
Expand Down
12 changes: 3 additions & 9 deletions src/app/noise/white-noise/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
"use client";

import { useEffect, useState } from "react";
import { Group, NumberInput, Slider, Stack, Text } from "@mantine/core";
import fragmentShader from "./fragment.glsl";
import { FragmentLogic, FragmentView } from "@/components/shaders/FragmentView";
import { useUniform } from "@/components/shaders/uniforms";

const UNIFORMS = {
u_frequence: {
value: 4.0,
},
};

function WhiteNoiseControl({ fragmentRef, controlUiTunnel }: FragmentLogic) {
function WhiteNoiseControl({ controlUiTunnel }: FragmentLogic) {

const [frequence, setFrequence] = useState<number | string>(UNIFORMS.u_frequence.value);
useEffect(() => {
if (fragmentRef.current?.uniforms) {
fragmentRef.current.uniforms.u_frequence.value = frequence;
fragmentRef.current.render();
}
}, [frequence, fragmentRef]);
const [frequence, setFrequence] = useUniform("u_frequence", UNIFORMS.u_frequence.value);
const ControlUiTunnel = controlUiTunnel;

return (
Expand Down
7 changes: 3 additions & 4 deletions src/components/shaders/FragmentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { ActionIcon, Affix, Drawer, Flex, Stack, Text, Title } from "@mantine/core";
import FragmentCanvas from "./FragmentCanvas";
import React, { RefObject, useRef } from "react";
import React, { useRef } from "react";
import Fragment, { FragmentHandle } from "./Fragment";
import { useDisclosure, useViewportSize } from "@mantine/hooks";
import { IconAdjustments } from "@tabler/icons-react";
Expand All @@ -16,7 +16,6 @@ type ChildrenProps = {
};

export type FragmentLogic = {
fragmentRef: RefObject<FragmentHandle>,
controlUiTunnel: React.FC<ChildrenProps>,
};

Expand All @@ -40,7 +39,7 @@ export function FragmentView({
withUi = false, autoRender = false
} : FragmentViewProps) {

const fragmentRef = useRef(null);
const fragmentRef = useRef<FragmentHandle>(null!);
const { width } = useViewportSize();
const drawerTargetRef = useRef<HTMLDivElement>(null);
const isMobile = (width as Pixels) < DESKTOP_THRESHOLD;
Expand Down Expand Up @@ -70,7 +69,7 @@ export function FragmentView({
/>
{Control &&
<UniformsContext.Provider value={fragmentRef}>
<Control controlUiTunnel={ui.In} fragmentRef={fragmentRef} />
<Control controlUiTunnel={ui.In} />
</UniformsContext.Provider>
}
</FragmentCanvas>
Expand Down
13 changes: 4 additions & 9 deletions src/components/shaders/ManagedFragmentShader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useFrame } from "@react-three/fiber";
import { FragmentLogic, FragmentView } from "./FragmentView";
import { FragmentView } from "./FragmentView";
import { useUniformClock } from "./uniforms";

type ManagedFragmentShaderProps = {
fragmentShader: string,
Expand All @@ -16,13 +16,8 @@ const UNIFORMS = {
},
};

function ManagedFragmentShaderControl({fragmentRef}: FragmentLogic) {
useFrame((state) => {
const { clock } = state;
if (fragmentRef.current?.uniforms) {
fragmentRef.current.uniforms.u_time.value = clock.getElapsedTime();
}
});
function ManagedFragmentShaderControl() {
useUniformClock("u_time");
return null;
}

Expand Down
33 changes: 0 additions & 33 deletions src/components/shaders/uniforms.js

This file was deleted.

32 changes: 32 additions & 0 deletions src/components/shaders/uniforms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useFrame } from "@react-three/fiber";
import { Dispatch, MutableRefObject, SetStateAction, createContext, useContext, useEffect, useState } from "react";
import { FragmentHandle } from "./Fragment";

export const UniformsContext = createContext<MutableRefObject<FragmentHandle>>(null!);

export function useFragmentRef(): MutableRefObject<FragmentHandle> {
return useContext(UniformsContext);
}

export function useUniform<S extends string | number>(uniformName: string, defaultValue: S | (() => S)): [S, Dispatch<SetStateAction<string | number>>] {
const fragmentRef = useFragmentRef();
const [uniformState, setUniformState] = useState(defaultValue);
useEffect(() => {
if (fragmentRef?.current?.uniforms) {
fragmentRef.current.uniforms[uniformName] = {value:uniformState};
fragmentRef.current.render();
}
}, [uniformName, uniformState, fragmentRef]);
return [uniformState, setUniformState as Dispatch<SetStateAction<string | number>>];
}

export function useUniformClock(uniformName: string) {
const fragmentRef = useFragmentRef();
useFrame((state) => {
const { clock } = state;
if (fragmentRef?.current?.uniforms) {
fragmentRef.current.uniforms[uniformName] = {value: clock.elapsedTime};
fragmentRef.current.render();
}
});
}

0 comments on commit 447032c

Please sign in to comment.