Three.js中如何让先执行的init函数获取EventListener传递的图片URL
问题分析
你当前的核心问题是页面加载时直接调用了init(),此时图片还未上传,自然只能拿到空的URL;而上传图片后再次调用init(userImageURL)会重复初始化整个Three.js场景,既冗余又不符合你“init优先执行且能获取更新后URL”的需求。
解决方案
以下两种方案可以解决你的问题,核心思路是避免重复初始化场景,仅在需要时更新纹理:
方案1:首次上传时初始化场景,后续上传仅更新纹理
去掉页面加载时的init()调用,改为首次上传图片时初始化场景,之后上传图片只更新模型纹理:
var userImageURL = ''; var img1_input = document.getElementById('img1-input'); // 声明全局场景变量,方便后续更新操作 let scene, modelTexture; img1_input.addEventListener('change', function(e) { var userImage = e.target.files[0]; userImageURL = URL.createObjectURL(userImage); console.log(userImageURL); if (!scene) { // 首次上传图片,初始化Three.js场景 init(userImageURL); } else { // 后续上传,仅更新纹理 updateModelTexture(userImageURL); } }) function init(userimg1) { console.log(userimg1); // 初始化Three.js场景、相机、渲染器等核心组件 scene = new THREE.Scene(); // ...此处保留你原有的渲染初始化代码 // 创建初始纹理并应用到模型 modelTexture = new THREE.TextureLoader().load(userimg1, () => { console.log('初始纹理加载完成'); }); // 将纹理绑定到模型材质(示例) // const material = new THREE.MeshBasicMaterial({ map: modelTexture }); // const mesh = new THREE.Mesh(yourGeometry, material); // scene.add(mesh); } function updateModelTexture(newURL) { console.log(newURL); // 加载新纹理并替换旧纹理 new THREE.TextureLoader().load(newURL, (newTexture) => { // 释放旧纹理内存,避免内存泄漏 modelTexture.dispose(); modelTexture = newTexture; // 更新模型材质的纹理并标记为需要更新 // mesh.material.map = modelTexture; // mesh.material.needsUpdate = true; }); }
方案2:提前初始化场景,用默认纹理占位,上传后更新
如果必须在页面加载时就执行init(),可以先使用一张默认空白图作为初始纹理,上传图片后再替换为用户上传的图片:
var userImageURL = ''; var img1_input = document.getElementById('img1-input'); let scene, modelMesh; // 页面加载时立即初始化场景 init(); img1_input.addEventListener('change', function(e) { var userImage = e.target.files[0]; userImageURL = URL.createObjectURL(userImage); console.log(userImageURL); // 调用纹理更新方法 updateModelTexture(userImageURL); }) function init() { console.log('场景初始化完成'); // 初始化Three.js场景、相机、渲染器等 scene = new THREE.Scene(); // ...此处保留你原有的渲染初始化代码 // 使用默认空白图创建初始纹理 const defaultTexture = new THREE.TextureLoader().load('path/to/blank-image.png'); const material = new THREE.MeshBasicMaterial({ map: defaultTexture }); // 假设你已有对应的几何体 modelMesh = new THREE.Mesh(yourGeometry, material); scene.add(modelMesh); } function updateModelTexture(newURL) { console.log(newURL); new THREE.TextureLoader().load(newURL, (newTexture) => { // 释放旧纹理内存 modelMesh.material.map.dispose(); // 更新纹理并通知Three.js材质已变更 modelMesh.material.map = newTexture; modelMesh.material.needsUpdate = true; }); }
内容的提问来源于stack exchange,提问作者Andy W
相关产品推荐
相关产品推荐

