diff --git a/src/components/NoisyText.js b/src/components/NoisyText.js new file mode 100644 index 0000000..9973a15 --- /dev/null +++ b/src/components/NoisyText.js @@ -0,0 +1,87 @@ +import { FontLoader, MeshStandardMaterial, TextBufferGeometry } from 'three'; +import { watch } from 'vue'; +import Mesh from '../meshes/Mesh.js'; +import TextProps from '../meshes/TextProps.js'; +import snoise2 from '../glsl/snoise2.glsl.js'; + +export default { + extends: Mesh, + props: { + ...TextProps, + color: { + type: [String, Number], + default: 0xffffff, + }, + }, + created() { + // add watchers + const watchProps = [ + 'text', 'size', 'height', 'curveSegments', + 'bevelEnabled', 'bevelThickness', 'bevelSize', 'bevelOffset', 'bevelSegments', + 'align', + ]; + watchProps.forEach(p => { + watch(() => this[p], () => { + if (this.font) this.refreshGeometry(); + }); + }); + + // uniform + this.time = { value: 0 }; + + const loader = new FontLoader(); + loader.load(this.fontSrc, (font) => { + this.font = font; + this.createGeometry(); + this.createMaterial(); + this.initMesh(); + + const startTime = Date.now(); + this.three.onBeforeRender(() => { + this.time.value = (Date.now() - startTime) / 1000; + }); + }); + }, + methods: { + createMaterial() { + this.material = new MeshStandardMaterial({ color: this.color }); + this.material.onBeforeCompile = (shader) => { + shader.uniforms.time = this.time; + shader.vertexShader = ` + uniform float time; + ${snoise2} + ` + shader.vertexShader; + + shader.vertexShader = shader.vertexShader.replace( + '#include ', + ` + vec3 p = vec3(position * 0.01); + p.x += time; + float noise = snoise(p.xy); + vec3 transformed = vec3(position); + transformed.z += noise * 10.0; + ` + ); + this.materialShader = shader; + }; + }, + createGeometry() { + this.geometry = new TextBufferGeometry(this.text, { + font: this.font, + size: this.size, + height: this.height, + depth: this.depth, + curveSegments: this.curveSegments, + bevelEnabled: this.bevelEnabled, + bevelThickness: this.bevelThickness, + bevelSize: this.bevelSize, + bevelOffset: this.bevelOffset, + bevelSegments: this.bevelSegments, + }); + + if (this.align === 'center') { + this.geometry.center(); + } + }, + }, +}; diff --git a/src/components/index.js b/src/components/index.js index d9777c4..cd3f278 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1 +1,5 @@ +export { default as NoisyText } from './NoisyText.js'; + +export { default as Slider1 } from './sliders/Slider1.vue'; + export { default as GLTFViewer } from './viewers/GLTFViewer.vue'; diff --git a/src/components/sliders/Slider1.vue b/src/components/sliders/Slider1.vue index 581a7a2..f72bf70 100644 --- a/src/components/sliders/Slider1.vue +++ b/src/components/sliders/Slider1.vue @@ -11,7 +11,7 @@ import { Object3D } from 'three'; import { gsap, Power4 } from 'gsap'; import { lerp, limit } from '../../tools.js'; import AnimatedPlane from './AnimatedPlane.js'; -import useTextures from './useTextures'; +import useTextures from '../../use/useTextures'; export default { props: { diff --git a/src/glsl/snoise2.glsl.js b/src/glsl/snoise2.glsl.js new file mode 100644 index 0000000..1fa726b --- /dev/null +++ b/src/glsl/snoise2.glsl.js @@ -0,0 +1,67 @@ +export default ` + // + // Description : Array and textureless GLSL 2D simplex noise function. + // Author : Ian McEwan, Ashima Arts. + // Maintainer : ijm + // Lastmod : 20110822 (ijm) + // License : Copyright (C) 2011 Ashima Arts. All rights reserved. + // Distributed under the MIT License. See LICENSE file. + // https://github.com/ashima/webgl-noise + // + + vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec2 mod289(vec2 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec3 permute(vec3 x) { + return mod289(((x*34.0)+1.0)*x); + } + + float snoise(vec2 v) + { + const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 + 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) + -0.577350269189626, // -1.0 + 2.0 * C.x + 0.024390243902439); // 1.0 / 41.0 + // First corner + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + // Other corners + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + // Permutations + i = mod289(i); // Avoid truncation effects in permutation + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + // Gradients: 41 points uniformly over a line, mapped onto a diamond. + // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + // Normalise gradients implicitly by scaling m + // Approximation of: m *= inversesqrt( a0*a0 + h*h ); + m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); + + // Compute final noise value at P + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); + } +`; diff --git a/src/meshes/Mesh.js b/src/meshes/Mesh.js index 2af1be6..88b9a75 100644 --- a/src/meshes/Mesh.js +++ b/src/meshes/Mesh.js @@ -18,9 +18,10 @@ export default { type: Boolean, default: false, }, + // mass: Number, }, mounted() { - if (this.geometry) this.initMesh(); + if (this.geometry && !this.mesh) this.initMesh(); }, unmounted() { if (this.geometry) this.geometry.dispose(); @@ -47,6 +48,12 @@ export default { }); this.scene.add(this.mesh); + + // if (this.three.cannon) { + // this.mesh.mass = this.mass; + // this.three.cannon.addMesh(this.mesh); + // } + this.$emit('ready'); }, refreshGeometry() { diff --git a/src/meshes/Text.js b/src/meshes/Text.js index 5994f08..7448744 100644 --- a/src/meshes/Text.js +++ b/src/meshes/Text.js @@ -1,22 +1,12 @@ import { FontLoader, TextBufferGeometry } from 'three'; -import Mesh from './Mesh.js'; import { watch } from 'vue'; +import Mesh from './Mesh.js'; +import TextProps from './TextProps.js'; export default { extends: Mesh, props: { - text: String, - fontSrc: String, - size: { type: Number, default: 80 }, - height: { type: Number, default: 5 }, - depth: { type: Number, default: 1 }, - curveSegments: { type: Number, default: 12 }, - bevelEnabled: { type: Boolean, default: false }, - bevelThickness: { type: Number, default: 10 }, - bevelSize: { type: Number, default: 8 }, - bevelOffset: { type: Number, default: 0 }, - bevelSegments: { type: Number, default: 5 }, - align: { type: [Boolean, String], default: false }, + ...TextProps, }, created() { // add watchers diff --git a/src/meshes/TextProps.js b/src/meshes/TextProps.js new file mode 100644 index 0000000..104dac7 --- /dev/null +++ b/src/meshes/TextProps.js @@ -0,0 +1,14 @@ +export default { + text: String, + fontSrc: String, + size: { type: Number, default: 80 }, + height: { type: Number, default: 5 }, + depth: { type: Number, default: 1 }, + curveSegments: { type: Number, default: 12 }, + bevelEnabled: { type: Boolean, default: false }, + bevelThickness: { type: Number, default: 10 }, + bevelSize: { type: Number, default: 8 }, + bevelOffset: { type: Number, default: 0 }, + bevelSegments: { type: Number, default: 5 }, + align: { type: [Boolean, String], default: false }, +}; diff --git a/src/components/sliders/useTextures.js b/src/use/useTextures.js similarity index 100% rename from src/components/sliders/useTextures.js rename to src/use/useTextures.js