最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to create water in react-three-fiber - Stack Overflow

programmeradmin1浏览0评论

I want to create 3D scene with water like in this example three.js shader ocean or water but I have to create this in react-three-fiber library. I already searched the internet to find some good working example for this case but without result.

Can I ask for help to figure it out how to implement above examples into react-three-fiber approach?

here is what I have so far for metioned Water ponent:

import React from "react";
import waterNormal from "./waternormals.jpg";
//import { useLoader } from "react-three-fiber";
import * as THREE from "three";

import { Water } from "three/examples/jsm/objects/Water.js";

const WaterObject = () => {
  //const mapNormalWater = useLoader(TextureLoader, waterNormal);

  return (
    <mesh>
      <planeBufferGeometry attach="geometry" args={[100, 100]} />
      <Water
        options={{
          textureWidth: 512,
          textureHeight: 512,
          waterNormals: new THREE.TextureLoader().load(
            waterNormal,
            function (texture) {
              texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            }
          ),
          sunDirection: new THREE.Vector3(),
          sunColor: 0xffffff,
          waterColor: 0x001e0f,
          distortionScale: 3.7,
          // fog: scene.fog !== undefined
        }}
      ></Water>
    </mesh>
  );
};

export default WaterObject ;

I want to create 3D scene with water like in this example three.js shader ocean or water but I have to create this in react-three-fiber library. I already searched the internet to find some good working example for this case but without result.

Can I ask for help to figure it out how to implement above examples into react-three-fiber approach?

here is what I have so far for metioned Water ponent:

import React from "react";
import waterNormal from "./waternormals.jpg";
//import { useLoader } from "react-three-fiber";
import * as THREE from "three";

import { Water } from "three/examples/jsm/objects/Water.js";

const WaterObject = () => {
  //const mapNormalWater = useLoader(TextureLoader, waterNormal);

  return (
    <mesh>
      <planeBufferGeometry attach="geometry" args={[100, 100]} />
      <Water
        options={{
          textureWidth: 512,
          textureHeight: 512,
          waterNormals: new THREE.TextureLoader().load(
            waterNormal,
            function (texture) {
              texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            }
          ),
          sunDirection: new THREE.Vector3(),
          sunColor: 0xffffff,
          waterColor: 0x001e0f,
          distortionScale: 3.7,
          // fog: scene.fog !== undefined
        }}
      ></Water>
    </mesh>
  );
};

export default WaterObject ;

Share Improve this question edited May 19, 2021 at 23:43 DonkeyLuck0 asked May 19, 2021 at 22:55 DonkeyLuck0DonkeyLuck0 1432 silver badges13 bronze badges 7
  • three jsm has a water shader codesandbox.io/s/water-shader-1b40u but it's broken in srgb so colors are terrible – hpalu Commented May 21, 2021 at 20:42
  • 1 ps. i didn't read it right, you already were trying to use the same thing. so, you can't just dump anything into jsx like that. jsx is for ponents (uppercase) and native elements (mesh, material, ...). if you have a third party three class and you want to use it in jsx you must use the extend function, like in the box i posted. – hpalu Commented May 21, 2021 at 22:45
  • did you figure out how to do this? I'm having an issue where it is telling me that Water is not a valid jsx element. @hpalu I looked at another example which uses extend({ Water }); but still haven't figured out what that is actually doing. I asked a similar question here: stackoverflow./questions/70642162/… – timhc22 Commented Jan 10, 2022 at 18:03
  • codesandbox.io/s/… I found this example which explains extend pretty well (and why <Water> bees <water>, but it is still not working :( – timhc22 Commented Jan 10, 2022 at 18:44
  • 1 @timhc22 About Why <Water> is changing to the <water> I think that it is related with Classes (pls someone correct me if I'm wrong). Water is Class (uppercase 1st letter) and you cannot use it as JSX elemnt but when you use extend it makes an instnace of object and can be used as standard JSX element here you can find this ponent github./pmndrs/react-three-fiber/blob/master/packages/fiber/… . The same thing happen when you write custom shader example: codesandbox.io/s/shadermaterials-1g4qq?file=/src/App.js:721-738 – DonkeyLuck0 Commented Jan 12, 2022 at 1:43
 |  Show 2 more ments

2 Answers 2

Reset to default 5

Solved thanks to the hpalu.

Below code to the ponent which can be imported and used in canvas ponent.

import React, { useRef, useMemo } from "react";
import { extend, useThree, useLoader, useFrame } from "@react-three/fiber";
import * as THREE from "three";

import { Water } from "three/examples/jsm/objects/Water.js";

extend({ Water });

function Ocean() {
  const ref = useRef();
  const gl = useThree((state) => state.gl);
  const waterNormals = useLoader(
    THREE.TextureLoader, "https://raw.githubusercontent./mrdoob/three.js/master/examples/textures/waternormals.jpg"
  );


  waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping;
  const geom = useMemo(() => new THREE.PlaneGeometry(30000, 30000), []);
  const config = useMemo(
    () => ({
      textureWidth: 512,
      textureHeight: 512,
      waterNormals,
      sunDirection: new THREE.Vector3(),
      sunColor: 0xeb8934,
      waterColor: 0x0064b5,
      distortionScale: 40,
      fog: false,
      format: gl.encoding,
    }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [waterNormals]
  );
  useFrame(
    (state, delta) => (ref.current.material.uniforms.time.value += delta)
  );
  return (
    <water
      ref={ref}
      args={[geom, config]}
      rotation-x={-Math.PI / 2}
      position={[0, 0, 0]}
    />
  );
}

export default Ocean;

Thanks both! This helped a great deal...

Still had quite some struggles getting this to work with other versions of what have ya, so adding the changes I made in case they could help others:

useFrame((state, delta) => {
    const material = ref?.current?.material as THREE.ShaderMaterial;
    material.uniforms.time.value += delta;
})

to prevent object is possibly 'null' error.

Declared a namespace interface, as the lower case 'water' really doesn't work otherwise:

extend({ Water });
declare global {
namespace JSX {
  interface IntrinsicElements {
    water: Object3DNode<Water, typeof Water>
  }
}
}

... and finally... if your up-vector is the Z-axis, as opposed to the default Y-axis, you get funky results, so beware the rotation of the object.

发布评论

评论列表(0)

  1. 暂无评论