I'm quite a newbie to R3F & Three.js, I am having difficulty including a time value as a variable for a simple shader.
I have a GLSL shader as a JavaScript file and I want to update the time value using uniform u_time
I am trying to pass through the time variable using THREE.Clock in my React ponent. When I console.log the timer inside of my useEffect hook , I get the time console logged as a rounded value as I need it for the shader. However I am not sure how to return this value to use in my shader, as the u_time value. Is there something I am missing in my useEffect hook?
React Component code
import React, { useRef, useEffect, useState } from "react";
import { Canvas, useThree, useFrame } from "@react-three/fiber";
import { vertexShader, fragmentShader } from '../Shaders/Shader';
const ShaderPlane = (props) => {
const [value, setValue] = useState(0);
const mesh = useRef()
const time = new THREE.Clock();
useEffect(() => setInterval(() => setValue(time.getElapsedTime().toFixed(1)), 1000), []);
console.log(value)
return (
<Canvas>
<ambientLight intensity={5} />
<spotLight position={[8, 3, 1]} penumbra={0.3} />
<mesh
{...props}
ref={mesh}
scale={[4,4,4]}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
uniforms={{
u_time: { value: value },
}}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
/>
</mesh>
</Canvas>
)
}
export default ShaderPlane;
Shader.js code
export const vertexShader = `
void main()
{
// v_uv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position * 1.0, 1.0 );
//turning the vec3 into a vec 4 by adding 1.0 to the end
}
`;
export const fragmentShader = `
uniform float u_time;
void main()
{
vec3 color = vec3((sin(u_time) + 1.0)/2.0, 0.0, (cos(u_time) + 1.0)/2.0);
gl_FragColor = vec4(color, 1.0);
}
`;
Appreciate your help :)
I'm quite a newbie to R3F & Three.js, I am having difficulty including a time value as a variable for a simple shader.
I have a GLSL shader as a JavaScript file and I want to update the time value using uniform u_time
I am trying to pass through the time variable using THREE.Clock in my React ponent. When I console.log the timer inside of my useEffect hook , I get the time console logged as a rounded value as I need it for the shader. However I am not sure how to return this value to use in my shader, as the u_time value. Is there something I am missing in my useEffect hook?
React Component code
import React, { useRef, useEffect, useState } from "react";
import { Canvas, useThree, useFrame } from "@react-three/fiber";
import { vertexShader, fragmentShader } from '../Shaders/Shader';
const ShaderPlane = (props) => {
const [value, setValue] = useState(0);
const mesh = useRef()
const time = new THREE.Clock();
useEffect(() => setInterval(() => setValue(time.getElapsedTime().toFixed(1)), 1000), []);
console.log(value)
return (
<Canvas>
<ambientLight intensity={5} />
<spotLight position={[8, 3, 1]} penumbra={0.3} />
<mesh
{...props}
ref={mesh}
scale={[4,4,4]}
>
<planeBufferGeometry attach="geometry" />
<shaderMaterial
uniforms={{
u_time: { value: value },
}}
vertexShader={vertexShader}
fragmentShader={fragmentShader}
/>
</mesh>
</Canvas>
)
}
export default ShaderPlane;
Shader.js code
export const vertexShader = `
void main()
{
// v_uv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position * 1.0, 1.0 );
//turning the vec3 into a vec 4 by adding 1.0 to the end
}
`;
export const fragmentShader = `
uniform float u_time;
void main()
{
vec3 color = vec3((sin(u_time) + 1.0)/2.0, 0.0, (cos(u_time) + 1.0)/2.0);
gl_FragColor = vec4(color, 1.0);
}
`;
Appreciate your help :)
R3F hooks can only be used inside the Canvas element because they rely on context. Just call the useFrame hook inside a ponent.
const Box = (props) => {
const ref = useRef();
useFrame((state) => {
const time = state.clock.getElapsedTime();
time.current += 0.03;
ref.current.rotation.y += 0.01;
ref.current.rotation.x += 0.001;
ref.current.material.uniforms.u_time.value = state.clock.elapsedTime;
});
return (
<mesh ref={ref} {...props}>
<boxGeometry attach="geometry" />
<shaderMat attach="material" />
</mesh>
);
};
Then call your ponent inside the Canvas:
const App = (props) => {
return (
<Canvas>
<ambientLight intensity={5} />
<spotLight position={[8, 3, 1]} penumbra={0.3} />
<Box />
</Canvas>
);
};
Use useFrame hook from react-three-fiber, it has a parameter that will give you access to the system clock