From 487cb5aa5eabc73aec77768b46d2f0652e4893b5 Mon Sep 17 00:00:00 2001 From: Jure Triglav Date: Wed, 27 Jan 2021 17:03:01 +0100 Subject: [PATCH] BREAKING CHANGE: Upgrade Three.js to r125 (#262) * chore: update Three.js dependency * refactor: remove subdivision modifier * fix: remove use of FaceNormalsHelper as it no longer exists in Three * fix: update typings for THREE * fix: update modifiers to work without THREE.Geometry * docs: update README * chore: add Three.js peer dependency --- .storybook/stories/useEdgeSplit.stories.tsx | 5 ++- .storybook/stories/useHelper.stories.tsx | 2 - .storybook/stories/useSubdivision.stories.tsx | 27 ------------- .../stories/useTessellation.stories.tsx | 8 ++-- README.md | 21 +--------- package.json | 5 ++- src/core/CurveModifier.tsx | 4 +- src/core/index.ts | 1 - src/core/useEdgeSplit.tsx | 16 +++----- src/core/useSimplification.tsx | 8 +--- src/core/useSubdivision.tsx | 40 ------------------- src/core/useTessellation.tsx | 24 ++++------- yarn.lock | 8 ++-- 13 files changed, 32 insertions(+), 137 deletions(-) delete mode 100644 .storybook/stories/useSubdivision.stories.tsx delete mode 100644 src/core/useSubdivision.tsx diff --git a/.storybook/stories/useEdgeSplit.stories.tsx b/.storybook/stories/useEdgeSplit.stories.tsx index 7a3667662..7f9cd785c 100644 --- a/.storybook/stories/useEdgeSplit.stories.tsx +++ b/.storybook/stories/useEdgeSplit.stories.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { useLoader } from 'react-three-fiber' import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader' -import { withKnobs, number } from '@storybook/addon-knobs' +import { withKnobs, number, boolean } from '@storybook/addon-knobs' import { Setup } from '../Setup' @@ -17,8 +17,9 @@ function CerberusModel() { const { children } = useLoader(OBJLoader, 'cerberus.obj') const cutoffEdge = number('Cut Off Edge', 20, { range: true, min: 0, max: 180, step: 1 }) + const tryKeepNormals = boolean('Keep normals', true) - const meshRef = useEdgeSplit(cutoffEdge * (Math.PI / 180)) + const meshRef = useEdgeSplit(cutoffEdge * (Math.PI / 180), tryKeepNormals) return ( diff --git a/.storybook/stories/useHelper.stories.tsx b/.storybook/stories/useHelper.stories.tsx index b3f578120..8c414f476 100644 --- a/.storybook/stories/useHelper.stories.tsx +++ b/.storybook/stories/useHelper.stories.tsx @@ -1,7 +1,6 @@ import * as React from 'react' import { BoxHelper, CameraHelper } from 'three' import { VertexNormalsHelper } from 'three/examples/jsm/helpers/VertexNormalsHelper' -import { FaceNormalsHelper } from 'three/examples/jsm/helpers/FaceNormalsHelper' import { Setup } from '../Setup' @@ -17,7 +16,6 @@ function Scene() { const mesh = React.useRef() useHelper(mesh, BoxHelper, 'royalblue') useHelper(mesh, VertexNormalsHelper, 1, 'red') - useHelper(mesh, FaceNormalsHelper, 1, 'hotpink') return ( diff --git a/.storybook/stories/useSubdivision.stories.tsx b/.storybook/stories/useSubdivision.stories.tsx deleted file mode 100644 index ec823b071..000000000 --- a/.storybook/stories/useSubdivision.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as React from 'react' -import { withKnobs, number } from '@storybook/addon-knobs' - -import { Setup } from '../Setup' - -import { Octahedron, useSubdivision } from '../../src' - -export default { - title: 'Modifiers/useSubdivision', - component: useSubdivision, - decorators: [withKnobs, (storyFn) => {storyFn()}], -} - -function UseSubdivisionScene() { - const meshRef = useSubdivision(number('Subdivisions', 1, { range: true, max: 5, step: 1 })) - - return ( - - - - ) -} - -export const UseSubdivisionSceneSt = () => -UseSubdivisionSceneSt.story = { - name: 'Default', -} diff --git a/.storybook/stories/useTessellation.stories.tsx b/.storybook/stories/useTessellation.stories.tsx index e75951f2b..bd1e314a0 100644 --- a/.storybook/stories/useTessellation.stories.tsx +++ b/.storybook/stories/useTessellation.stories.tsx @@ -15,7 +15,7 @@ export default { const VertexDisplaceMaterial = shaderMaterial( { - amplitude: 1, + amplitude: 1.0, }, ` uniform float amplitude; @@ -60,8 +60,8 @@ declare global { } function UseTessellationScene() { - const passes = number('passes', 3) - const maxEdgeLength = number('maxEdgeLength', 3) + const passes = number('passes', 4) + const maxEdgeLength = number('maxEdgeLength', 0.1) const meshRef = useTessellation(passes, maxEdgeLength) React.useEffect(() => { @@ -86,7 +86,7 @@ function UseTessellationScene() { geometry.setAttribute('displacement', new THREE.BufferAttribute(displacement, 3)) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + }, [meshRef.current && meshRef.current.geometry]) useFrame(({ clock }) => { const { current: mesh } = meshRef diff --git a/README.md b/README.md index 85ac3bd18..82b4b3dce 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,6 @@ The `native` route of the library **does not** export `Html` or `Loader`. There @@ -781,7 +780,7 @@ return ( [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.react-spring.io/?path=/story/modifiers-useedgesplit) -This hook mutates a mesh geometry using [three's Edge Split modifier](https://threejs.org/examples/?q=modifier#webgl_modifier_edgesplit). +This hook mutates a mesh geometry using [three's Edge Split modifier](https://threejs.org/examples/?q=modifier#webgl_modifier_edgesplit). The first parameter is the cut-off angle, and the second parameter is a `tryKeepNormals` flag (default `true`). ```jsx const meshRef = useEdgeSplit(Math.PI / 2) @@ -793,24 +792,6 @@ return ( ) ``` -#### useSubdivision - -[![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.react-spring.io/?path=/story/modifiers-usesubdivision) - -This hook mutates a mesh geometry using [three's Subdivision modifier](https://threejs.org/examples/webgl_modifier_subdivision.html). - -👉 Vertex count is quadrupled for each subdivision. - -```jsx -const meshRef = useSubdivision(4) - -return ( - - - -) -``` - #### useSimplification [![](https://img.shields.io/badge/-storybook-%23ff69b4)](https://drei.react-spring.io/?path=/story/modifiers-usesimplification) diff --git a/package.json b/package.json index 395a26f0a..886c1a372 100644 --- a/package.json +++ b/package.json @@ -112,14 +112,15 @@ "rollup-plugin-multi-input": "^1.1.1", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-size-snapshot": "^0.12.0", - "three": "0.123.0", + "three": "0.125.0", "typescript": "^3.9.7", "use-asset": "^1.0.2" }, "peerDependencies": { "react": ">=16.13", "react-dom": ">=16.13", - "react-three-fiber": ">=5.0" + "react-three-fiber": ">=5.0", + "three": ">=0.125.0" }, "peerDependenciesMeta": { "react-dom": { diff --git a/src/core/CurveModifier.tsx b/src/core/CurveModifier.tsx index 72ba02d41..2a787e50d 100644 --- a/src/core/CurveModifier.tsx +++ b/src/core/CurveModifier.tsx @@ -4,13 +4,13 @@ import { Flow } from 'three/examples/jsm/modifiers/CurveModifier' export interface CurveModifierProps { children: React.ReactElement - curve?: THREE.Curve + curve?: THREE.Curve } export type CurveModifierRef = Pick export const CurveModifier = React.forwardRef(({ children, curve }: CurveModifierProps, ref) => { - const [object3D, setObj] = React.useState() + const [object3D, setObj] = React.useState() const original = React.useRef() const modifier = React.useRef() diff --git a/src/core/index.ts b/src/core/index.ts index 6d351338c..745c0bd4e 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -45,7 +45,6 @@ export * from './useFBO' // Modifiers export * from './useSimplification' -export * from './useSubdivision' export * from './useTessellation' export * from './useEdgeSplit' export * from './CurveModifier' diff --git a/src/core/useEdgeSplit.tsx b/src/core/useEdgeSplit.tsx index 7a3e22620..da817c600 100644 --- a/src/core/useEdgeSplit.tsx +++ b/src/core/useEdgeSplit.tsx @@ -2,9 +2,9 @@ import * as React from 'react' import * as THREE from 'three' import { EdgeSplitModifier } from 'three/examples/jsm/modifiers/EdgeSplitModifier' -export function useEdgeSplit(cutOffAngle: number) { +export function useEdgeSplit(cutOffAngle: number, tryKeepNormals: boolean = true) { const ref = React.useRef() - const original = React.useRef() + const original = React.useRef() const modifier = React.useRef() React.useEffect(() => { @@ -16,20 +16,16 @@ export function useEdgeSplit(cutOffAngle: number) { React.useEffect(() => { if (original.current && ref.current && modifier.current) { - let geometry = new THREE.Geometry() + let geometry = new THREE.BufferGeometry() - if (original.current instanceof THREE.BufferGeometry) { - geometry.fromBufferGeometry(original.current) - } else { - geometry = original.current.clone() - } + geometry = original.current.clone() - const modifiedGeometry = modifier.current.modify(geometry, cutOffAngle) + const modifiedGeometry = modifier.current.modify(geometry, cutOffAngle, tryKeepNormals) modifiedGeometry.computeVertexNormals() ref.current.geometry = modifiedGeometry } - }, [cutOffAngle]) + }, [cutOffAngle, tryKeepNormals]) return ref } diff --git a/src/core/useSimplification.tsx b/src/core/useSimplification.tsx index 3c1e0ff8e..ea9f8aa5f 100644 --- a/src/core/useSimplification.tsx +++ b/src/core/useSimplification.tsx @@ -4,7 +4,7 @@ import { SimplifyModifier } from 'three/examples/jsm/modifiers/SimplifyModifier' export function useSimplification(simplePercent: number) { const ref = React.useRef() - const original = React.useRef() + const original = React.useRef() const modifier = React.useRef() React.useEffect(() => { @@ -18,11 +18,7 @@ export function useSimplification(simplePercent: number) { if (original.current && ref.current) { let geometry = new THREE.BufferGeometry() - if (original.current instanceof THREE.BufferGeometry) { - geometry = original.current.clone() - } else { - geometry = geometry.fromGeometry(original.current) - } + geometry = original.current.clone() const count = Math.floor(geometry.attributes.position.count * simplePercent) // number of vertices to remove ref.current.geometry = modifier.current!.modify(geometry, count) diff --git a/src/core/useSubdivision.tsx b/src/core/useSubdivision.tsx deleted file mode 100644 index b56cb5577..000000000 --- a/src/core/useSubdivision.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from 'react' -import * as THREE from 'three' -import { SubdivisionModifier } from 'three/examples/jsm/modifiers/SubdivisionModifier' - -export function useSubdivision(subdivisions) { - const ref = React.useRef() - const original = React.useRef() - const modifier = React.useRef() - - React.useEffect(() => { - if (!original.current) { - original.current = ref.current!.geometry.clone() - modifier.current = new SubdivisionModifier(parseInt(subdivisions)) - } - }, [subdivisions]) - - React.useEffect(() => { - modifier.current!.subdivisions = subdivisions - }, [subdivisions]) - - React.useEffect(() => { - if (original.current && ref.current) { - let geometry = new THREE.Geometry() - - if (original.current instanceof THREE.BufferGeometry) { - geometry.fromBufferGeometry(original.current) - } else { - geometry = original.current.clone() - } - - const bufferGeometry = new THREE.BufferGeometry() - - const subdivided = bufferGeometry.fromGeometry(modifier.current!.modify(geometry) as THREE.Geometry) - - ref.current.geometry = subdivided - } - }, [subdivisions]) - - return ref -} diff --git a/src/core/useTessellation.tsx b/src/core/useTessellation.tsx index f52163caf..dc96b4505 100644 --- a/src/core/useTessellation.tsx +++ b/src/core/useTessellation.tsx @@ -4,15 +4,15 @@ import { TessellateModifier } from 'three/examples/jsm/modifiers/TessellateModif export function useTessellation(passes = 3, maxEdgeLength) { const ref = React.useRef() - const original = React.useRef() + const original = React.useRef() const modifier = React.useRef() React.useEffect(() => { if (!original.current) { original.current = ref.current!.geometry.clone() - modifier.current = new TessellateModifier(parseInt(maxEdgeLength)) + modifier.current = new TessellateModifier(parseInt(maxEdgeLength), passes) } - }, [maxEdgeLength]) + }, [maxEdgeLength, passes]) React.useEffect(() => { modifier.current!.maxEdgeLength = maxEdgeLength @@ -20,22 +20,12 @@ export function useTessellation(passes = 3, maxEdgeLength) { React.useEffect(() => { if (original.current && ref.current) { - let geometry = new THREE.Geometry() - - if (original.current instanceof THREE.BufferGeometry) { - geometry.fromBufferGeometry(original.current) - } else { - geometry = original.current.clone() - } - - const bufferGeometry = new THREE.BufferGeometry() + let geometry = new THREE.BufferGeometry() - for (let i = 0; i < passes; i++) { - modifier.current!.modify(geometry) - } + geometry = original.current.clone() + geometry = modifier.current!.modify(geometry) - const tessellated = bufferGeometry.fromGeometry(geometry) - ref.current.geometry = tessellated + ref.current.geometry = geometry } }, [maxEdgeLength, passes]) diff --git a/yarn.lock b/yarn.lock index ce8df5ebb..7d46e4de8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11888,10 +11888,10 @@ text-table@0.2.0, text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -three@0.123.0: - version "0.123.0" - resolved "https://registry.yarnpkg.com/three/-/three-0.123.0.tgz#3bb6d8f908a432eb7cd450f7eab6dd40fde53085" - integrity sha512-KNnx/IbilvoHRkxOtL0ouozoDoElyuvAXhFB21RK7F5IPWSmqyFelICK6x3hJerLNSlAdHxR0hkuvMMhH9pqXg== +three@0.125.0: + version "0.125.0" + resolved "https://registry.yarnpkg.com/three/-/three-0.125.0.tgz#19e922b9dc51ad0b706893aeee888de68e99850a" + integrity sha512-qL36qUGsPQ/Ofo/RZdXwHwM7A8wzUSAIyawtjIebJSPvounUQeneSqxI0aBY2iwKpseGy+RUtj3C5f/z4poyXw== throat@^5.0.0: version "5.0.0"