在 THREE.js 中使用纹理
我从 THREE.js 开始,尝试绘制一个带有纹理的矩形,由单一光源照亮。我认为这很简单(为简洁起见,省略了 HTML):
function loadScene() {
var world = document.getElementById('world'),
WIDTH = 1200,
HEIGHT = 500,
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000,
renderer = new THREE.WebGLRenderer(),
camera = new THREE.Camera(VIEW_ANGLE, ASPECT, NEAR, FAR),
scene = new THREE.Scene(),
texture = THREE.ImageUtils.loadTexture('crate.gif'),
material = new THREE.MeshBasicMaterial({map: texture}),
// material = new THREE.MeshPhongMaterial({color: 0xCC0000});
geometry = new THREE.PlaneGeometry(100, 100),
mesh = new THREE.Mesh(geometry, material),
pointLight = new THREE.PointLight(0xFFFFFF);
camera.position.z = 200;
renderer.setSize(WIDTH, HEIGHT);
scene.addChild(mesh);
world.appendChild(renderer.domElement);
pointLight.position.x = 50;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.addLight(pointLight);
renderer.render(scene, camera);
}
问题是,我看不到任何东西。如果我更改材料并使用带注释的材料,则会出现一个正方形,正如我所期望的那样。请注意,
- 纹理是 256x256,因此其边长是 2 的幂
- 该函数实际上是在加载主体时调用的;事实上,它适用于不同的材料。
- 即使我从网络服务器提供文件,它也不起作用,因此这不是跨域策略不允许加载图像的问题。
我做错了什么?
I am starting with THREE.js, and I am trying to draw a rectangle with a texture on it, lit by a single source of light. I think this is as simple as it gets (HTML omitted for brevity):
function loadScene() {
var world = document.getElementById('world'),
WIDTH = 1200,
HEIGHT = 500,
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000,
renderer = new THREE.WebGLRenderer(),
camera = new THREE.Camera(VIEW_ANGLE, ASPECT, NEAR, FAR),
scene = new THREE.Scene(),
texture = THREE.ImageUtils.loadTexture('crate.gif'),
material = new THREE.MeshBasicMaterial({map: texture}),
// material = new THREE.MeshPhongMaterial({color: 0xCC0000});
geometry = new THREE.PlaneGeometry(100, 100),
mesh = new THREE.Mesh(geometry, material),
pointLight = new THREE.PointLight(0xFFFFFF);
camera.position.z = 200;
renderer.setSize(WIDTH, HEIGHT);
scene.addChild(mesh);
world.appendChild(renderer.domElement);
pointLight.position.x = 50;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.addLight(pointLight);
renderer.render(scene, camera);
}
The problem is, I cannot see anything. If I change the material and use the commented one, a square appears as I would expect. Note that
- The texture is 256x256, so its sides are power of two
- The function is actually called when the body is loaded; indeed it works with a different material.
- It does not work even if I serve the file from a webserver, so it is not an issue of cross-domain policy not allowing to load the image.
What I am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当加载图像时,渲染器已经绘制了场景,因此为时已晚。解决办法就是
改成
By the time the image is loaded, the renderer has already drawn the scene, hence it is too late. The solution is to change
into
安德里亚的解决方案是绝对正确的,我将根据相同的想法编写另一个实现。
如果您查看了 THREE.ImageUtils.loadTexture() 源代码 你会发现它使用了 javascript Image 对象。加载所有图像后会触发 $(window).load 事件!因此,在这种情况下,我们可以使用已加载的纹理渲染场景...
CoffeeScript
JavaScript
谢谢...
Andrea solution is absolutely right, I will just write another implementation based on the same idea.
If you took a look at the THREE.ImageUtils.loadTexture() source you will find it uses the javascript Image object. The $(window).load event is fired after all Images are loaded ! so at that event we can render our scene with the textures already loaded...
CoffeeScript
JavaScript
Thanks...
在 Three.js 的 r75 版本中,您应该使用:
In version r75 of three.js, you should use:
在 Three.js 的 r82 版本中 TextureLoader 是用于加载纹理的对象。
加载一个纹理(源代码,演示)
提取(test.js):
加载多个纹理 (源代码,demo)
在此示例中,纹理加载到网格的构造函数内,使用 承诺。
提取 (Globe.js):
使用
创建一个新容器Object3D
用于在同一个容器中拥有两个网格:一个名为
textures
的地图,其中每个对象都包含纹理文件的url
和用于存储 Three.js 纹理 对象。Promise 数组,对于映射中名为
textures
的每个对象,在数组texturePromises
中推送一个新的 Promise,每个 Promise 都会调用loader.load
。如果entry.val
的值是有效的THREE.Texture
对象,则解析该 Promise。Promise.all
将 Promise 数组texturePromises
作为参数。这样做会让浏览器等待所有的承诺得到解决,当它们解决时,我们就可以加载几何图形和材质。对于云球来说,只需要一种纹理:
In version r82 of Three.js TextureLoader is the object to use for loading a texture.
Loading one texture (source code, demo)
Extract (test.js):
Loading multiple textures (source code, demo)
In this example the textures are loaded inside the constructor of the mesh, multiple texture are loaded using Promises.
Extract (Globe.js):
Create a new container using
Object3D
for having two meshes in the same container:A map called
textures
where every object contains theurl
of a texture file andval
for storing the value of a Three.js texture object.The array of promises, for each object in the map called
textures
push a new Promise in the arraytexturePromises
, every Promise will callloader.load
. If the value ofentry.val
is a validTHREE.Texture
object, then resolve the promise.Promise.all
takes the promise arraytexturePromises
as argument. Doing so makes the browser wait for all the promises to resolve, when they do we can load the geometry and the material.For the cloud sphere only one texture is necessary:
没有错误处理
有错误处理
结果:
https://codepen.io/hiteshsahu/pen/jpGLpq/
Without Error Handeling
With Error Handling
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq/
使用TextureLoader 将图像加载为纹理,然后将该纹理简单地应用到场景背景。
结果:
https://codepen.io/hiteshsahu/pen/jpGLpq?editors=0011< /a>
See the Pen Flat Earth Three.JS by Hitesh Sahu (@hiteshsahu) on CodePen.
Use TextureLoader to load a image as texture and then simply apply that texture to scene background.
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq?editors=0011
See the Pen Flat Earth Three.JS by Hitesh Sahu (@hiteshsahu) on CodePen.