mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
cs
This commit is contained in:
parent
6f64c8b859
commit
d15b90e4b2
@ -8,7 +8,6 @@ import {
|
||||
ShaderMaterial,
|
||||
Uniform,
|
||||
Vector2,
|
||||
WebGLRenderer,
|
||||
WebGLRenderTarget,
|
||||
} from 'three'
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { defineComponent, watch } from 'vue';
|
||||
import { DoubleSide, Mesh, MeshStandardMaterial, PlaneGeometry } from 'three';
|
||||
import Object3D from '../../core/Object3D';
|
||||
import { bindProps } from '../../tools';
|
||||
import LiquidEffect from './LiquidEffect.js';
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { DoubleSide, Mesh, MeshStandardMaterial, PlaneGeometry } from 'three'
|
||||
import Object3D from '../../core/Object3D'
|
||||
import { bindProps } from '../../tools'
|
||||
import LiquidEffect from './LiquidEffect.js'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Object3D,
|
||||
@ -16,39 +16,40 @@ export default defineComponent({
|
||||
roughness: { type: Number, default: 0.25 },
|
||||
},
|
||||
mounted() {
|
||||
this.liquidEffect = new LiquidEffect(this.renderer.renderer);
|
||||
this.liquidEffect = new LiquidEffect(this.renderer.renderer)
|
||||
this.renderer.onMounted(() => {
|
||||
this.liquidEffect.renderer = this.renderer.renderer;
|
||||
this.renderer.onBeforeRender(this.update);
|
||||
});
|
||||
this.liquidEffect.renderer = this.renderer.renderer
|
||||
this.renderer.onBeforeRender(this.update)
|
||||
})
|
||||
|
||||
this.material = new MeshStandardMaterial({ color: this.color, side: DoubleSide, metalness: this.metalness, roughness: this.roughness,
|
||||
this.material = new MeshStandardMaterial({
|
||||
color: this.color, side: DoubleSide, metalness: this.metalness, roughness: this.roughness,
|
||||
onBeforeCompile: shader => {
|
||||
shader.uniforms.hmap = { value: this.liquidEffect.hMap.texture };
|
||||
shader.vertexShader = "uniform sampler2D hmap;\n" + shader.vertexShader;
|
||||
const token = '#include <begin_vertex>';
|
||||
shader.uniforms.hmap = { value: this.liquidEffect.hMap.texture }
|
||||
shader.vertexShader = "uniform sampler2D hmap;\n" + shader.vertexShader
|
||||
const token = '#include <begin_vertex>'
|
||||
const customTransform = `
|
||||
vec3 transformed = vec3(position);
|
||||
vec4 info = texture2D(hmap, uv);
|
||||
vNormal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a).xzy;
|
||||
transformed.z = 20. * info.r;
|
||||
`;
|
||||
shader.vertexShader = shader.vertexShader.replace(token, customTransform);
|
||||
`
|
||||
shader.vertexShader = shader.vertexShader.replace(token, customTransform)
|
||||
},
|
||||
});
|
||||
bindProps(this, ['metalness', 'roughness'], this.material);
|
||||
watch(() => this.color, (value) => this.material.color.set(value));
|
||||
})
|
||||
bindProps(this, ['metalness', 'roughness'], this.material)
|
||||
watch(() => this.color, (value) => this.material.color.set(value))
|
||||
|
||||
this.geometry = new PlaneGeometry(this.width, this.height, this.widthSegments, this.heightSegments);
|
||||
this.mesh = new Mesh(this.geometry, this.material);
|
||||
this.initObject3D(this.mesh);
|
||||
this.geometry = new PlaneGeometry(this.width, this.height, this.widthSegments, this.heightSegments)
|
||||
this.mesh = new Mesh(this.geometry, this.material)
|
||||
this.initObject3D(this.mesh)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.update);
|
||||
this.renderer.offBeforeRender(this.update)
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.liquidEffect.update();
|
||||
this.liquidEffect.update()
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent } from 'vue'
|
||||
import {
|
||||
BackSide,
|
||||
CubeCamera,
|
||||
@ -7,9 +7,9 @@ import {
|
||||
Mesh as TMesh,
|
||||
RGBFormat,
|
||||
WebGLCubeRenderTarget,
|
||||
} from 'three';
|
||||
import Mesh from '../../meshes/Mesh';
|
||||
import { bindProp } from '../../tools';
|
||||
} from 'three'
|
||||
import Mesh from '../../meshes/Mesh'
|
||||
import { bindProp } from '../../tools'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Mesh,
|
||||
@ -20,54 +20,54 @@ export default defineComponent({
|
||||
autoUpdate: Boolean,
|
||||
},
|
||||
mounted() {
|
||||
this.initGem();
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT);
|
||||
else this.renderer.onMounted(this.updateCubeRT);
|
||||
this.initGem()
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT)
|
||||
else this.renderer.onMounted(this.updateCubeRT)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.updateCubeRT);
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera);
|
||||
if (this.meshBack) this.removeFromParent(this.meshBack);
|
||||
if (this.materialBack) this.materialBack.dispose();
|
||||
this.renderer.offBeforeRender(this.updateCubeRT)
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera)
|
||||
if (this.meshBack) this.removeFromParent(this.meshBack)
|
||||
if (this.materialBack) this.materialBack.dispose()
|
||||
},
|
||||
methods: {
|
||||
initGem() {
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter });
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT);
|
||||
bindProp(this, 'position', this.cubeCamera);
|
||||
this.addToParent(this.cubeCamera);
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter })
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT)
|
||||
bindProp(this, 'position', this.cubeCamera)
|
||||
this.addToParent(this.cubeCamera)
|
||||
|
||||
this.material.side = FrontSide;
|
||||
this.material.envMap = cubeRT.texture;
|
||||
this.material.envMapIntensity = 10;
|
||||
this.material.metalness = 0;
|
||||
this.material.roughness = 0;
|
||||
this.material.opacity = 0.75;
|
||||
this.material.transparent = true;
|
||||
this.material.premultipliedAlpha = true;
|
||||
this.material.needsUpdate = true;
|
||||
this.material.side = FrontSide
|
||||
this.material.envMap = cubeRT.texture
|
||||
this.material.envMapIntensity = 10
|
||||
this.material.metalness = 0
|
||||
this.material.roughness = 0
|
||||
this.material.opacity = 0.75
|
||||
this.material.transparent = true
|
||||
this.material.premultipliedAlpha = true
|
||||
this.material.needsUpdate = true
|
||||
|
||||
this.materialBack = this.material.clone();
|
||||
this.materialBack.side = BackSide;
|
||||
this.materialBack.envMapIntensity = 5;
|
||||
this.materialBack.metalness = 1;
|
||||
this.materialBack.roughness = 0;
|
||||
this.materialBack.opacity = 0.5;
|
||||
this.materialBack = this.material.clone()
|
||||
this.materialBack.side = BackSide
|
||||
this.materialBack.envMapIntensity = 5
|
||||
this.materialBack.metalness = 1
|
||||
this.materialBack.roughness = 0
|
||||
this.materialBack.opacity = 0.5
|
||||
|
||||
this.meshBack = new TMesh(this.geometry, this.materialBack);
|
||||
this.meshBack = new TMesh(this.geometry, this.materialBack)
|
||||
|
||||
bindProp(this, 'position', this.meshBack);
|
||||
bindProp(this, 'rotation', this.meshBack);
|
||||
bindProp(this, 'scale', this.meshBack);
|
||||
this.addToParent(this.meshBack);
|
||||
bindProp(this, 'position', this.meshBack)
|
||||
bindProp(this, 'rotation', this.meshBack)
|
||||
bindProp(this, 'scale', this.meshBack)
|
||||
this.addToParent(this.meshBack)
|
||||
},
|
||||
updateCubeRT() {
|
||||
this.mesh.visible = false;
|
||||
this.meshBack.visible = false;
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||
this.mesh.visible = true;
|
||||
this.meshBack.visible = true;
|
||||
this.mesh.visible = false
|
||||
this.meshBack.visible = false
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene)
|
||||
this.mesh.visible = true
|
||||
this.meshBack.visible = true
|
||||
},
|
||||
},
|
||||
__hmrId: 'Gem',
|
||||
});
|
||||
})
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent } from 'vue'
|
||||
import {
|
||||
CubeCamera,
|
||||
LinearMipmapLinearFilter,
|
||||
RGBFormat,
|
||||
WebGLCubeRenderTarget,
|
||||
} from 'three';
|
||||
import Mesh from '../../meshes/Mesh';
|
||||
} from 'three'
|
||||
import Mesh from '../../meshes/Mesh'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Mesh,
|
||||
@ -16,28 +16,28 @@ export default defineComponent({
|
||||
autoUpdate: Boolean,
|
||||
},
|
||||
mounted() {
|
||||
this.initMirrorMesh();
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT);
|
||||
else this.renderer.onMounted(this.updateCubeRT);
|
||||
this.initMirrorMesh()
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT)
|
||||
else this.renderer.onMounted(this.updateCubeRT)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.updateCubeRT);
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera);
|
||||
this.renderer.offBeforeRender(this.updateCubeRT)
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera)
|
||||
},
|
||||
methods: {
|
||||
initMirrorMesh() {
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter });
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT);
|
||||
this.addToParent(this.cubeCamera);
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter })
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT)
|
||||
this.addToParent(this.cubeCamera)
|
||||
|
||||
this.material.envMap = cubeRT.texture;
|
||||
this.material.needsUpdate = true;
|
||||
this.material.envMap = cubeRT.texture
|
||||
this.material.needsUpdate = true
|
||||
},
|
||||
updateCubeRT() {
|
||||
this.mesh.visible = false;
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||
this.mesh.visible = true;
|
||||
this.mesh.visible = false
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene)
|
||||
this.mesh.visible = true
|
||||
},
|
||||
},
|
||||
__hmrId: 'MirrorMesh',
|
||||
});
|
||||
})
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent } from 'vue'
|
||||
import {
|
||||
CubeCamera,
|
||||
CubeRefractionMapping,
|
||||
LinearMipmapLinearFilter,
|
||||
RGBFormat,
|
||||
WebGLCubeRenderTarget,
|
||||
} from 'three';
|
||||
import Mesh from '../../meshes/Mesh';
|
||||
import { bindProp } from '../../tools';
|
||||
} from 'three'
|
||||
import Mesh from '../../meshes/Mesh'
|
||||
import { bindProp } from '../../tools'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Mesh,
|
||||
@ -19,30 +19,30 @@ export default defineComponent({
|
||||
autoUpdate: Boolean,
|
||||
},
|
||||
mounted() {
|
||||
this.initMirrorMesh();
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT);
|
||||
else this.renderer.onMounted(this.updateCubeRT);
|
||||
this.initMirrorMesh()
|
||||
if (this.autoUpdate) this.renderer.onBeforeRender(this.updateCubeRT)
|
||||
else this.renderer.onMounted(this.updateCubeRT)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.updateCubeRT);
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera);
|
||||
this.renderer.offBeforeRender(this.updateCubeRT)
|
||||
if (this.cubeCamera) this.removeFromParent(this.cubeCamera)
|
||||
},
|
||||
methods: {
|
||||
initMirrorMesh() {
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { mapping: CubeRefractionMapping, format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter });
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT);
|
||||
bindProp(this, 'position', this.cubeCamera);
|
||||
this.addToParent(this.cubeCamera);
|
||||
const cubeRT = new WebGLCubeRenderTarget(this.cubeRTSize, { mapping: CubeRefractionMapping, format: RGBFormat, generateMipmaps: true, minFilter: LinearMipmapLinearFilter })
|
||||
this.cubeCamera = new CubeCamera(this.cubeCameraNear, this.cubeCameraFar, cubeRT)
|
||||
bindProp(this, 'position', this.cubeCamera)
|
||||
this.addToParent(this.cubeCamera)
|
||||
|
||||
this.material.envMap = cubeRT.texture;
|
||||
this.material.refractionRatio = this.refractionRatio;
|
||||
this.material.needsUpdate = true;
|
||||
this.material.envMap = cubeRT.texture
|
||||
this.material.refractionRatio = this.refractionRatio
|
||||
this.material.needsUpdate = true
|
||||
},
|
||||
updateCubeRT() {
|
||||
this.mesh.visible = false;
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene);
|
||||
this.mesh.visible = true;
|
||||
this.mesh.visible = false
|
||||
this.cubeCamera.update(this.renderer.renderer, this.scene)
|
||||
this.mesh.visible = true
|
||||
},
|
||||
},
|
||||
__hmrId: 'RefractionMesh',
|
||||
});
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Stats from 'stats.js';
|
||||
import Stats from 'stats.js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@ -7,40 +7,40 @@ export default {
|
||||
emits: ['created'],
|
||||
inject: ['renderer'],
|
||||
setup({ noSetup }) {
|
||||
const stats = new Stats();
|
||||
const stats = new Stats()
|
||||
if (!noSetup) {
|
||||
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
|
||||
document.body.appendChild(stats.dom);
|
||||
stats.showPanel(0) // 0: fps, 1: ms, 2: mb, 3+: custom
|
||||
document.body.appendChild(stats.dom)
|
||||
}
|
||||
return { stats };
|
||||
return { stats }
|
||||
},
|
||||
mounted() {
|
||||
if (!this.noSetup) {
|
||||
this.renderer.onBeforeRender(this.begin);
|
||||
this.renderer.onAfterRender(this.end);
|
||||
this.renderer.onBeforeRender(this.begin)
|
||||
this.renderer.onAfterRender(this.end)
|
||||
}
|
||||
this.$emit('created', { stats: this.stats });
|
||||
this.$emit('created', { stats: this.stats })
|
||||
},
|
||||
methods: {
|
||||
begin() {
|
||||
if (this.stats) {
|
||||
this.stats.begin();
|
||||
this.stats.begin()
|
||||
}
|
||||
},
|
||||
end() {
|
||||
if (this.stats) {
|
||||
this.stats.end();
|
||||
this.stats.end()
|
||||
}
|
||||
},
|
||||
},
|
||||
unmounted() {
|
||||
if (this.stats && this.stats.dom) {
|
||||
this.stats.dom.parentElement.removeChild(this.stats.dom);
|
||||
this.stats.dom.parentElement.removeChild(this.stats.dom)
|
||||
}
|
||||
this.renderer.offBeforeRender(this.begin);
|
||||
this.renderer.offAfterRender(this.end);
|
||||
this.renderer.offBeforeRender(this.begin)
|
||||
this.renderer.offAfterRender(this.end)
|
||||
},
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default() : [];
|
||||
return this.$slots.default ? this.$slots.default() : []
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -14,57 +14,57 @@ export default {
|
||||
error: '',
|
||||
xrSupport: false,
|
||||
currentSession: null,
|
||||
};
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
message() {
|
||||
if (this.xrSupport) {
|
||||
return this.currentSession ? this.exitMessage : this.enterMessage;
|
||||
return this.currentSession ? this.exitMessage : this.enterMessage
|
||||
} else if (this.error) {
|
||||
return this.error;
|
||||
return this.error
|
||||
}
|
||||
return '';
|
||||
return ''
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if ('xr' in navigator) {
|
||||
navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
|
||||
this.xrSupport = supported;
|
||||
});
|
||||
this.xrSupport = supported
|
||||
})
|
||||
} else {
|
||||
if (window.isSecureContext === false) {
|
||||
this.error = 'WEBXR NEEDS HTTPS';
|
||||
this.error = 'WEBXR NEEDS HTTPS'
|
||||
} else {
|
||||
this.error = 'WEBXR NOT AVAILABLE';
|
||||
this.error = 'WEBXR NOT AVAILABLE'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init(renderer) {
|
||||
this.renderer = renderer;
|
||||
this.renderer = renderer
|
||||
},
|
||||
onClick() {
|
||||
if (!this.xrSupport) return;
|
||||
if (!this.renderer) return;
|
||||
if (!this.xrSupport) return
|
||||
if (!this.renderer) return
|
||||
|
||||
if (this.currentSession) {
|
||||
this.currentSession.end();
|
||||
this.currentSession.end()
|
||||
} else {
|
||||
const sessionInit = { optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking'] };
|
||||
navigator.xr.requestSession('immersive-vr', sessionInit).then(this.onSessionStarted);
|
||||
const sessionInit = { optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking'] }
|
||||
navigator.xr.requestSession('immersive-vr', sessionInit).then(this.onSessionStarted)
|
||||
}
|
||||
},
|
||||
async onSessionStarted(session) {
|
||||
session.addEventListener('end', this.onSessionEnded);
|
||||
await this.renderer.xr.setSession(session);
|
||||
this.currentSession = session;
|
||||
session.addEventListener('end', this.onSessionEnded)
|
||||
await this.renderer.xr.setSession(session)
|
||||
this.currentSession = session
|
||||
},
|
||||
onSessionEnded() {
|
||||
this.currentSession.removeEventListener('end', this.onSessionEnded);
|
||||
this.currentSession = null;
|
||||
this.currentSession.removeEventListener('end', this.onSessionEnded)
|
||||
this.currentSession = null
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { DoubleSide, MeshBasicMaterial, PlaneGeometry } from 'three'
|
||||
import Image from '../../meshes/Image'
|
||||
import snoise2 from '../../glsl/snoise2.glsl.js'
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { defineComponent, watch } from 'vue';
|
||||
import { ObjectSpaceNormalMap, ShaderMaterial, Vector2, WebGLRenderTarget } from 'three';
|
||||
import { Pass } from 'three/examples/jsm/postprocessing/Pass.js';
|
||||
import Plane from '../../meshes/Plane';
|
||||
import snoise3 from '../../glsl/snoise3.glsl.js';
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import { ObjectSpaceNormalMap, ShaderMaterial, Vector2, WebGLRenderTarget } from 'three'
|
||||
import { Pass } from 'three/examples/jsm/postprocessing/Pass.js'
|
||||
import Plane from '../../meshes/Plane'
|
||||
import snoise3 from '../../glsl/snoise3.glsl.js'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Plane,
|
||||
@ -14,38 +14,38 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
// uniforms
|
||||
const uTime = { value: 0 };
|
||||
const uNoiseCoef = { value: props.noiseCoef };
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value; });
|
||||
const uDelta = { value: new Vector2(props.deltaCoef, props.deltaCoef) };
|
||||
watch(() => props.deltaCoef, (value) => { uDelta.value.set(value, value); });
|
||||
const uTime = { value: 0 }
|
||||
const uNoiseCoef = { value: props.noiseCoef }
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value })
|
||||
const uDelta = { value: new Vector2(props.deltaCoef, props.deltaCoef) }
|
||||
watch(() => props.deltaCoef, (value) => { uDelta.value.set(value, value) })
|
||||
|
||||
return {
|
||||
uTime, uNoiseCoef, uDelta,
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
this.init()
|
||||
|
||||
watch(() => this.displacementScale, (value) => { this.material.displacementScale = value; });
|
||||
watch(() => this.displacementScale, (value) => { this.material.displacementScale = value })
|
||||
|
||||
this.startTime = Date.now();
|
||||
this.renderer.onBeforeRender(this.update);
|
||||
this.startTime = Date.now()
|
||||
this.renderer.onBeforeRender(this.update)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.update);
|
||||
this.fsQuad.dispose();
|
||||
this.dispRT.dispose();
|
||||
this.dispMat.dispose();
|
||||
this.normRT.dispose();
|
||||
this.normMat.dispose();
|
||||
this.renderer.offBeforeRender(this.update)
|
||||
this.fsQuad.dispose()
|
||||
this.dispRT.dispose()
|
||||
this.dispMat.dispose()
|
||||
this.normRT.dispose()
|
||||
this.normMat.dispose()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.fsQuad = new Pass.FullScreenQuad();
|
||||
this.fsQuad = new Pass.FullScreenQuad()
|
||||
|
||||
// displacement map
|
||||
this.dispRT = new WebGLRenderTarget(512, 512, { depthBuffer: false, stencilBuffer: false });
|
||||
this.dispRT = new WebGLRenderTarget(512, 512, { depthBuffer: false, stencilBuffer: false })
|
||||
this.dispMat = new ShaderMaterial({
|
||||
uniforms: {
|
||||
uTime: this.uTime,
|
||||
@ -70,10 +70,10 @@ export default defineComponent({
|
||||
gl_FragColor = vec4(noise, 0.0, 0.0, 1.0);
|
||||
}
|
||||
`,
|
||||
});
|
||||
})
|
||||
|
||||
// normal map
|
||||
this.normRT = new WebGLRenderTarget(512, 512, { depthBuffer: false, stencilBuffer: false });
|
||||
this.normRT = new WebGLRenderTarget(512, 512, { depthBuffer: false, stencilBuffer: false })
|
||||
this.normMat = new ShaderMaterial({
|
||||
uniforms: {
|
||||
dispMap: { value: this.dispRT.texture },
|
||||
@ -100,30 +100,30 @@ export default defineComponent({
|
||||
gl_FragColor = vec4(0.5 + (x1 - x2), 0.5 + (y1 - y2), 1.0, 1.0);
|
||||
}
|
||||
`,
|
||||
});
|
||||
})
|
||||
|
||||
this.material.displacementMap = this.dispRT.texture;
|
||||
this.material.displacementScale = this.displacementScale;
|
||||
this.material.normalMap = this.normRT.texture;
|
||||
this.material.normalMapType = ObjectSpaceNormalMap;
|
||||
this.material.displacementMap = this.dispRT.texture
|
||||
this.material.displacementScale = this.displacementScale
|
||||
this.material.normalMap = this.normRT.texture
|
||||
this.material.normalMapType = ObjectSpaceNormalMap
|
||||
// this.material.needsUpdate = true;
|
||||
},
|
||||
update() {
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef;
|
||||
this.renderDisp();
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef
|
||||
this.renderDisp()
|
||||
},
|
||||
renderDisp() {
|
||||
this.renderMat(this.dispMat, this.dispRT);
|
||||
this.renderMat(this.normMat, this.normRT);
|
||||
this.renderMat(this.dispMat, this.dispRT)
|
||||
this.renderMat(this.normMat, this.normRT)
|
||||
},
|
||||
renderMat(mat, target) {
|
||||
const renderer = this.renderer.renderer;
|
||||
this.fsQuad.material = mat;
|
||||
const oldTarget = renderer.getRenderTarget();
|
||||
renderer.setRenderTarget(target);
|
||||
this.fsQuad.render(renderer);
|
||||
renderer.setRenderTarget(oldTarget);
|
||||
const renderer = this.renderer.renderer
|
||||
this.fsQuad.material = mat
|
||||
const oldTarget = renderer.getRenderTarget()
|
||||
renderer.setRenderTarget(target)
|
||||
this.fsQuad.render(renderer)
|
||||
renderer.setRenderTarget(oldTarget)
|
||||
},
|
||||
},
|
||||
__hmrId: 'NoisyPlane',
|
||||
});
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineComponent, watch } from 'vue';
|
||||
import Sphere from '../../meshes/Sphere';
|
||||
import snoise4 from '../../glsl/snoise4.glsl.js';
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import Sphere from '../../meshes/Sphere'
|
||||
import snoise4 from '../../glsl/snoise4.glsl.js'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Sphere,
|
||||
@ -14,38 +14,38 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
// uniforms
|
||||
const uTime = { value: 0 };
|
||||
const uNoiseCoef = { value: props.noiseCoef };
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value; });
|
||||
const uDispCoef = { value: props.dispCoef };
|
||||
watch(() => props.dispCoef, (value) => { uDispCoef.value = value; });
|
||||
const uTime = { value: 0 }
|
||||
const uNoiseCoef = { value: props.noiseCoef }
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value })
|
||||
const uDispCoef = { value: props.dispCoef }
|
||||
watch(() => props.dispCoef, (value) => { uDispCoef.value = value })
|
||||
|
||||
return {
|
||||
uTime, uNoiseCoef, uDispCoef,
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateMaterial();
|
||||
this.updateMaterial()
|
||||
|
||||
this.startTime = Date.now();
|
||||
this.renderer.onBeforeRender(this.updateTime);
|
||||
this.startTime = Date.now()
|
||||
this.renderer.onBeforeRender(this.updateTime)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.updateTime);
|
||||
this.renderer.offBeforeRender(this.updateTime)
|
||||
},
|
||||
methods: {
|
||||
updateMaterial() {
|
||||
this.material.onBeforeCompile = (shader) => {
|
||||
shader.uniforms.uTime = this.uTime;
|
||||
shader.uniforms.uNoiseCoef = this.uNoiseCoef;
|
||||
shader.uniforms.uDispCoef = this.uDispCoef;
|
||||
shader.uniforms.uTime = this.uTime
|
||||
shader.uniforms.uNoiseCoef = this.uNoiseCoef
|
||||
shader.uniforms.uDispCoef = this.uDispCoef
|
||||
shader.vertexShader = `
|
||||
uniform float uTime;
|
||||
uniform float uNoiseCoef;
|
||||
uniform float uDispCoef;
|
||||
varying float vNoise;
|
||||
${snoise4}
|
||||
` + shader.vertexShader;
|
||||
` + shader.vertexShader
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace(
|
||||
'#include <begin_vertex>',
|
||||
@ -55,14 +55,14 @@ export default defineComponent({
|
||||
vec3 transformed = vec3(position);
|
||||
transformed += normalize(position) * vNoise * uDispCoef;
|
||||
`
|
||||
);
|
||||
this.materialShader = shader;
|
||||
};
|
||||
this.material.needsupdate = true;
|
||||
)
|
||||
this.materialShader = shader
|
||||
}
|
||||
this.material.needsupdate = true
|
||||
},
|
||||
updateTime() {
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef;
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef
|
||||
},
|
||||
},
|
||||
__hmrId: 'NoisySphere',
|
||||
});
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { defineComponent, watch } from 'vue';
|
||||
import Text from '../../meshes/Text';
|
||||
import snoise2 from '../../glsl/snoise2.glsl.js';
|
||||
import { defineComponent, watch } from 'vue'
|
||||
import Text from '../../meshes/Text'
|
||||
import snoise2 from '../../glsl/snoise2.glsl.js'
|
||||
|
||||
export default defineComponent({
|
||||
extends: Text,
|
||||
@ -11,37 +11,37 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
// uniforms
|
||||
const uTime = { value: 0 };
|
||||
const uNoiseCoef = { value: props.noiseCoef };
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value; });
|
||||
const uZCoef = { value: props.zCoef };
|
||||
watch(() => props.zCoef, (value) => { uZCoef.value = value; });
|
||||
const uTime = { value: 0 }
|
||||
const uNoiseCoef = { value: props.noiseCoef }
|
||||
watch(() => props.noiseCoef, (value) => { uNoiseCoef.value = value })
|
||||
const uZCoef = { value: props.zCoef }
|
||||
watch(() => props.zCoef, (value) => { uZCoef.value = value })
|
||||
|
||||
return {
|
||||
uTime, uNoiseCoef, uZCoef,
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateMaterial();
|
||||
this.updateMaterial()
|
||||
|
||||
this.startTime = Date.now();
|
||||
this.renderer.onBeforeRender(this.updateTime);
|
||||
this.startTime = Date.now()
|
||||
this.renderer.onBeforeRender(this.updateTime)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.updateTime);
|
||||
this.renderer.offBeforeRender(this.updateTime)
|
||||
},
|
||||
methods: {
|
||||
updateMaterial() {
|
||||
this.material.onBeforeCompile = (shader) => {
|
||||
shader.uniforms.uTime = this.uTime;
|
||||
shader.uniforms.uNoiseCoef = this.uNoiseCoef;
|
||||
shader.uniforms.uZCoef = this.uZCoef;
|
||||
shader.uniforms.uTime = this.uTime
|
||||
shader.uniforms.uNoiseCoef = this.uNoiseCoef
|
||||
shader.uniforms.uZCoef = this.uZCoef
|
||||
shader.vertexShader = `
|
||||
uniform float uTime;
|
||||
uniform float uNoiseCoef;
|
||||
uniform float uZCoef;
|
||||
${snoise2}
|
||||
` + shader.vertexShader;
|
||||
` + shader.vertexShader
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace(
|
||||
'#include <begin_vertex>',
|
||||
@ -52,14 +52,14 @@ export default defineComponent({
|
||||
vec3 transformed = vec3(position);
|
||||
transformed.z += noise * uZCoef;
|
||||
`
|
||||
);
|
||||
this.materialShader = shader;
|
||||
};
|
||||
this.material.needsupdate = true;
|
||||
)
|
||||
this.materialShader = shader
|
||||
}
|
||||
this.material.needsupdate = true
|
||||
},
|
||||
updateTime() {
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef;
|
||||
this.uTime.value = (Date.now() - this.startTime) * this.timeCoef
|
||||
},
|
||||
},
|
||||
__hmrId: 'NoisyText',
|
||||
});
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import useCannon from './useCannon.js';
|
||||
import { defineComponent } from 'vue'
|
||||
import useCannon from './useCannon.js'
|
||||
// import { bindProp } from '../../tools';
|
||||
|
||||
export default defineComponent({
|
||||
@ -10,54 +10,54 @@ export default defineComponent({
|
||||
onBeforeStep: Function,
|
||||
},
|
||||
created() {
|
||||
this._parent = this.getParent();
|
||||
if (!this._parent) console.error('Missing parent (Scene, Group...)');
|
||||
this._parent = this.getParent()
|
||||
if (!this._parent) console.error('Missing parent (Scene, Group...)')
|
||||
|
||||
this.cannon = useCannon({ gravity: this.gravity, broadphase: this.broadphase });
|
||||
this.cannon = useCannon({ gravity: this.gravity, broadphase: this.broadphase })
|
||||
},
|
||||
mounted() {
|
||||
this.renderer.onBeforeRender(this.step);
|
||||
this.renderer.onBeforeRender(this.step)
|
||||
},
|
||||
unmounted() {
|
||||
this.renderer.offBeforeRender(this.step);
|
||||
this.renderer.offBeforeRender(this.step)
|
||||
},
|
||||
methods: {
|
||||
step() {
|
||||
this.onBeforeStep?.(this.cannon);
|
||||
this.cannon.step();
|
||||
this.onBeforeStep?.(this.cannon)
|
||||
this.cannon.step()
|
||||
},
|
||||
add(o) {
|
||||
this.addToParent(o);
|
||||
this.cannon.addMesh(o);
|
||||
this.addToParent(o)
|
||||
this.cannon.addMesh(o)
|
||||
},
|
||||
remove(o) {
|
||||
this.removeFromParent(o);
|
||||
this.cannon.removeMesh(o);
|
||||
this.removeFromParent(o)
|
||||
this.cannon.removeMesh(o)
|
||||
},
|
||||
getParent() {
|
||||
let parent = this.$parent;
|
||||
let parent = this.$parent
|
||||
while (parent) {
|
||||
if (parent.add) return parent;
|
||||
parent = parent.$parent;
|
||||
if (parent.add) return parent
|
||||
parent = parent.$parent
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
},
|
||||
addToParent(o) {
|
||||
if (this._parent) {
|
||||
this._parent.add(o);
|
||||
return true;
|
||||
this._parent.add(o)
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
},
|
||||
removeFromParent(o) {
|
||||
if (this._parent) {
|
||||
this._parent.remove(o);
|
||||
return true;
|
||||
this._parent.remove(o)
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
},
|
||||
},
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default() : [];
|
||||
return this.$slots.default ? this.$slots.default() : []
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -3,191 +3,191 @@ import {
|
||||
Body, World,
|
||||
SAPBroadphase,
|
||||
Quaternion, Vec3,
|
||||
} from 'cannon';
|
||||
} from 'cannon'
|
||||
|
||||
export default function useCannon(options) {
|
||||
const {
|
||||
broadphase = null,
|
||||
gravity = new Vec3(0, 0, -9.82),
|
||||
// solverIterations = 10,
|
||||
} = options;
|
||||
} = options
|
||||
|
||||
const world = new World();
|
||||
world.gravity.set(gravity.x, gravity.y, gravity.z);
|
||||
const world = new World()
|
||||
world.gravity.set(gravity.x, gravity.y, gravity.z)
|
||||
|
||||
if (broadphase === 'sap') {
|
||||
world.broadphase = new SAPBroadphase(world);
|
||||
world.broadphase = new SAPBroadphase(world)
|
||||
}
|
||||
// world.solver.iterations = solverIterations;
|
||||
|
||||
const meshes = [];
|
||||
const meshes = []
|
||||
|
||||
const obj = {
|
||||
world,
|
||||
addMesh,
|
||||
removeMesh,
|
||||
step,
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
return obj
|
||||
|
||||
function addMesh(mesh) {
|
||||
const shape = getShape(mesh.geometry);
|
||||
const shape = getShape(mesh.geometry)
|
||||
if (shape) {
|
||||
if (mesh.isInstancedMesh) {
|
||||
handleInstancedMesh(mesh, shape);
|
||||
handleInstancedMesh(mesh, shape)
|
||||
} else if (mesh.isMesh) {
|
||||
handleMesh(mesh, shape);
|
||||
handleMesh(mesh, shape)
|
||||
}
|
||||
} else {
|
||||
console.warn(`Unhandled Mesh geometry ${mesh.geometry.type}`);
|
||||
console.warn(`Unhandled Mesh geometry ${mesh.geometry.type}`)
|
||||
}
|
||||
}
|
||||
|
||||
function removeMesh(mesh) {
|
||||
const index = meshes.indexOf(mesh);
|
||||
const index = meshes.indexOf(mesh)
|
||||
if (index !== -1) {
|
||||
meshes.splice(index, 1);
|
||||
meshes.splice(index, 1)
|
||||
}
|
||||
if (mesh.userData.bodies) {
|
||||
mesh.userData.bodies.forEach(body => {
|
||||
world.removeBody(body);
|
||||
});
|
||||
mesh.userData.bodies = [];
|
||||
world.removeBody(body)
|
||||
})
|
||||
mesh.userData.bodies = []
|
||||
}
|
||||
if (mesh.userData.body) {
|
||||
world.removeBody(mesh.userData.body);
|
||||
delete mesh.userData.body;
|
||||
world.removeBody(mesh.userData.body)
|
||||
delete mesh.userData.body
|
||||
}
|
||||
}
|
||||
|
||||
function step() {
|
||||
world.step(1 / 60);
|
||||
world.step(1 / 60)
|
||||
for (let i = 0, l = meshes.length; i < l; i++) {
|
||||
const mesh = meshes[i];
|
||||
const mesh = meshes[i]
|
||||
if (mesh.isInstancedMesh) {
|
||||
const iMatrix = mesh.instanceMatrix.array;
|
||||
const bodies = mesh.userData.bodies;
|
||||
const iMatrix = mesh.instanceMatrix.array
|
||||
const bodies = mesh.userData.bodies
|
||||
for (let j = 0; j < bodies.length; j++) {
|
||||
const body = bodies[j];
|
||||
compose(body.position, body.quaternion, mesh.userData.scales[j], iMatrix, j * 16);
|
||||
const body = bodies[j]
|
||||
compose(body.position, body.quaternion, mesh.userData.scales[j], iMatrix, j * 16)
|
||||
}
|
||||
mesh.instanceMatrix.needsUpdate = true;
|
||||
mesh.instanceMatrix.needsUpdate = true
|
||||
} else if (mesh.isMesh) {
|
||||
mesh.position.copy(mesh.userData.body.position);
|
||||
mesh.quaternion.copy(mesh.userData.body.quaternion);
|
||||
mesh.position.copy(mesh.userData.body.position)
|
||||
mesh.quaternion.copy(mesh.userData.body.quaternion)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getShape(geometry) {
|
||||
const parameters = geometry.parameters;
|
||||
const parameters = geometry.parameters
|
||||
switch (geometry.type) {
|
||||
case 'BoxGeometry':
|
||||
return new Box(new Vec3(
|
||||
parameters.width / 2,
|
||||
parameters.height / 2,
|
||||
parameters.depth / 2
|
||||
));
|
||||
))
|
||||
|
||||
case 'PlaneGeometry':
|
||||
return new Plane();
|
||||
return new Plane()
|
||||
|
||||
case 'SphereGeometry':
|
||||
return new Sphere(parameters.radius);
|
||||
return new Sphere(parameters.radius)
|
||||
|
||||
case 'CylinderGeometry':
|
||||
return new Cylinder(parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments);
|
||||
return new Cylinder(parameters.radiusTop, parameters.radiusBottom, parameters.height, parameters.radialSegments)
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return null
|
||||
}
|
||||
|
||||
function handleMesh(mesh, shape) {
|
||||
const position = new Vec3();
|
||||
position.copy(mesh.position);
|
||||
const position = new Vec3()
|
||||
position.copy(mesh.position)
|
||||
|
||||
const quaternion = new Quaternion();
|
||||
quaternion.copy(mesh.quaternion);
|
||||
const quaternion = new Quaternion()
|
||||
quaternion.copy(mesh.quaternion)
|
||||
|
||||
const mass = mesh.userData.mass ? mesh.userData.mass : 0;
|
||||
const damping = mesh.userData.damping ? mesh.userData.damping : 0.01;
|
||||
const mass = mesh.userData.mass ? mesh.userData.mass : 0
|
||||
const damping = mesh.userData.damping ? mesh.userData.damping : 0.01
|
||||
|
||||
const body = new Body({ shape, position, quaternion, mass, linearDamping: damping, angularDamping: damping });
|
||||
world.addBody(body);
|
||||
const body = new Body({ shape, position, quaternion, mass, linearDamping: damping, angularDamping: damping })
|
||||
world.addBody(body)
|
||||
|
||||
mesh.userData.body = body;
|
||||
mesh.userData.body = body
|
||||
if (mesh.userData.mass > 0) {
|
||||
meshes.push(mesh);
|
||||
meshes.push(mesh)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function handleInstancedMesh(mesh, shape) {
|
||||
const iMatrix = mesh.instanceMatrix.array;
|
||||
const bodies = [];
|
||||
const iMatrix = mesh.instanceMatrix.array
|
||||
const bodies = []
|
||||
for (let i = 0; i < mesh.count; i++) {
|
||||
const index = i * 16;
|
||||
const index = i * 16
|
||||
|
||||
const position = new Vec3();
|
||||
position.set(iMatrix[index + 12], iMatrix[index + 13], iMatrix[index + 14]);
|
||||
const position = new Vec3()
|
||||
position.set(iMatrix[index + 12], iMatrix[index + 13], iMatrix[index + 14])
|
||||
|
||||
// handle instance scale
|
||||
let scale = 1;
|
||||
if (mesh.userData.scales?.[i]) scale = mesh.userData.scales?.[i];
|
||||
const geoParams = mesh.geometry.parameters;
|
||||
let scale = 1
|
||||
if (mesh.userData.scales?.[i]) scale = mesh.userData.scales?.[i]
|
||||
const geoParams = mesh.geometry.parameters
|
||||
if (mesh.geometry.type === 'SphereGeometry') {
|
||||
shape = new Sphere(scale * geoParams.radius);
|
||||
shape = new Sphere(scale * geoParams.radius)
|
||||
} else if (mesh.geometry.type === 'BoxGeometry') {
|
||||
shape = new Box(new Vec3(
|
||||
scale * geoParams.width / 2,
|
||||
scale * geoParams.height / 2,
|
||||
scale * geoParams.depth / 2
|
||||
));
|
||||
))
|
||||
} else {
|
||||
console.warn(`Unhandled InstancedMesh geometry ${mesh.geometry.type}`);
|
||||
return;
|
||||
console.warn(`Unhandled InstancedMesh geometry ${mesh.geometry.type}`)
|
||||
return
|
||||
}
|
||||
|
||||
let mass = 0;
|
||||
if (mesh.userData.masses?.[i]) mass = mesh.userData.masses[i];
|
||||
else if (mesh.userData.mass) mass = mesh.userData.mass;
|
||||
let mass = 0
|
||||
if (mesh.userData.masses?.[i]) mass = mesh.userData.masses[i]
|
||||
else if (mesh.userData.mass) mass = mesh.userData.mass
|
||||
|
||||
let damping = 0.01;
|
||||
if (mesh.userData.dampings?.[i]) damping = mesh.userData.dampings?.[i];
|
||||
else if (mesh.userData.damping) damping = mesh.userData.damping;
|
||||
let damping = 0.01
|
||||
if (mesh.userData.dampings?.[i]) damping = mesh.userData.dampings?.[i]
|
||||
else if (mesh.userData.damping) damping = mesh.userData.damping
|
||||
|
||||
const body = new Body({ shape, position, mass, linearDamping: damping, angularDamping: damping });
|
||||
world.addBody(body);
|
||||
bodies.push(body);
|
||||
const body = new Body({ shape, position, mass, linearDamping: damping, angularDamping: damping })
|
||||
world.addBody(body)
|
||||
bodies.push(body)
|
||||
}
|
||||
|
||||
mesh.userData.bodies = bodies;
|
||||
meshes.push(mesh);
|
||||
};
|
||||
mesh.userData.bodies = bodies
|
||||
meshes.push(mesh)
|
||||
}
|
||||
|
||||
function compose(position, quaternion, scale, iMatrix, index) {
|
||||
const x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
|
||||
const x2 = x + x, y2 = y + y, z2 = z + z;
|
||||
const xx = x * x2, xy = x * y2, xz = x * z2;
|
||||
const yy = y * y2, yz = y * z2, zz = z * z2;
|
||||
const wx = w * x2, wy = w * y2, wz = w * z2;
|
||||
const x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w
|
||||
const x2 = x + x, y2 = y + y, z2 = z + z
|
||||
const xx = x * x2, xy = x * y2, xz = x * z2
|
||||
const yy = y * y2, yz = y * z2, zz = z * z2
|
||||
const wx = w * x2, wy = w * y2, wz = w * z2
|
||||
|
||||
iMatrix[index + 0] = (1 - (yy + zz)) * scale;
|
||||
iMatrix[index + 1] = (xy + wz) * scale;
|
||||
iMatrix[index + 2] = (xz - wy) * scale;
|
||||
iMatrix[index + 3] = 0;
|
||||
iMatrix[index + 0] = (1 - (yy + zz)) * scale
|
||||
iMatrix[index + 1] = (xy + wz) * scale
|
||||
iMatrix[index + 2] = (xz - wy) * scale
|
||||
iMatrix[index + 3] = 0
|
||||
|
||||
iMatrix[index + 4] = (xy - wz) * scale;
|
||||
iMatrix[index + 5] = (1 - (xx + zz)) * scale;
|
||||
iMatrix[index + 6] = (yz + wx) * scale;
|
||||
iMatrix[index + 7] = 0;
|
||||
iMatrix[index + 4] = (xy - wz) * scale
|
||||
iMatrix[index + 5] = (1 - (xx + zz)) * scale
|
||||
iMatrix[index + 6] = (yz + wx) * scale
|
||||
iMatrix[index + 7] = 0
|
||||
|
||||
iMatrix[index + 8] = (xz + wy) * scale;
|
||||
iMatrix[index + 9] = (yz - wx) * scale;
|
||||
iMatrix[index + 10] = (1 - (xx + yy)) * scale;
|
||||
iMatrix[index + 11] = 0;
|
||||
iMatrix[index + 8] = (xz + wy) * scale
|
||||
iMatrix[index + 9] = (yz - wx) * scale
|
||||
iMatrix[index + 10] = (1 - (xx + yy)) * scale
|
||||
iMatrix[index + 11] = 0
|
||||
|
||||
iMatrix[index + 12] = position.x;
|
||||
iMatrix[index + 13] = position.y;
|
||||
iMatrix[index + 14] = position.z;
|
||||
iMatrix[index + 15] = 1;
|
||||
iMatrix[index + 12] = position.x
|
||||
iMatrix[index + 13] = position.y
|
||||
iMatrix[index + 14] = position.z
|
||||
iMatrix[index + 15] = 1
|
||||
}
|
||||
}
|
||||
|
@ -7,22 +7,22 @@ import {
|
||||
Object3D,
|
||||
Vector2,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
} from 'three'
|
||||
|
||||
import { Geometry, Face3 } from 'three/examples/jsm/deprecated/Geometry.js';
|
||||
import { Geometry, Face3 } from 'three/examples/jsm/deprecated/Geometry.js'
|
||||
|
||||
export default class AnimatedPlane {
|
||||
constructor(params) {
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
this[key] = value;
|
||||
});
|
||||
this[key] = value
|
||||
})
|
||||
|
||||
this.o3d = new Object3D();
|
||||
this.uProgress = { value: 0 };
|
||||
this.uvScale = new Vector2();
|
||||
this.o3d = new Object3D()
|
||||
this.uProgress = { value: 0 }
|
||||
this.uvScale = new Vector2()
|
||||
|
||||
this.initMaterial();
|
||||
this.initPlane();
|
||||
this.initMaterial()
|
||||
this.initPlane()
|
||||
}
|
||||
|
||||
initMaterial() {
|
||||
@ -31,8 +31,8 @@ export default class AnimatedPlane {
|
||||
transparent: true,
|
||||
map: this.texture,
|
||||
onBeforeCompile: shader => {
|
||||
shader.uniforms.progress = this.uProgress;
|
||||
shader.uniforms.uvScale = { value: this.uvScale };
|
||||
shader.uniforms.progress = this.uProgress
|
||||
shader.uniforms.uvScale = { value: this.uvScale }
|
||||
shader.vertexShader = `
|
||||
uniform float progress;
|
||||
uniform vec2 uvScale;
|
||||
@ -56,12 +56,12 @@ export default class AnimatedPlane {
|
||||
sy, -sx * cy, cx * cy
|
||||
);
|
||||
}
|
||||
` + shader.vertexShader;
|
||||
` + shader.vertexShader
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace('#include <uv_vertex>', `
|
||||
#include <uv_vertex>
|
||||
vUv = vUv * uvScale + uvOffset;
|
||||
`);
|
||||
`)
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace('#include <project_vertex>', `
|
||||
mat3 rotMat = rotationMatrixXYZ(progress * rotation);
|
||||
@ -76,124 +76,124 @@ export default class AnimatedPlane {
|
||||
|
||||
mvPosition = modelViewMatrix * mvPosition;
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
`);
|
||||
`)
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
initPlane() {
|
||||
const { width, wWidth, wHeight } = this.screen;
|
||||
this.wSize = this.size * wWidth / width;
|
||||
this.nx = Math.ceil(wWidth / this.wSize) + 1;
|
||||
this.ny = Math.ceil(wHeight / this.wSize) + 1;
|
||||
this.icount = this.nx * this.ny;
|
||||
const { width, wWidth, wHeight } = this.screen
|
||||
this.wSize = this.size * wWidth / width
|
||||
this.nx = Math.ceil(wWidth / this.wSize) + 1
|
||||
this.ny = Math.ceil(wHeight / this.wSize) + 1
|
||||
this.icount = this.nx * this.ny
|
||||
|
||||
this.initGeometry();
|
||||
this.initUV();
|
||||
this.initAnimAttributes();
|
||||
this.initGeometry()
|
||||
this.initUV()
|
||||
this.initAnimAttributes()
|
||||
|
||||
if (this.imesh) {
|
||||
this.o3d.remove(this.imesh);
|
||||
this.o3d.remove(this.imesh)
|
||||
}
|
||||
this.imesh = new InstancedMesh(this.bGeometry, this.material, this.icount);
|
||||
this.o3d.add(this.imesh);
|
||||
this.imesh = new InstancedMesh(this.bGeometry, this.material, this.icount)
|
||||
this.o3d.add(this.imesh)
|
||||
|
||||
const dummy = new Object3D();
|
||||
let index = 0;
|
||||
let x = -(wWidth - (wWidth - this.nx * this.wSize)) / 2 + this.dx;
|
||||
const dummy = new Object3D()
|
||||
let index = 0
|
||||
let x = -(wWidth - (wWidth - this.nx * this.wSize)) / 2 + this.dx
|
||||
for (let i = 0; i < this.nx; i++) {
|
||||
let y = -(wHeight - (wHeight - this.ny * this.wSize)) / 2 + this.dy;
|
||||
let y = -(wHeight - (wHeight - this.ny * this.wSize)) / 2 + this.dy
|
||||
for (let j = 0; j < this.ny; j++) {
|
||||
dummy.position.set(x, y, 0);
|
||||
dummy.updateMatrix();
|
||||
this.imesh.setMatrixAt(index++, dummy.matrix);
|
||||
y += this.wSize;
|
||||
dummy.position.set(x, y, 0)
|
||||
dummy.updateMatrix()
|
||||
this.imesh.setMatrixAt(index++, dummy.matrix)
|
||||
y += this.wSize
|
||||
}
|
||||
x += this.wSize;
|
||||
x += this.wSize
|
||||
}
|
||||
}
|
||||
|
||||
initGeometry() {
|
||||
// square
|
||||
const geometry = new Geometry();
|
||||
geometry.vertices.push(new Vector3(0, 0, 0));
|
||||
geometry.vertices.push(new Vector3(this.wSize, 0, 0));
|
||||
geometry.vertices.push(new Vector3(0, this.wSize, 0));
|
||||
geometry.vertices.push(new Vector3(this.wSize, this.wSize, 0));
|
||||
geometry.faces.push(new Face3(0, 2, 1));
|
||||
geometry.faces.push(new Face3(2, 3, 1));
|
||||
const geometry = new Geometry()
|
||||
geometry.vertices.push(new Vector3(0, 0, 0))
|
||||
geometry.vertices.push(new Vector3(this.wSize, 0, 0))
|
||||
geometry.vertices.push(new Vector3(0, this.wSize, 0))
|
||||
geometry.vertices.push(new Vector3(this.wSize, this.wSize, 0))
|
||||
geometry.faces.push(new Face3(0, 2, 1))
|
||||
geometry.faces.push(new Face3(2, 3, 1))
|
||||
|
||||
geometry.faceVertexUvs[0].push([
|
||||
new Vector2(0, 0),
|
||||
new Vector2(0, 1),
|
||||
new Vector2(1, 0),
|
||||
]);
|
||||
])
|
||||
geometry.faceVertexUvs[0].push([
|
||||
new Vector2(0, 1),
|
||||
new Vector2(1, 1),
|
||||
new Vector2(1, 0),
|
||||
]);
|
||||
])
|
||||
|
||||
// geometry.computeFaceNormals();
|
||||
// geometry.computeVertexNormals();
|
||||
|
||||
// center
|
||||
this.dx = this.wSize / 2;
|
||||
this.dy = this.wSize / 2;
|
||||
geometry.translate(-this.dx, -this.dy, 0);
|
||||
this.dx = this.wSize / 2
|
||||
this.dy = this.wSize / 2
|
||||
geometry.translate(-this.dx, -this.dy, 0)
|
||||
|
||||
this.bGeometry = geometry.toBufferGeometry();
|
||||
this.bGeometry = geometry.toBufferGeometry()
|
||||
}
|
||||
|
||||
initAnimAttributes() {
|
||||
const { randFloat: rnd, randFloatSpread: rndFS } = MathUtils;
|
||||
const v3 = new Vector3();
|
||||
const { randFloat: rnd, randFloatSpread: rndFS } = MathUtils
|
||||
const v3 = new Vector3()
|
||||
|
||||
const offsets = new Float32Array(this.icount * 3);
|
||||
const offsets = new Float32Array(this.icount * 3)
|
||||
for (let i = 0; i < offsets.length; i += 3) {
|
||||
if (this.anim === 1) v3.set(rndFS(10), rnd(50, 100), rnd(20, 50)).toArray(offsets, i);
|
||||
else v3.set(rndFS(20), rndFS(20), rnd(20, 200)).toArray(offsets, i);
|
||||
if (this.anim === 1) v3.set(rndFS(10), rnd(50, 100), rnd(20, 50)).toArray(offsets, i)
|
||||
else v3.set(rndFS(20), rndFS(20), rnd(20, 200)).toArray(offsets, i)
|
||||
}
|
||||
this.bGeometry.setAttribute('offset', new InstancedBufferAttribute(offsets, 3));
|
||||
this.bGeometry.setAttribute('offset', new InstancedBufferAttribute(offsets, 3))
|
||||
|
||||
const rotations = new Float32Array(this.icount * 3);
|
||||
const angle = Math.PI * 4;
|
||||
const rotations = new Float32Array(this.icount * 3)
|
||||
const angle = Math.PI * 4
|
||||
for (let i = 0; i < rotations.length; i += 3) {
|
||||
rotations[i] = rndFS(angle);
|
||||
rotations[i + 1] = rndFS(angle);
|
||||
rotations[i + 2] = rndFS(angle);
|
||||
rotations[i] = rndFS(angle)
|
||||
rotations[i + 1] = rndFS(angle)
|
||||
rotations[i + 2] = rndFS(angle)
|
||||
}
|
||||
this.bGeometry.setAttribute('rotation', new InstancedBufferAttribute(rotations, 3));
|
||||
this.bGeometry.setAttribute('rotation', new InstancedBufferAttribute(rotations, 3))
|
||||
}
|
||||
|
||||
initUV() {
|
||||
const ratio = this.nx / this.ny;
|
||||
const tRatio = this.texture.image.width / this.texture.image.height;
|
||||
if (ratio > tRatio) this.uvScale.set(1 / this.nx, (tRatio / ratio) / this.ny);
|
||||
else this.uvScale.set((ratio / tRatio) / this.nx, 1 / this.ny);
|
||||
const nW = this.uvScale.x * this.nx;
|
||||
const nH = this.uvScale.y * this.ny;
|
||||
const ratio = this.nx / this.ny
|
||||
const tRatio = this.texture.image.width / this.texture.image.height
|
||||
if (ratio > tRatio) this.uvScale.set(1 / this.nx, (tRatio / ratio) / this.ny)
|
||||
else this.uvScale.set((ratio / tRatio) / this.nx, 1 / this.ny)
|
||||
const nW = this.uvScale.x * this.nx
|
||||
const nH = this.uvScale.y * this.ny
|
||||
|
||||
const v2 = new Vector2();
|
||||
const uvOffsets = new Float32Array(this.icount * 2);
|
||||
const v2 = new Vector2()
|
||||
const uvOffsets = new Float32Array(this.icount * 2)
|
||||
for (let i = 0; i < this.nx; i++) {
|
||||
for (let j = 0; j < this.ny; j++) {
|
||||
v2.set(
|
||||
this.uvScale.x * i + (1 - nW) / 2,
|
||||
this.uvScale.y * j + (1 - nH) / 2
|
||||
).toArray(uvOffsets, (i * this.ny + j) * 2);
|
||||
).toArray(uvOffsets, (i * this.ny + j) * 2)
|
||||
}
|
||||
}
|
||||
this.bGeometry.setAttribute('uvOffset', new InstancedBufferAttribute(uvOffsets, 2));
|
||||
this.bGeometry.setAttribute('uvOffset', new InstancedBufferAttribute(uvOffsets, 2))
|
||||
}
|
||||
|
||||
setTexture(texture) {
|
||||
this.texture = texture;
|
||||
this.material.map = texture;
|
||||
this.initUV();
|
||||
this.texture = texture
|
||||
this.material.map = texture
|
||||
this.initUV()
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.initPlane();
|
||||
this.initPlane()
|
||||
}
|
||||
}
|
||||
|
@ -7,52 +7,52 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
import { Object3D } from 'three';
|
||||
import { gsap, Power4 } from 'gsap';
|
||||
import { defineComponent } from 'vue'
|
||||
import { Object3D } from 'three'
|
||||
import { gsap, Power4 } from 'gsap'
|
||||
|
||||
import Camera from '../../core/PerspectiveCamera';
|
||||
import Renderer from '../../core/Renderer';
|
||||
import Scene from '../../core/Scene';
|
||||
import Camera from '../../core/PerspectiveCamera'
|
||||
import Renderer from '../../core/Renderer'
|
||||
import Scene from '../../core/Scene'
|
||||
|
||||
import { lerp } from '../../tools';
|
||||
import AnimatedPlane from './AnimatedPlane.js';
|
||||
import useTextures from '../../use/useTextures';
|
||||
import { lerp } from '../../tools'
|
||||
import AnimatedPlane from './AnimatedPlane.js'
|
||||
import useTextures from '../../use/useTextures'
|
||||
|
||||
export default defineComponent({
|
||||
components: { Camera, Renderer, Scene },
|
||||
props: {
|
||||
images: Array,
|
||||
events: { type: Object, default: () => { return { wheel: true, click: true, keyup: true }; } },
|
||||
events: { type: Object, default: () => { return { wheel: true, click: true, keyup: true } } },
|
||||
},
|
||||
setup() {
|
||||
const loader = useTextures();
|
||||
const loader = useTextures()
|
||||
return {
|
||||
loader,
|
||||
progress: 0,
|
||||
targetProgress: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.renderer = this.$refs.renderer;
|
||||
this.three = this.renderer.three;
|
||||
this.renderer = this.$refs.renderer
|
||||
this.three = this.renderer.three
|
||||
|
||||
if (this.images.length < 2) {
|
||||
console.error('This slider needs at least 2 images.');
|
||||
console.error('This slider needs at least 2 images.')
|
||||
} else {
|
||||
this.loader.loadTextures(this.images, this.init);
|
||||
this.loader.loadTextures(this.images, this.init)
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.loader.dispose();
|
||||
const domElement = this.renderer.renderer.domElement;
|
||||
domElement.removeEventListener('click', this.onClick);
|
||||
domElement.removeEventListener('wheel', this.onWheel);
|
||||
document.removeEventListener('keyup', this.onKeyup);
|
||||
this.loader.dispose()
|
||||
const domElement = this.renderer.renderer.domElement
|
||||
domElement.removeEventListener('click', this.onClick)
|
||||
domElement.removeEventListener('wheel', this.onWheel)
|
||||
document.removeEventListener('keyup', this.onKeyup)
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.initScene();
|
||||
this.initScene()
|
||||
|
||||
gsap.fromTo(this.plane1.uProgress,
|
||||
{
|
||||
@ -63,105 +63,105 @@ export default defineComponent({
|
||||
duration: 2.5,
|
||||
ease: Power4.easeOut,
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const domElement = this.renderer.renderer.domElement;
|
||||
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
||||
this.renderer.onBeforeRender(this.updateProgress);
|
||||
this.renderer.onResize(this.onResize);
|
||||
const domElement = this.renderer.renderer.domElement
|
||||
if (this.events.click) domElement.addEventListener('click', this.onClick)
|
||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel)
|
||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup)
|
||||
this.renderer.onBeforeRender(this.updateProgress)
|
||||
this.renderer.onResize(this.onResize)
|
||||
},
|
||||
initScene() {
|
||||
const renderer = this.renderer.renderer;
|
||||
const scene = this.$refs.scene.scene;
|
||||
const renderer = this.renderer.renderer
|
||||
const scene = this.$refs.scene.scene
|
||||
|
||||
this.plane1 = new AnimatedPlane({
|
||||
renderer, screen: this.renderer.size,
|
||||
size: 10,
|
||||
anim: 1,
|
||||
texture: this.loader.textures[0],
|
||||
});
|
||||
})
|
||||
|
||||
this.plane2 = new AnimatedPlane({
|
||||
renderer, screen: this.renderer.size,
|
||||
size: 10,
|
||||
anim: 2,
|
||||
texture: this.loader.textures[1],
|
||||
});
|
||||
})
|
||||
|
||||
this.setPlanesProgress(0);
|
||||
this.planes = new Object3D();
|
||||
this.planes.add(this.plane1.o3d);
|
||||
this.planes.add(this.plane2.o3d);
|
||||
scene.add(this.planes);
|
||||
this.setPlanesProgress(0)
|
||||
this.planes = new Object3D()
|
||||
this.planes.add(this.plane1.o3d)
|
||||
this.planes.add(this.plane2.o3d)
|
||||
scene.add(this.planes)
|
||||
},
|
||||
onResize() {
|
||||
this.plane1.resize();
|
||||
this.plane2.resize();
|
||||
this.plane1.resize()
|
||||
this.plane2.resize()
|
||||
},
|
||||
onWheel(e) {
|
||||
// e.preventDefault();
|
||||
// e.preventDefault()
|
||||
if (e.deltaY > 0) {
|
||||
this.setTargetProgress(this.targetProgress + 1 / 20);
|
||||
this.setTargetProgress(this.targetProgress + 1 / 20)
|
||||
} else {
|
||||
this.setTargetProgress(this.targetProgress - 1 / 20);
|
||||
this.setTargetProgress(this.targetProgress - 1 / 20)
|
||||
}
|
||||
},
|
||||
onClick(e) {
|
||||
if (e.clientY < this.renderer.size.height / 2) {
|
||||
this.navPrevious();
|
||||
this.navPrevious()
|
||||
} else {
|
||||
this.navNext();
|
||||
this.navNext()
|
||||
}
|
||||
},
|
||||
onKeyup(e) {
|
||||
if (e.keyCode === 37 || e.keyCode === 38) {
|
||||
this.navPrevious();
|
||||
this.navPrevious()
|
||||
} else if (e.keyCode === 39 || e.keyCode === 40) {
|
||||
this.navNext();
|
||||
this.navNext()
|
||||
}
|
||||
},
|
||||
navNext() {
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress + 1);
|
||||
else this.setTargetProgress(Math.ceil(this.targetProgress));
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress + 1)
|
||||
else this.setTargetProgress(Math.ceil(this.targetProgress))
|
||||
},
|
||||
navPrevious() {
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress - 1);
|
||||
else this.setTargetProgress(Math.floor(this.targetProgress));
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress - 1)
|
||||
else this.setTargetProgress(Math.floor(this.targetProgress))
|
||||
},
|
||||
setTargetProgress(value) {
|
||||
this.targetProgress = value;
|
||||
this.targetProgress = value
|
||||
if (this.targetProgress < 0) {
|
||||
this.progress += this.images.length;
|
||||
this.targetProgress += this.images.length;
|
||||
this.progress += this.images.length
|
||||
this.targetProgress += this.images.length
|
||||
}
|
||||
},
|
||||
updateProgress() {
|
||||
const progress1 = lerp(this.progress, this.targetProgress, 0.1);
|
||||
const pdiff = progress1 - this.progress;
|
||||
if (pdiff === 0) return;
|
||||
const progress1 = lerp(this.progress, this.targetProgress, 0.1)
|
||||
const pdiff = progress1 - this.progress
|
||||
if (pdiff === 0) return
|
||||
|
||||
const p0 = this.progress % 1;
|
||||
const p1 = progress1 % 1;
|
||||
const p0 = this.progress % 1
|
||||
const p1 = progress1 % 1
|
||||
if ((pdiff > 0 && p1 < p0) || (pdiff < 0 && p0 < p1)) {
|
||||
const i = Math.floor(progress1) % this.images.length;
|
||||
const j = (i + 1) % this.images.length;
|
||||
this.plane1.setTexture(this.loader.textures[i]);
|
||||
this.plane2.setTexture(this.loader.textures[j]);
|
||||
const i = Math.floor(progress1) % this.images.length
|
||||
const j = (i + 1) % this.images.length
|
||||
this.plane1.setTexture(this.loader.textures[i])
|
||||
this.plane2.setTexture(this.loader.textures[j])
|
||||
}
|
||||
|
||||
this.progress = progress1;
|
||||
this.setPlanesProgress(this.progress % 1);
|
||||
this.progress = progress1
|
||||
this.setPlanesProgress(this.progress % 1)
|
||||
},
|
||||
setPlanesProgress(progress) {
|
||||
this.plane1.uProgress.value = progress;
|
||||
this.plane2.uProgress.value = -1 + progress;
|
||||
this.plane1.material.opacity = 1 - progress;
|
||||
this.plane2.material.opacity = progress;
|
||||
this.plane1.o3d.position.z = progress;
|
||||
this.plane2.o3d.position.z = progress - 1;
|
||||
this.plane1.uProgress.value = progress
|
||||
this.plane2.uProgress.value = -1 + progress
|
||||
this.plane1.material.opacity = 1 - progress
|
||||
this.plane2.material.opacity = progress
|
||||
this.plane1.o3d.position.z = progress
|
||||
this.plane2.o3d.position.z = progress - 1
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
@ -6,55 +6,55 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
import { Vector2 } from 'three';
|
||||
import { gsap, Power4 } from 'gsap';
|
||||
import { defineComponent } from 'vue'
|
||||
import { Vector2 } from 'three'
|
||||
import { gsap, Power4 } from 'gsap'
|
||||
|
||||
import OrthographicCamera from '../../core/OrthographicCamera';
|
||||
import Renderer from '../../core/Renderer';
|
||||
import Scene from '../../core/Scene';
|
||||
import OrthographicCamera from '../../core/OrthographicCamera'
|
||||
import Renderer from '../../core/Renderer'
|
||||
import Scene from '../../core/Scene'
|
||||
|
||||
import { lerp, lerpv2 } from '../../tools';
|
||||
import ZoomBlurImage from './ZoomBlurImage.js';
|
||||
import useTextures from '../../use/useTextures';
|
||||
import { lerp, lerpv2 } from '../../tools'
|
||||
import ZoomBlurImage from './ZoomBlurImage.js'
|
||||
import useTextures from '../../use/useTextures'
|
||||
|
||||
export default defineComponent({
|
||||
components: { OrthographicCamera, Renderer, Scene },
|
||||
props: {
|
||||
images: Array,
|
||||
events: { type: Object, default: () => { return { wheel: true, click: true, keyup: true }; } },
|
||||
events: { type: Object, default: () => { return { wheel: true, click: true, keyup: true } } },
|
||||
},
|
||||
setup() {
|
||||
const center = new Vector2();
|
||||
const loader = useTextures();
|
||||
const center = new Vector2()
|
||||
const loader = useTextures()
|
||||
|
||||
return {
|
||||
loader,
|
||||
center,
|
||||
progress: 0,
|
||||
targetProgress: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.renderer = this.$refs.renderer;
|
||||
this.three = this.renderer.three;
|
||||
this.renderer = this.$refs.renderer
|
||||
this.three = this.renderer.three
|
||||
|
||||
if (this.images.length < 2) {
|
||||
console.error('This slider needs at least 2 images.');
|
||||
console.error('This slider needs at least 2 images.')
|
||||
} else {
|
||||
this.loader.loadTextures(this.images, this.init);
|
||||
this.loader.loadTextures(this.images, this.init)
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.loader.dispose();
|
||||
const domElement = this.renderer.renderer.domElement;
|
||||
domElement.removeEventListener('click', this.onClick);
|
||||
domElement.removeEventListener('wheel', this.onWheel);
|
||||
document.removeEventListener('keyup', this.onKeyup);
|
||||
this.loader.dispose()
|
||||
const domElement = this.renderer.renderer.domElement
|
||||
domElement.removeEventListener('click', this.onClick)
|
||||
domElement.removeEventListener('wheel', this.onWheel)
|
||||
document.removeEventListener('keyup', this.onKeyup)
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.initScene();
|
||||
this.initScene()
|
||||
gsap.fromTo(this.image1.uStrength,
|
||||
{
|
||||
value: -2,
|
||||
@ -64,97 +64,97 @@ export default defineComponent({
|
||||
duration: 2.5,
|
||||
ease: Power4.easeOut,
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const domElement = this.renderer.renderer.domElement;
|
||||
if (this.events.click) domElement.addEventListener('click', this.onClick);
|
||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel);
|
||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup);
|
||||
this.renderer.onBeforeRender(this.animate);
|
||||
this.renderer.onResize(this.onResize);
|
||||
const domElement = this.renderer.renderer.domElement
|
||||
if (this.events.click) domElement.addEventListener('click', this.onClick)
|
||||
if (this.events.wheel) domElement.addEventListener('wheel', this.onWheel)
|
||||
if (this.events.keyup) document.addEventListener('keyup', this.onKeyup)
|
||||
this.renderer.onBeforeRender(this.animate)
|
||||
this.renderer.onResize(this.onResize)
|
||||
},
|
||||
initScene() {
|
||||
const scene = this.$refs.scene.scene;
|
||||
const scene = this.$refs.scene.scene
|
||||
|
||||
this.image1 = new ZoomBlurImage(this.renderer);
|
||||
this.image1.setMap(this.loader.textures[0]);
|
||||
this.image2 = new ZoomBlurImage(this.renderer);
|
||||
this.image2.setMap(this.loader.textures[1]);
|
||||
this.setImagesProgress(0);
|
||||
this.image1 = new ZoomBlurImage(this.renderer)
|
||||
this.image1.setMap(this.loader.textures[0])
|
||||
this.image2 = new ZoomBlurImage(this.renderer)
|
||||
this.image2.setMap(this.loader.textures[1])
|
||||
this.setImagesProgress(0)
|
||||
|
||||
scene.add(this.image1.mesh);
|
||||
scene.add(this.image2.mesh);
|
||||
scene.add(this.image1.mesh)
|
||||
scene.add(this.image2.mesh)
|
||||
},
|
||||
animate() {
|
||||
const { positionN } = this.renderer.three.pointer;
|
||||
this.center.copy(positionN).divideScalar(2).addScalar(0.5);
|
||||
lerpv2(this.image1.uCenter.value, this.center, 0.1);
|
||||
lerpv2(this.image2.uCenter.value, this.center, 0.1);
|
||||
const { positionN } = this.renderer.three.pointer
|
||||
this.center.copy(positionN).divideScalar(2).addScalar(0.5)
|
||||
lerpv2(this.image1.uCenter.value, this.center, 0.1)
|
||||
lerpv2(this.image2.uCenter.value, this.center, 0.1)
|
||||
|
||||
this.updateProgress();
|
||||
this.updateProgress()
|
||||
},
|
||||
onResize() {
|
||||
this.image1.updateUV();
|
||||
this.image2.updateUV();
|
||||
this.image1.updateUV()
|
||||
this.image2.updateUV()
|
||||
},
|
||||
onWheel(e) {
|
||||
// e.preventDefault();
|
||||
// e.preventDefault()
|
||||
if (e.deltaY > 0) {
|
||||
this.setTargetProgress(this.targetProgress + 1 / 20);
|
||||
this.setTargetProgress(this.targetProgress + 1 / 20)
|
||||
} else {
|
||||
this.setTargetProgress(this.targetProgress - 1 / 20);
|
||||
this.setTargetProgress(this.targetProgress - 1 / 20)
|
||||
}
|
||||
},
|
||||
onClick(e) {
|
||||
if (e.clientY < this.renderer.size.height / 2) {
|
||||
this.navPrevious();
|
||||
this.navPrevious()
|
||||
} else {
|
||||
this.navNext();
|
||||
this.navNext()
|
||||
}
|
||||
},
|
||||
onKeyup(e) {
|
||||
if (e.keyCode === 37 || e.keyCode === 38) {
|
||||
this.navPrevious();
|
||||
this.navPrevious()
|
||||
} else if (e.keyCode === 39 || e.keyCode === 40) {
|
||||
this.navNext();
|
||||
this.navNext()
|
||||
}
|
||||
},
|
||||
navNext() {
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress + 1);
|
||||
else this.setTargetProgress(Math.ceil(this.targetProgress));
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress + 1)
|
||||
else this.setTargetProgress(Math.ceil(this.targetProgress))
|
||||
},
|
||||
navPrevious() {
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress - 1);
|
||||
else this.setTargetProgress(Math.floor(this.targetProgress));
|
||||
if (Number.isInteger(this.targetProgress)) this.setTargetProgress(this.targetProgress - 1)
|
||||
else this.setTargetProgress(Math.floor(this.targetProgress))
|
||||
},
|
||||
setTargetProgress(value) {
|
||||
this.targetProgress = value;
|
||||
this.targetProgress = value
|
||||
if (this.targetProgress < 0) {
|
||||
this.progress += this.images.length;
|
||||
this.targetProgress += this.images.length;
|
||||
this.progress += this.images.length
|
||||
this.targetProgress += this.images.length
|
||||
}
|
||||
},
|
||||
updateProgress() {
|
||||
const progress1 = lerp(this.progress, this.targetProgress, 0.1);
|
||||
const pdiff = progress1 - this.progress;
|
||||
if (pdiff === 0) return;
|
||||
const progress1 = lerp(this.progress, this.targetProgress, 0.1)
|
||||
const pdiff = progress1 - this.progress
|
||||
if (pdiff === 0) return
|
||||
|
||||
const p0 = this.progress % 1;
|
||||
const p1 = progress1 % 1;
|
||||
const p0 = this.progress % 1
|
||||
const p1 = progress1 % 1
|
||||
if ((pdiff > 0 && p1 < p0) || (pdiff < 0 && p0 < p1)) {
|
||||
const i = Math.floor(progress1) % this.images.length;
|
||||
const j = (i + 1) % this.images.length;
|
||||
this.image1.setMap(this.loader.textures[i]);
|
||||
this.image2.setMap(this.loader.textures[j]);
|
||||
const i = Math.floor(progress1) % this.images.length
|
||||
const j = (i + 1) % this.images.length
|
||||
this.image1.setMap(this.loader.textures[i])
|
||||
this.image2.setMap(this.loader.textures[j])
|
||||
}
|
||||
|
||||
this.progress = progress1;
|
||||
this.setImagesProgress(this.progress % 1);
|
||||
this.progress = progress1
|
||||
this.setImagesProgress(this.progress % 1)
|
||||
},
|
||||
setImagesProgress(progress) {
|
||||
this.image1.uStrength.value = progress;
|
||||
this.image2.uStrength.value = -1 + progress;
|
||||
this.image1.uStrength.value = progress
|
||||
this.image2.uStrength.value = -1 + progress
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
@ -3,23 +3,23 @@ import {
|
||||
PlaneGeometry,
|
||||
ShaderMaterial,
|
||||
Vector2,
|
||||
} from 'three';
|
||||
} from 'three'
|
||||
|
||||
export default function ZoomBlurImage(renderer) {
|
||||
let geometry, material, mesh;
|
||||
let geometry, material, mesh
|
||||
|
||||
const uMap = { value: null };
|
||||
const uCenter = { value: new Vector2(0.5, 0.5) };
|
||||
const uStrength = { value: 0 };
|
||||
const uUVOffset = { value: new Vector2(0, 0) };
|
||||
const uUVScale = { value: new Vector2(1, 1) };
|
||||
const uMap = { value: null }
|
||||
const uCenter = { value: new Vector2(0.5, 0.5) }
|
||||
const uStrength = { value: 0 }
|
||||
const uUVOffset = { value: new Vector2(0, 0) }
|
||||
const uUVScale = { value: new Vector2(1, 1) }
|
||||
|
||||
init();
|
||||
init()
|
||||
|
||||
return { geometry, material, mesh, uCenter, uStrength, setMap, updateUV };
|
||||
return { geometry, material, mesh, uCenter, uStrength, setMap, updateUV }
|
||||
|
||||
function init() {
|
||||
geometry = new PlaneGeometry(2, 2, 1, 1);
|
||||
geometry = new PlaneGeometry(2, 2, 1, 1)
|
||||
|
||||
material = new ShaderMaterial({
|
||||
transparent: true,
|
||||
@ -83,27 +83,27 @@ export default function ZoomBlurImage(renderer) {
|
||||
}
|
||||
}
|
||||
`,
|
||||
});
|
||||
})
|
||||
|
||||
mesh = new Mesh(geometry, material);
|
||||
mesh = new Mesh(geometry, material)
|
||||
}
|
||||
|
||||
function setMap(value) {
|
||||
uMap.value = value;
|
||||
updateUV();
|
||||
uMap.value = value
|
||||
updateUV()
|
||||
}
|
||||
|
||||
function updateUV() {
|
||||
const ratio = renderer.size.ratio;
|
||||
const iRatio = uMap.value.image.width / uMap.value.image.height;
|
||||
uUVOffset.value.set(0, 0);
|
||||
uUVScale.value.set(1, 1);
|
||||
const ratio = renderer.size.ratio
|
||||
const iRatio = uMap.value.image.width / uMap.value.image.height
|
||||
uUVOffset.value.set(0, 0)
|
||||
uUVScale.value.set(1, 1)
|
||||
if (iRatio > ratio) {
|
||||
uUVScale.value.x = ratio / iRatio;
|
||||
uUVOffset.value.x = (1 - uUVScale.value.x) / 2;
|
||||
uUVScale.value.x = ratio / iRatio
|
||||
uUVOffset.value.x = (1 - uUVScale.value.x) / 2
|
||||
} else {
|
||||
uUVScale.value.y = iRatio / ratio;
|
||||
uUVOffset.value.y = (1 - uUVScale.value.y) / 2;
|
||||
uUVScale.value.y = iRatio / ratio
|
||||
uUVOffset.value.y = (1 - uUVScale.value.y) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user