增加一个LED shader
This commit is contained in:
parent
c96d550001
commit
5bcd94a3d0
@ -19,6 +19,7 @@
|
||||
"ant-design-vue": "4.x",
|
||||
"highlight.js": "^11.11.1",
|
||||
"peerjs": "^1.5.4",
|
||||
"three": "^0.172.0",
|
||||
"vue": "^3.3.0",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue-router": "^4.5.0"
|
||||
@ -26,6 +27,7 @@
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.6.1",
|
||||
"@types/node": "^20.10.6",
|
||||
"@types/three": "^0.172.0",
|
||||
"@types/wicg-file-system-access": "^2023.10.5",
|
||||
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
||||
"@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 Index from "../pages/file/index.vue";
|
||||
import Voice from "../pages/voice/webrtcVoice.vue";
|
||||
import PointShader from "../pages/pointShader/pointShader.vue";
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{ path: "/", component: Index },
|
||||
{ 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"
|
||||
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":
|
||||
version "7.0.15"
|
||||
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"
|
||||
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":
|
||||
version "2023.10.5"
|
||||
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"
|
||||
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:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
@ -1175,6 +1207,11 @@ fastq@^1.6.0:
|
||||
dependencies:
|
||||
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:
|
||||
version "6.0.1"
|
||||
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"
|
||||
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:
|
||||
version "4.0.8"
|
||||
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"
|
||||
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:
|
||||
version "5.0.2"
|
||||
resolved "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.2.tgz#ec5549d84e053f043c9fd0f2a6dd892ff84456b1"
|
||||
|
Loading…
Reference in New Issue
Block a user