javascript - React-three-fiber useEffect , useState, THREE.Clock - Stack Overflow

admin2025-04-20  0

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 :)

Share Improve this question asked May 16, 2021 at 20:08 ib95ib95 1293 silver badges10 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

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

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745148779a287502.html

最新回复(0)