You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js纹理无法加载问题求助(Vite环境3D卡片渲染)

问题:Three.js卡片纹理无法渲染(Vite环境)

用npx vite运行Three.js应用,想要渲染一张卡片。相机和灯光设置正常,能看到卡片的边缘(深度),但正反两面的纹理加载不出来。已确认文件结构正确,用TextureLoader的错误检测也没发现问题,找不到原因。

文件结构

  • 项目根目录
    • textures/
      • citizen1.png
      • cardback.png
    • main.js
    • cards.js

代码片段

main.js

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { CARDS } from './cards';

const gltfLoader = new GLTFLoader()

// Scene
const scene = new THREE.Scene()

// 添加卡片
CARDS.forEach(function(card){
    scene.add(card)
    console.log(card)
})

// 灯光
const light = new THREE.PointLight(0xffffff, 1, 100)
const ambientLight = new THREE.AmbientLight(0xA3A3A3, 1)
scene.add(ambientLight)
light.position.set(0, 10, 7)
scene.add(light)

// 相机
const camera = new THREE.PerspectiveCamera(45, 800/600)
camera.position.set(0, 10, 6)
camera.lookAt(new THREE.Vector3(0, 6, 2))
scene.add(camera)

// 渲染器
const canvas = document.querySelector('.webgl')
const renderer = new THREE.WebGL1Renderer({canvas})
renderer.setSize(800, 600)
renderer.render(scene, camera)

cards.js

import {
    MeshBasicMaterial,
    BoxGeometry,
    Mesh,
    SRGBColorSpace,
    TextureLoader,
    Vector3
} from 'three';

const textureLoader = new TextureLoader();
const cardGeo = new BoxGeometry(0.4, 0.7, 0.03);

const citizen1Texture = textureLoader.load('textures/citizen1.png');
citizen1Texture.colorSpace = SRGBColorSpace;

const coverTexture = textureLoader.load('textures/cardback.png');
coverTexture.colorSpace = SRGBColorSpace;

const card1Mat = [
    new MeshBasicMaterial(),
    new MeshBasicMaterial(),
    new MeshBasicMaterial(),
    new MeshBasicMaterial(),
    new MeshBasicMaterial({map: citizen1Texture}),
    new MeshBasicMaterial({map: coverTexture})
];

const CARDS = [];

const cardsPositions = [
    new Vector3(0.5, 7.005, 3.21)
];

function configureCard(card, pos, name){
    card.name - name; // 笔误
    card.castShadow = true;
    card.position.copy(pos[0]);
    CARDS.push(card);
}

const card1 = new Mesh(cardGeo, card1Mat);
configureCard(card1, cardsPositions, 'card1');

export { CARDS }

解决方法

1. 修正Vite环境下的纹理路径

Vite加载本地静态资源需要用import.meta.url解析正确路径,否则可能资源找不到(即使控制台无报错)。修改cards.js中的纹理加载代码:

// 替换原纹理加载代码
const citizen1Texture = textureLoader.load(new URL('./textures/citizen1.png', import.meta.url).href);
citizen1Texture.colorSpace = SRGBColorSpace;

const coverTexture = textureLoader.load(new URL('./textures/cardback.png', import.meta.url).href);
coverTexture.colorSpace = SRGBColorSpace;

2. 修复笔误

cards.js中configureCard函数里的card.name - name是语法错误,改为赋值:

card.name = name;

3. 确保纹理加载完成后再渲染

TextureLoader.load是异步操作,可能渲染时纹理还未加载完成。可添加加载回调或用LoadingManager管理资源:

// 使用LoadingManager
const loadingManager = new THREE.LoadingManager();
loadingManager.onLoad = function() {
    console.log('所有资源加载完成');
    renderer.render(scene, camera);
};

const textureLoader = new TextureLoader(loadingManager);

// 或给单个纹理加加载完成回调
citizen1Texture.onLoad = function() {
    renderer.render(scene, camera);
};
coverTexture.onLoad = function() {
    renderer.render(scene, camera);
};

4. 调整卡片视角

BoxGeometry的面索引对应:0-右侧、1-左侧、2-顶部、3-底部、4-正面、5-背面。当前相机位置可能对着卡片顶部/侧面,而非带纹理的前后两面。可在configureCard函数中添加旋转:

card.rotation.x = Math.PI / 2; // 让卡片正面朝向相机,可根据实际情况调整角度

5. 添加渲染循环

当前代码仅渲染一次,添加渲染循环可确保纹理加载完成后自动更新画面:

// 在main.js末尾添加
function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

内容的提问来源于stack exchange,提问作者sergiutzuu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:22:04