threejs 摄像头视频流投影到模型上

注意 请使用高版本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);
            }
        },
    },

};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值