Skip to content

Commit 1b08c0c

Browse files
nartcctran
andauthored
feat: introduce MeshDistortMaterial (#61)
Co-authored-by: ctran <[email protected]>
1 parent 6e3d7b4 commit 1b08c0c

File tree

7 files changed

+167
-2
lines changed

7 files changed

+167
-2
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import * as THREE from 'three'
2+
import { Setup } from '../Setup'
3+
import GUI from 'lil-gui'
4+
import { Meta } from '@storybook/html'
5+
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
6+
import { MeshDistortMaterial } from '../../src/materials/MeshDistortMaterial'
7+
8+
export default {
9+
title: 'Shaders/MeshDistortMaterial',
10+
} as Meta // TODO: this should be `satisfies Meta` but commit hooks lag behind TS
11+
12+
let gui: GUI, materialGuiFolder: GUI
13+
let scene: THREE.Scene,
14+
camera: THREE.PerspectiveCamera,
15+
renderer: THREE.WebGLRenderer,
16+
animateLoop: (arg0: (time: number) => void) => void,
17+
meshDistortMaterial: MeshDistortMaterial
18+
19+
export const MDMStory = async () => {
20+
const setupResult = Setup()
21+
scene = setupResult.scene
22+
camera = setupResult.camera
23+
renderer = setupResult.renderer
24+
animateLoop = setupResult.render
25+
26+
gui = new GUI({ title: MDMStory.storyName })
27+
camera.position.set(0, 0, 5)
28+
29+
const controls = new OrbitControls(camera, renderer.domElement)
30+
controls.update()
31+
32+
const ambientLight = new THREE.AmbientLight()
33+
scene.add(ambientLight)
34+
35+
const dirLight = new THREE.DirectionalLight(0xabcdef, 10)
36+
dirLight.position.set(1, 20, 1)
37+
dirLight.castShadow = true
38+
dirLight.shadow.mapSize.width = 1024
39+
dirLight.shadow.mapSize.height = 1024
40+
scene.add(dirLight)
41+
42+
setupMeshDistortMaterial()
43+
}
44+
45+
async function setupMeshDistortMaterial() {
46+
const geometry = new THREE.SphereGeometry(1, 32, 32)
47+
meshDistortMaterial = new MeshDistortMaterial({ color: '#f25042' })
48+
49+
meshDistortMaterial._radius.value = 0.2
50+
51+
const mesh = new THREE.Mesh(geometry, meshDistortMaterial)
52+
mesh.scale.set(2, 4, 1)
53+
54+
scene.add(mesh)
55+
56+
createMeshDistortGUI()
57+
58+
animateLoop((time) => {
59+
meshDistortMaterial.time = time * 0.0025
60+
meshDistortMaterial.distort = THREE.MathUtils.lerp(meshDistortMaterial.distort, 0.4, 0.05)
61+
})
62+
}
63+
64+
/**
65+
* Create gui for material properties
66+
*/
67+
function createMeshDistortGUI() {
68+
if (materialGuiFolder) {
69+
materialGuiFolder.destroy()
70+
}
71+
72+
const matProps = gui.addFolder('MeshDistortMaterial id: ' + meshDistortMaterial.id)
73+
74+
matProps.addColor(meshDistortMaterial, 'color')
75+
matProps.add(meshDistortMaterial._radius, 'value').min(0.01).max(0.5).step(0.01).name('radius')
76+
77+
materialGuiFolder = matProps
78+
}
79+
80+
MDMStory.storyName = 'Sphere'

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { pcss, ... } from '@pmndrs/vanilla'
4242
<li><a href="#meshreflectormaterial">MeshReflectorMaterial</a></li>
4343
<li><a href="#shadermaterial">shaderMaterial</a></li>
4444
<li><a href="#discardmaterial">MeshDiscardMaterial</a></li>
45+
<li><a href="#meshdistortmaterial">MeshDistortMaterial</a></li>
4546
<li><a href="#meshtransmissionmaterial">MeshTransmissionMaterial</a></li>
4647
<li><a href="#spotlight">SpotLight</a></li>
4748
</ul>
@@ -182,6 +183,16 @@ A material that discards fragments. It can be used to render nothing efficiently
182183
const mesh = new THREE.Mesh(geometry, new MeshDiscardMaterial())
183184
```
184185

186+
#### MeshDistortMaterial
187+
188+
[![storybook](https://img.shields.io/badge/-storybook-%23ff69b4)](https://pmndrs.github.io/drei-vanilla/?path=/story/shaders-meshtransmissionmaterial--mdm-story)
189+
190+
<p>
191+
<a href="https://codesandbox.io/s/l03yb"><img width="20%" src="https://codesandbox.io/api/v1/sandboxes/l03yb/screenshot.png" alt="Demo"/></a>
192+
</p>
193+
194+
This material makes your geometry distort following simplex noise.
195+
185196
#### MeshTransmissionMaterial
186197

187198
[![storybook](https://img.shields.io/badge/-storybook-%23ff69b4)](https://pmndrs.github.io/drei-vanilla/?path=/story/shaders-meshtransmissionmaterial--mtm-story)

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"build-storybook": "build-storybook"
6060
},
6161
"dependencies": {
62+
"glsl-noise": "^0.0.0",
6263
"troika-three-text": "0.47.2"
6364
},
6465
"devDependencies": {
@@ -102,6 +103,7 @@
102103
"lil-gui": "^0.19.1",
103104
"prettier": "^2.4.1",
104105
"pretty-quick": "^3.1.0",
106+
"raw-loader": "^4.0.2",
105107
"react": "^18.0.0",
106108
"react-dom": "^18.0.0",
107109
"rimraf": "^3.0.2",
@@ -118,5 +120,6 @@
118120
},
119121
"peerDependencies": {
120122
"three": ">=0.137"
121-
}
123+
},
124+
"packageManager": "[email protected]"
122125
}

src/helpers/glsl/distort.vert.glsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#pragma glslify: snoise3 = require(glsl-noise/simplex/3d)

src/materials/MeshDistortMaterial.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { IUniform, MeshPhysicalMaterial, MeshPhysicalMaterialParameters } from 'three'
2+
// @ts-ignore
3+
import distort from '../helpers/glsl/distort.vert.glsl'
4+
5+
export class MeshDistortMaterial extends MeshPhysicalMaterial {
6+
_time: IUniform<number>
7+
_distort: IUniform<number>
8+
_radius: IUniform<number>
9+
10+
constructor(parameters: MeshPhysicalMaterialParameters = {}) {
11+
super(parameters)
12+
this.setValues(parameters)
13+
this._time = { value: 0 }
14+
this._distort = { value: 0.4 }
15+
this._radius = { value: 1 }
16+
}
17+
18+
// FIXME Use `THREE.WebGLProgramParametersWithUniforms` type when able to target @types/[email protected]
19+
onBeforeCompile(shader: { vertexShader: string; uniforms: { [uniform: string]: IUniform } }) {
20+
shader.uniforms.time = this._time
21+
shader.uniforms.radius = this._radius
22+
shader.uniforms.distort = this._distort
23+
24+
shader.vertexShader = `
25+
uniform float time;
26+
uniform float radius;
27+
uniform float distort;
28+
${distort}
29+
${shader.vertexShader}
30+
`
31+
shader.vertexShader = shader.vertexShader.replace(
32+
'#include <begin_vertex>',
33+
`
34+
float updateTime = time / 50.0;
35+
float noise = snoise(vec3(position / 2.0 + updateTime * 5.0));
36+
vec3 transformed = vec3(position * (noise * pow(distort, 2.0) + radius));
37+
`
38+
)
39+
}
40+
41+
get time() {
42+
return this._time.value
43+
}
44+
45+
set time(v) {
46+
this._time.value = v
47+
}
48+
49+
get distort() {
50+
return this._distort.value
51+
}
52+
53+
set distort(v) {
54+
this._distort.value = v
55+
}
56+
57+
get radius() {
58+
return this._radius.value
59+
}
60+
61+
set radius(v) {
62+
this._radius.value = v
63+
}
64+
}

src/materials/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './SpotLightMaterial'
44
export * from './BlurPass'
55
export * from './ConvolutionMaterial'
66
export * from './MeshReflectorMaterial'
7+
export * from './MeshDistortMaterial'

yarn.lock

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7606,6 +7606,11 @@ glsl-inject-defines@^1.0.1:
76067606
glsl-token-string "^1.0.1"
76077607
glsl-tokenizer "^2.0.2"
76087608

7609+
glsl-noise@^0.0.0:
7610+
version "0.0.0"
7611+
resolved "https://registry.yarnpkg.com/glsl-noise/-/glsl-noise-0.0.0.tgz#367745f3a33382c0eeec4cb54b7e99cfc1d7670b"
7612+
integrity sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==
7613+
76097614
76107615
version "0.0.1"
76117616
resolved "https://registry.npmjs.org/glsl-resolve/-/glsl-resolve-0.0.1.tgz"
@@ -12115,7 +12120,7 @@ [email protected]:
1211512120

1211612121
raw-loader@^4.0.2:
1211712122
version "4.0.2"
12118-
resolved "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz"
12123+
resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6"
1211912124
integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==
1212012125
dependencies:
1212112126
loader-utils "^2.0.0"

0 commit comments

Comments
 (0)