增加一个LED shader
This commit is contained in:
parent
c96d550001
commit
5bcd94a3d0
@ -19,6 +19,7 @@
|
|||||||
"ant-design-vue": "4.x",
|
"ant-design-vue": "4.x",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"peerjs": "^1.5.4",
|
"peerjs": "^1.5.4",
|
||||||
|
"three": "^0.172.0",
|
||||||
"vue": "^3.3.0",
|
"vue": "^3.3.0",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0"
|
||||||
@ -26,6 +27,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rushstack/eslint-patch": "^1.6.1",
|
"@rushstack/eslint-patch": "^1.6.1",
|
||||||
"@types/node": "^20.10.6",
|
"@types/node": "^20.10.6",
|
||||||
|
"@types/three": "^0.172.0",
|
||||||
"@types/wicg-file-system-access": "^2023.10.5",
|
"@types/wicg-file-system-access": "^2023.10.5",
|
||||||
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
205
src/pages/pointShader/pointShader.vue
Normal file
205
src/pages/pointShader/pointShader.vue
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<video
|
||||||
|
id="video"
|
||||||
|
src="/static/test.mp4"
|
||||||
|
style="display: none"
|
||||||
|
loop
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></video>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<button @click="handleClick">播放</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { onMounted, onUnmounted } from "vue";
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
const video = document.getElementById("video") as HTMLVideoElement;
|
||||||
|
video.play();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建场景和相机
|
||||||
|
const scene = new THREE.Scene();
|
||||||
|
const camera = new THREE.PerspectiveCamera(
|
||||||
|
75,
|
||||||
|
window.innerWidth / window.innerHeight,
|
||||||
|
0.1,
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
camera.position.z = 5;
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const renderer = new THREE.WebGLRenderer({
|
||||||
|
canvas: document.querySelector("#canvas"),
|
||||||
|
});
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
// 获取视频元素
|
||||||
|
const video = document.getElementById("video") as HTMLVideoElement;
|
||||||
|
|
||||||
|
// 创建视频纹理
|
||||||
|
const videoTexture = new THREE.VideoTexture(video);
|
||||||
|
videoTexture.minFilter = THREE.LinearFilter;
|
||||||
|
videoTexture.magFilter = THREE.LinearFilter;
|
||||||
|
videoTexture.format = THREE.RGBFormat;
|
||||||
|
|
||||||
|
// 播放视频
|
||||||
|
try {
|
||||||
|
await video.play();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("视频播放失败:", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建平面几何体
|
||||||
|
const geometry = new THREE.PlaneGeometry(10, 10, 200, 200);
|
||||||
|
|
||||||
|
// 创建 ShaderMaterial
|
||||||
|
const material = new THREE.ShaderMaterial({
|
||||||
|
vertexShader: `
|
||||||
|
varying vec2 vUv;
|
||||||
|
varying float vDist;
|
||||||
|
varying float vRandom;
|
||||||
|
uniform vec2 mouse;
|
||||||
|
uniform float radius;
|
||||||
|
uniform float time;
|
||||||
|
uniform float drag;
|
||||||
|
|
||||||
|
// 随机函数
|
||||||
|
float random(vec2 st) {
|
||||||
|
return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vUv = uv;
|
||||||
|
vec3 pos = position;
|
||||||
|
|
||||||
|
// 基于位置和时间生成随机值
|
||||||
|
float rand = random(pos.xy) * 2.0 - 1.0;
|
||||||
|
vRandom = rand;
|
||||||
|
|
||||||
|
// 计算打散效果
|
||||||
|
float disperseFactor = sin(time * 0.5) * 0.00001;
|
||||||
|
vec3 disperseDir = vec3(
|
||||||
|
rand * disperseFactor,
|
||||||
|
rand * disperseFactor,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// 鼠标交互
|
||||||
|
vec2 mouseDir = pos.xy - mouse;
|
||||||
|
float dist = length(mouseDir);
|
||||||
|
|
||||||
|
if (dist < radius) {
|
||||||
|
float force = (radius - dist) / radius;
|
||||||
|
pos.xy += normalize(mouseDir) * force * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用打散效果
|
||||||
|
pos += disperseDir;
|
||||||
|
|
||||||
|
// 减小粒子大小
|
||||||
|
gl_PointSize = 3.0 * (1.0 + random(pos.xy));
|
||||||
|
|
||||||
|
vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
|
||||||
|
gl_Position = projectionMatrix * mvPosition;
|
||||||
|
|
||||||
|
vDist = dist;
|
||||||
|
}`,
|
||||||
|
fragmentShader: `
|
||||||
|
uniform sampler2D mainTexture;
|
||||||
|
varying vec2 vUv;
|
||||||
|
varying float vDist;
|
||||||
|
varying float vRandom;
|
||||||
|
uniform float time;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// 减小马赛克大小
|
||||||
|
float mosaicSize = 1000.0;
|
||||||
|
vec2 mosaicUv = floor(vUv * mosaicSize) / mosaicSize;
|
||||||
|
|
||||||
|
// 减小抖动效果
|
||||||
|
float jitter = sin(time * 2.0 + vRandom * 6.28) * 0.000001;
|
||||||
|
mosaicUv += vec2(jitter);
|
||||||
|
|
||||||
|
vec4 texColor = texture2D(mainTexture, mosaicUv);
|
||||||
|
|
||||||
|
// 调整扭曲和淡出效果
|
||||||
|
float distortionFactor = 1.0 - vDist * 0.05;
|
||||||
|
float alpha = 0.9 + 0.1 * sin(time * 2.0 + vRandom * 6.28);
|
||||||
|
|
||||||
|
// 边缘淡出效果
|
||||||
|
float edgeFade = 1.0 - length(gl_PointCoord - vec2(0.5)) * 2.0;
|
||||||
|
edgeFade = smoothstep(0.0, 0.5, edgeFade);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(texColor.rgb * distortionFactor, texColor.a * alpha * edgeFade);
|
||||||
|
}`,
|
||||||
|
uniforms: {
|
||||||
|
mainTexture: { value: videoTexture },
|
||||||
|
mouse: { value: new THREE.Vector2(0, 0) },
|
||||||
|
radius: { value: 0.5 },
|
||||||
|
time: { value: 0 },
|
||||||
|
drag: { value: 0.98 },
|
||||||
|
},
|
||||||
|
transparent: true,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
depthWrite: false,
|
||||||
|
blending: THREE.AdditiveBlending,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建平面点云
|
||||||
|
const points = new THREE.Points(geometry, material);
|
||||||
|
scene.add(points);
|
||||||
|
|
||||||
|
// 鼠标事件监听
|
||||||
|
const mouse = new THREE.Vector2();
|
||||||
|
const rect = renderer.domElement.getBoundingClientRect();
|
||||||
|
document.addEventListener("mousemove", (event) => {
|
||||||
|
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
|
||||||
|
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
|
||||||
|
|
||||||
|
material.uniforms.mouse.value.set(mouse.x * 5, mouse.y * 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 动画更新
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
|
||||||
|
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
||||||
|
videoTexture.needsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
material.uniforms.time.value += 0.016;
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
animate();
|
||||||
|
|
||||||
|
// 窗口大小改变时更新
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
const width = window.innerWidth;
|
||||||
|
const height = window.innerHeight;
|
||||||
|
|
||||||
|
camera.aspect = width / height;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
renderer.setSize(width, height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组件卸载时清理
|
||||||
|
onUnmounted(() => {
|
||||||
|
const video = document.getElementById("video") as HTMLVideoElement;
|
||||||
|
video.pause();
|
||||||
|
video.src = "";
|
||||||
|
video.load();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
canvas {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,11 +1,13 @@
|
|||||||
import { createRouter, createWebHashHistory } from "vue-router";
|
import { createRouter, createWebHashHistory } from "vue-router";
|
||||||
import Index from "../pages/file/index.vue";
|
import Index from "../pages/file/index.vue";
|
||||||
import Voice from "../pages/voice/webrtcVoice.vue";
|
import Voice from "../pages/voice/webrtcVoice.vue";
|
||||||
|
import PointShader from "../pages/pointShader/pointShader.vue";
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
{ path: "/", component: Index },
|
{ path: "/", component: Index },
|
||||||
{ path: "/voice", component: Voice },
|
{ path: "/voice", component: Voice },
|
||||||
|
{ path: "/pointShader", component: PointShader },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BIN
static/jl.jpg
Normal file
BIN
static/jl.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 183 KiB |
BIN
static/test.mp4
Normal file
BIN
static/test.mp4
Normal file
Binary file not shown.
47
yarn.lock
47
yarn.lock
@ -394,6 +394,11 @@
|
|||||||
core-js "^3.15.1"
|
core-js "^3.15.1"
|
||||||
nanopop "^2.1.0"
|
nanopop "^2.1.0"
|
||||||
|
|
||||||
|
"@tweenjs/tween.js@~23.1.3":
|
||||||
|
version "23.1.3"
|
||||||
|
resolved "https://registry.npmmirror.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz#eff0245735c04a928bb19c026b58c2a56460539d"
|
||||||
|
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
|
||||||
|
|
||||||
"@types/json-schema@^7.0.12":
|
"@types/json-schema@^7.0.12":
|
||||||
version "7.0.15"
|
version "7.0.15"
|
||||||
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||||
@ -411,6 +416,28 @@
|
|||||||
resolved "https://registry.npmmirror.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
|
resolved "https://registry.npmmirror.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
|
||||||
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
||||||
|
|
||||||
|
"@types/stats.js@*":
|
||||||
|
version "0.17.3"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/stats.js/-/stats.js-0.17.3.tgz#705446e12ce0fad618557dd88236f51148b7a935"
|
||||||
|
integrity sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==
|
||||||
|
|
||||||
|
"@types/three@^0.172.0":
|
||||||
|
version "0.172.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/three/-/three-0.172.0.tgz#5094852dfa781d2fe1c65eb1b4985a4aa99858b7"
|
||||||
|
integrity sha512-LrUtP3FEG26Zg5WiF0nbg8VoXiKokBLTcqM2iLvM9vzcfEiYmmBAPGdBgV0OYx9fvWlY3R/3ERTZcD9X5sc0NA==
|
||||||
|
dependencies:
|
||||||
|
"@tweenjs/tween.js" "~23.1.3"
|
||||||
|
"@types/stats.js" "*"
|
||||||
|
"@types/webxr" "*"
|
||||||
|
"@webgpu/types" "*"
|
||||||
|
fflate "~0.8.2"
|
||||||
|
meshoptimizer "~0.18.1"
|
||||||
|
|
||||||
|
"@types/webxr@*":
|
||||||
|
version "0.5.20"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/webxr/-/webxr-0.5.20.tgz#b16b681af314ec011b2e8221b0a072d691c04953"
|
||||||
|
integrity sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==
|
||||||
|
|
||||||
"@types/wicg-file-system-access@^2023.10.5":
|
"@types/wicg-file-system-access@^2023.10.5":
|
||||||
version "2023.10.5"
|
version "2023.10.5"
|
||||||
resolved "https://registry.npmmirror.com/@types/wicg-file-system-access/-/wicg-file-system-access-2023.10.5.tgz#14b3c25eb4d914b5734795bdea71da229f918b9d"
|
resolved "https://registry.npmmirror.com/@types/wicg-file-system-access/-/wicg-file-system-access-2023.10.5.tgz#14b3c25eb4d914b5734795bdea71da229f918b9d"
|
||||||
@ -661,6 +688,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@vue/tsconfig/-/tsconfig-0.1.3.tgz#4a61dbd29783d01ddab504276dcf0c2b6988654f"
|
resolved "https://registry.npmmirror.com/@vue/tsconfig/-/tsconfig-0.1.3.tgz#4a61dbd29783d01ddab504276dcf0c2b6988654f"
|
||||||
integrity sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==
|
integrity sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==
|
||||||
|
|
||||||
|
"@webgpu/types@*":
|
||||||
|
version "0.1.52"
|
||||||
|
resolved "https://registry.npmmirror.com/@webgpu/types/-/types-0.1.52.tgz#239995418d86de927269aca54cbadfbee04eb03a"
|
||||||
|
integrity sha512-eI883Nlag2hGIkhXxAnq8s4APpqXWuPL3Gbn2ghiU12UjLvfCbVqHK4XfXl3eLRTatqcMmeK7jws7IwWsGfbzw==
|
||||||
|
|
||||||
acorn-jsx@^5.3.2:
|
acorn-jsx@^5.3.2:
|
||||||
version "5.3.2"
|
version "5.3.2"
|
||||||
resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||||
@ -1175,6 +1207,11 @@ fastq@^1.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
reusify "^1.0.4"
|
reusify "^1.0.4"
|
||||||
|
|
||||||
|
fflate@~0.8.2:
|
||||||
|
version "0.8.2"
|
||||||
|
resolved "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
|
||||||
|
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
|
||||||
|
|
||||||
file-entry-cache@^6.0.1:
|
file-entry-cache@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
resolved "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||||
@ -1542,6 +1579,11 @@ merge2@^1.3.0, merge2@^1.4.1:
|
|||||||
resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||||
|
|
||||||
|
meshoptimizer@~0.18.1:
|
||||||
|
version "0.18.1"
|
||||||
|
resolved "https://registry.npmmirror.com/meshoptimizer/-/meshoptimizer-0.18.1.tgz#cdb90907f30a7b5b1190facd3b7ee6b7087797d8"
|
||||||
|
integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==
|
||||||
|
|
||||||
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.8:
|
micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.8:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||||
@ -2012,6 +2054,11 @@ text-table@^0.2.0:
|
|||||||
resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
||||||
|
|
||||||
|
three@^0.172.0:
|
||||||
|
version "0.172.0"
|
||||||
|
resolved "https://registry.npmmirror.com/three/-/three-0.172.0.tgz#6944a72f8439e8f7e4b034c8539ec82f5ebe0082"
|
||||||
|
integrity sha512-6HMgMlzU97MsV7D/tY8Va38b83kz8YJX+BefKjspMNAv0Vx6dxMogHOrnRl/sbMIs3BPUKijPqDqJ/+UwJbIow==
|
||||||
|
|
||||||
throttle-debounce@^5.0.0:
|
throttle-debounce@^5.0.0:
|
||||||
version "5.0.2"
|
version "5.0.2"
|
||||||
resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz#ec5549d84e053f043c9fd0f2a6dd892ff84456b1"
|
resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz#ec5549d84e053f043c9fd0f2a6dd892ff84456b1"
|
||||||
|
Loading…
Reference in New Issue
Block a user