【Threejs】场景编辑功能及内外侧通信

分析

threejs官方提供了一个较为完善的threejs场景编辑的demo,并且支持导出导入,前进后退,场景缓存等功能,所以我们需要做的只有把他引入自己的页面。但是同时业务中可能涉及一些特殊的功能或者一些可配置的内容,我们需要在官方editor的沙盒中完成这些操作。所以最终方案就是通过iframe引入editor编辑器,然后通过contentMessage传送消息给沙盒,同时也可以反向监听沙盒里面的instance。

实施

Editor引入到项目中

首先你需要在public文件夹中放入完整的editor沙盒同时把对应的依赖也放进去(这里推荐使用分布式的,因为public包过大会影响打包效率)。
然后在项目中引入。

//nextjs演示 vue可以将ref替换为useRef vue2可以替换为ref
'use client'
import Head from 'next/head'
import React, { useEffect, useRef } from 'react'
import * as THREE from 'three'
import nextinit from './nextinit'

const ThreeEditor = () => {
    const inner = useRef()
    useEffect(() => {
        nextinit(inner.current)//初始化工具 添加事件
    }, [])

    return (
        <>
            <div className='w-full h-full bg-[#cfc]'>
                <iframe
                    ref={inner}
                    className=' w-full h-full'
                    src="/three/editor/index.html" // 请替换成你实际的静态页面文件名
                ></iframe>
            </div>
        </>
    )
}

export default ThreeEditor
注册事件系统

在editor的包文件中创建一个事件处理类并添加到index中

	//...........略
		const eventHandler = new EventHandler(editor)


	</script>
</body>

</html>
事件处理系统和一些演示的方法
import { BoxGeometry, Mesh, MeshNormalMaterial } from "three";

export default class EventHandler {
    editor
    constructor(editor) {
        this.editor = editor
        window.addEventListener('message', (event) => {
            // 确保消息来自父页面
            if (event.source !== parent) return;

            const message = event.data;

            this.eventIn(message)
        });
    }
    eventIn = (message) => {
        console.log(message);
        if (message.type === 'addTestBox') {
            const scene = editor.scene;
            const boxgeo = new BoxGeometry(5, 5, 5);
            const material = new MeshNormalMaterial();
            const mesh = new Mesh(boxgeo, material);
            scene.add(mesh);
        }
        if (message.type === 'cleanScene') {
            this.cleanScene()
        }
    }
    cleanScene = () => {
        let { scene, removeObject } = this.editor
        scene.children.forEach(obj3D => {
            if (obj3D.type == 'Mesh' || obj3D.type == 'Group')
                console.log(obj3D)
        });
    }
}

在项目中使用事件

这里我通过刚才的nextinit方法进行处理

  useEffect(() => {
        nextinit(inner.current)
    }, [])

// import { BoxGeometry, Mesh, MeshNormalMaterial } from "three"

const nextinit = (Frame) => {
    console.log(Frame.contentWindow);

    const sendMessageToIframe = (message) => {
        Frame.contentWindow.postMessage(message, '*');
    };
    setTimeout(() => {
        // const editor = Frame.contentWindow.editor
        sendMessageToIframe({ type: 'cleanScene' });
    }, 1000)
    setTimeout(() => {
        // const editor = Frame.contentWindow.editor
        sendMessageToIframe({ type: 'addTestBox' });
    }, 3000)


}
export default nextinit

效果展示

删除之前的几何体后加入一个box
在这里插入图片描述

注意事项

iframe内外的webgl通过不互通,从外部只能传送字符串一类的数据,不能传送任何instance进去,不然会报错内存错误,对应的buffer丢失。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸢_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值