注意 请使用高版本threejs 低版本有问题
其实就是将视频作为SpotLight的贴图 给SpotLight.map设置就好了 根据官方webgl_lights_spotlight改动
官方案例链接 https://threejs.org/examples/#webgl_lights_spotlight
.vue里
<template>
<div>
<div id="containerss"></div>
<video id="spotLight_test_video" style="display:none;width: 100px;height: 100px" ref="videosmallone"
preload="auto" muted autoplay type="rtmp/flv">
<source src=""/>
</video>
</div>
</template>
<script>
import index from "./index.js";
export default index;
</script>
<style>
</style>
.js
import * as THREE from "three";
import Stats from 'three/examples/jsm/libs/stats.module.js';
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import { PLYLoader } from 'three/examples/jsm/loaders/PLYLoader.js';
import flvjs from "flv.js";
// 可视化改变三维场景库
import {GUI} from "three/examples/jsm/libs/lil-gui.module.min.js";
let scene = null;
let camera = null;
let spotLight = null;
let renderer = null;
let lightHelper = null;
//性能统计对象
const stats = new Stats();
export default {
data() {
return {
scene: null,
camera: null,
player: null,
texture: null,
};
},
mounted() {
this.initss()
this.initTextures()
this.init()
this.initModel()
},
beforeDestroy() {
this.resetScene()
},
methods: {
initModel(){
const geometry = new THREE.PlaneGeometry( 40, 40 );
const material = new THREE.MeshLambertMaterial( { color: 0xbcbcbc, } );
const mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, - 1, 0 );
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
},
//初始化 Three.js 场景、相机、光照等,并设置渲染器、事件监听器等
init() {
// 渲染器
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( this.animate );
document.body.appendChild( renderer.domElement );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 100 );
camera.position.set( 7, 4, 1 );
const controls = new OrbitControls( camera, renderer.domElement );
controls.update();
const ambient = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 0.15 );
scene.add( ambient );
// this.texture = new THREE.TextureLoader().load( 'static/favicon.png' );
// this.texture.minFilter = THREE.LinearFilter;
// this.texture.magFilter = THREE.LinearFilter;
spotLight = new THREE.SpotLight( 0xffffff, 100 );
spotLight.position.set( 0, 5, 0.5 );
spotLight.angle = 0.6;
spotLight.penumbra = 0.336;
spotLight.decay = 1.57;
spotLight.distance = 13.86;
spotLight.map = this.texture;
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 10;
spotLight.shadow.focus = 0.9;
scene.add( spotLight );
lightHelper = new THREE.SpotLightHelper( spotLight );
scene.add( lightHelper );
window.addEventListener( 'resize', this.onWindowResize );
// GUI
const gui = new GUI();
let params = {
positionx:spotLight.position.x,
positiony:spotLight.position.y,
positionz:spotLight.position.z,
color: spotLight.color.getHex(),
intensity: spotLight.intensity,
distance: spotLight.distance,
angle: spotLight.angle,
penumbra: spotLight.penumbra,
decay: spotLight.decay,
focus: spotLight.shadow.focus,
shadows: true
};
gui.add( params, 'positionx' ).onChange( function ( val ) {spotLight.position.x=val;});
gui.add( params, 'positiony' ).onChange( function ( val ) {spotLight.position.y=val;});
gui.add( params, 'positionz' ).onChange( function ( val ) {spotLight.position.z=val;});
gui.addColor( params, 'color' ).onChange( function ( val ) {spotLight.color.setHex( val );
});
gui.add( params, 'intensity', 0, 500 ).onChange( function ( val ) {spotLight.intensity = val;
});
gui.add( params, 'distance', 0, 20 ).onChange( function ( val ) {spotLight.distance = val;
});
gui.add( params, 'angle', 0, Math.PI / 3 ).onChange( function ( val ) {spotLight.angle = val;
});
gui.add( params, 'penumbra', 0, 1 ).onChange( function ( val ) {spotLight.penumbra = val;
});
gui.add( params, 'decay', 1, 2 ).onChange( function ( val ) {spotLight.decay = val;
});
gui.add( params, 'focus', 0, 1 ).onChange( function ( val ) {spotLight.shadow.focus = val;
});
gui.open();
},
//引入摄像头视频流 第一个摄像头
initss() { //这个val 就是一个地址,例如:
setTimeout(() => { //使用定时器是因为,在mounted声明周期里调用,可能会出现DOM没加载出来的原因
let videoElement = document.getElementById('spotLight_test_video') // 获取到html中的video标签
if (flvjs.isSupported()) {
//因为我这个是复用组件,进来先判断 player是否存在,如果存在,销毁掉它,不然会占用TCP名额
if (this.player !== null) {
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.player.destroy();
this.player = null;
}
this.player = flvjs.createPlayer( //创建直播流,加载到DOM中去
{
type: "flv",
//你的url地址
url: '',
isLive: true, //数据源是否为直播流
hasAudio: false, //数据源是否包含有音频
hasVideo: true, //数据源是否包含有视频
enableStashBuffer: true, //是否启用缓存区
},
{
enableWorker: false, //不启用分离线程
enableStashBuffer: false, //关闭IO隐藏缓冲区
autoCleanupSourceBuffer: true, //自动清除缓存
lazyLoad: false,
}
);
this.player.attachMediaElement(videoElement); //放到dom中去
this.player.load();//准备完成
//!!!!!!这里需要注意,有的时候load加载完成不一定可以播放,要是播放不成功,用settimeout 给下面的this.player.play() 延时几百毫秒再播放
setTimeout(() => {
this.player.play();//播放
}, 1000)
}
}, 1000);
},
//将摄像头视频流转成贴图存起来
initTextures() {
let video = document.getElementById('spotLight_test_video');
this.texture = new THREE.VideoTexture(video);
},
//窗口大小改变时,更新相机和渲染器的相关属性,以适应新的窗口尺寸,保持渲染效果的正确显示
onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
},
//主要的动画循环函数,处理控制、更新、碰撞检测等逻辑,并渲染场景
animate() {
// const time = performance.now() / 3000;
// spotLight.position.x = Math.cos( time ) * 2.5;
// spotLight.position.z = Math.sin( time ) * 2.5;
lightHelper.update();
renderer.render( scene, camera );
},
//销毁场景等信息
resetScene() {
try {
if (renderer && renderer.dispose) {
renderer.dispose();
}
renderer = null; // 解除对渲染器的引用
// 清理相机
this.camera = null;
// 遍历场景中的所有对象并清理它们的材质和几何体
this.scene.traverse((child) => {
if (child.material) {
// 清理材质(包括材质数组)
if (child.material instanceof Array) {
child.material.forEach((item) => {
if (item.dispose) {
item.dispose();
}
});
} else {
if (child.material.dispose) {
child.material.dispose();
}
}
}
if (child.geometry) {
if (child.geometry.dispose) {
child.geometry.dispose();
}
}
});
this.scene = null;
} catch (e) {
console.error("Failed to destroy three.js", e);
}
},
},
};