一开始,我们的代码是这样写的:
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js' // 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color(0xffffff); // 创建一个纹理加载器 const loader = new THREE.TextureLoader(); // 得到一个纹理对象 const texture = loader.load('./img/diqiu.png'); // 创建立方体 const geometry = new THREE.BoxGeometry(2, 2, 2); const material = new THREE.MeshPhongMaterial({ map: texture // 设置颜色贴图 }); // material.map = texture // 使用形状和材质创建一个网格物体 const cube = new THREE.Mesh(geometry, material); scene.add(cube) // 创建光 const light = new THREE.PointLight(0xffffff, 1, 0, 0); light.position.set(10, 10, 10) scene.add(light) // 设置光源辅助对象 const pointLightHelper = new THREE.PointLightHelper(light, 1); scene.add(pointLightHelper); // 创建相机 let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(10, 10, 10) camera.lookAt(0, 0, 0) // 创建 三维坐标轴 const axesHelper = new THREE.AxesHelper(10); // 将坐标轴加入到场景中 scene.add(axesHelper); // 创建渲染对象 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 执行渲染 renderer.render(scene, camera); document.body.appendChild(renderer.domElement); // 创建轨道控制器对象 const controls = new OrbitControls(camera, renderer.domElement) controls.addEventListener('change', function () { // 重新执行渲染操作 renderer.render(scene, camera); })
然后在浏览器中访问我们的页面,发现贴图并没有生效,而是一片黑,不过只要稍微动一下就出效果了,最开始我想难道是光源的问题?不过很快就被我否掉了,因为如果是光源的问题,不会稍微动一点点就出效果。我就感觉,可能是因为渲染的时候,贴图并没有生效。这可能就是创建贴图对象的时候,并没有成功,我这时候就猜测这个 load() 函数可能是个异步执行的,就是这句:
const texture = loader.load('./img/diqiu.png');
查看他们官方文档(https://threejs.org/docs/index.html#api/zh/loaders/TextureLoader),给的例子都是使用的回调函数,我感觉我的猜测可能没错,于是我随便写了点代码验证了一下:
console.log(111); const texture = loader.load('./img/diqiu.png', function () { console.log(222); }); console.log(333);
果然,猜的没错,执行结果是:111、333、222
既然问题出在这里,那么问题就比较好解决了,比如:将首次渲染操作写到回调函数中:
// 创建渲染对象 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 创建一个纹理加载器 const loader = new THREE.TextureLoader(); // 得到一个纹理对象 const texture = loader.load('./img/diqiu.png', function () { // 执行渲染 renderer.render(scene, camera); document.body.appendChild(renderer.domElement); });
完整的代码可以参考:
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js' // 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color(0xffffff); // 创建渲染对象 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 创建一个纹理加载器 const loader = new THREE.TextureLoader(); // 得到一个纹理对象 const texture = loader.load('./img/diqiu.png', function () { // 执行渲染 renderer.render(scene, camera); document.body.appendChild(renderer.domElement); }); // 创建立方体 const geometry = new THREE.BoxGeometry(2, 2, 2); const material = new THREE.MeshPhongMaterial({ map: texture // 设置颜色贴图 }); // material.map = texture // 使用形状和材质创建一个网格物体 const cube = new THREE.Mesh(geometry, material); scene.add(cube) // 创建光 const light = new THREE.PointLight(0xffffff, 1, 0, 0); light.position.set(10, 10, 10) scene.add(light) // 设置光源辅助对象 const pointLightHelper = new THREE.PointLightHelper(light, 1); scene.add(pointLightHelper); // 创建相机 let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(10, 10, 10) camera.lookAt(0, 0, 0) // 创建 三维坐标轴 const axesHelper = new THREE.AxesHelper(10); // 将坐标轴加入到场景中 scene.add(axesHelper); // 创建轨道控制器对象 const controls = new OrbitControls(camera, renderer.domElement) controls.addEventListener('change', function () { // 重新执行渲染操作 renderer.render(scene, camera); })
使用异步函数处理
其实纹理加载器还有个.loadAsync() 方法,它可以返回一个promise对象,因此我们可以使用 async和await去编写我们的代码:
// 得到一个纹理对象 使用异步函数 const texture = await loader.loadAsync('./img/diqiu.png');
完整点的代码可以是这样的:
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js' // 创建场景 const scene = new THREE.Scene(); scene.background = new THREE.Color(0xffffff); (async () => { // 创建一个纹理加载器 const loader = new THREE.TextureLoader(); // 得到一个纹理对象 使用异步函数 const texture = await loader.loadAsync('./img/diqiu.png'); // 创建立方体 const geometry = new THREE.BoxGeometry(2, 2, 2); const material = new THREE.MeshPhongMaterial({ map: texture // 设置颜色贴图 }); // material.map = texture // 使用形状和材质创建一个网格物体 const cube = new THREE.Mesh(geometry, material); scene.add(cube) // 创建光 const light = new THREE.PointLight(0xffffff, 1, 0, 0); light.position.set(10, 10, 10) scene.add(light) // 设置光源辅助对象 const pointLightHelper = new THREE.PointLightHelper(light, 1); scene.add(pointLightHelper); // 创建相机 let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(10, 10, 10) camera.lookAt(0, 0, 0) // 创建 三维坐标轴 const axesHelper = new THREE.AxesHelper(10); // 将坐标轴加入到场景中 scene.add(axesHelper); // 创建渲染对象 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 执行渲染 renderer.render(scene, camera); document.body.appendChild(renderer.domElement); // 创建轨道控制器对象 const controls = new OrbitControls(camera, renderer.domElement) controls.addEventListener('change', function () { // 重新执行渲染操作 renderer.render(scene, camera); }) })()