three.js 中的同步与异步纹理加载
synch vs. asynch texture loading in three.js
我在午餐时间一直在玩 Three.js,实现旧的 NEHE 演示(到目前为止最多 #30)。令人讨厌的一方面是新的异步纹理加载器。我有一个着色器 material 演示,其中 material 是这样创建的:
var uniforms = {
tOne: { type: "t", value: THREE.ImageUtils.loadTexture( "images/cover.png" ) },
tSec: { type: "t", value: THREE.ImageUtils.loadTexture( "images/grass.png" ) }
};
var material_shh = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var mesh = new THREE.Mesh( cubeGeom, material_shh );
gfxScene.add(mesh);
这工作正常,但 three.js 在控制台中向我抱怨说 loadTexture 已被弃用。 (为什么?)。无论如何,我可以这样写它来使用 textureLoader:
var textureLoader = new THREE.TextureLoader();
var cover, grass;
textureLoader.load( "images/cover.png", function( texture ) {
cover = texture;
});
textureLoader.load( "images/grass.png", function( texture ) {
grass = texture;
var uniforms = {
tOne: { type: "t", value: cover },
tSec: { type: "t", value: grass }
};
var material_shh = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var mesh = new THREE.Mesh( cubeGeom, material_shh );
gfxScene.add(mesh);
});
这也行,但似乎相当复杂。我知道异步对 Web 应用程序等有好处,但是......它假设我保证 cover.png 将在 grass.png 之前加载。这实际上有保证吗?我宁愿坚持使用同步 loadTexture 实用程序,但也许有充分的理由不使用 loadTexture(除了它已被弃用)。 TIA.
TextureLoader.load()
returns 纹理对象,所以如果您不关心同步负载,那么您可以以相同的方式使用新的 TextureLoader
:
var textureLoader = new THREE.TextureLoader();
var uniforms = {
tOne: {type: "t", value: textureLoader.load("images/cover.png")},
tSec: {type: "t", value: textureLoader.load("images/grass.png")}
};
编辑 #1
对于同步加载,您可以使用 LoadingManager
。目前它不是最优雅的 API,但它应该适用于简单的情况。此示例适用于版本 r84
.
function loadTextures(urls, callback) {
var textures = [];
var onLoad = function() {
callback(null, textures);
};
var onProgress = function() {};
var onError = function(url) {
callback(new Error('Cannot load ' + url));
};
var manager = new THREE.LoadingManager(onLoad, onProgress, onError);
var loader = new THREE.TextureLoader(manager);
for (var i=0; i<urls.length; i++) {
textures.push(loader.load(urls[i]));
}
}
var urls = [
"images/cover.png",
"images/grass.png"
];
loadTextures(urls, function(error, textures) {
if (error) {
console.log(error);
return;
}
// Main code goes here using the textures array
});
我的做法:
let urls = [
'img/right.jpg',//right
'img/left.jpg',//left
'img/top.jpg',//top
'img/top.jpg',//bottom
'img/front.jpg',//front
'img/front.jpg',//back
];
function loadTextures(urls) {
return new Promise((resolve, reject) => {
let textures = [];
let onLoad = function () {
resolve(textures);
};
let onProgress = function () { };
let onError = function (url) {
resolve(false);
};
let manager = new THREE.LoadingManager(onLoad, onProgress, onError);
for (let i = 0; i < urls.length; i++) {
let url = urls[i];
let loader = new THREE.TextureLoader(manager);
textures[i] = loader.load(url);
console.log('textures 0', textures, url);
}
});
}
然后,在初始化函数中:
let init = async function () {
let textures = await loadTextures(urls);
if (textures) {
let materials = [];
for (var i = 0; i < textures.length; i++) {
materials[i] = new THREE.MeshPhongMaterial({
color: 0xf0f0f0,
map: textures[i]
});
}
box = new THREE.Mesh(geometryBox, materials);
scene.add(box);
}
}
我在午餐时间一直在玩 Three.js,实现旧的 NEHE 演示(到目前为止最多 #30)。令人讨厌的一方面是新的异步纹理加载器。我有一个着色器 material 演示,其中 material 是这样创建的:
var uniforms = {
tOne: { type: "t", value: THREE.ImageUtils.loadTexture( "images/cover.png" ) },
tSec: { type: "t", value: THREE.ImageUtils.loadTexture( "images/grass.png" ) }
};
var material_shh = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var mesh = new THREE.Mesh( cubeGeom, material_shh );
gfxScene.add(mesh);
这工作正常,但 three.js 在控制台中向我抱怨说 loadTexture 已被弃用。 (为什么?)。无论如何,我可以这样写它来使用 textureLoader:
var textureLoader = new THREE.TextureLoader();
var cover, grass;
textureLoader.load( "images/cover.png", function( texture ) {
cover = texture;
});
textureLoader.load( "images/grass.png", function( texture ) {
grass = texture;
var uniforms = {
tOne: { type: "t", value: cover },
tSec: { type: "t", value: grass }
};
var material_shh = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertShader,
fragmentShader: fragShader
});
var mesh = new THREE.Mesh( cubeGeom, material_shh );
gfxScene.add(mesh);
});
这也行,但似乎相当复杂。我知道异步对 Web 应用程序等有好处,但是......它假设我保证 cover.png 将在 grass.png 之前加载。这实际上有保证吗?我宁愿坚持使用同步 loadTexture 实用程序,但也许有充分的理由不使用 loadTexture(除了它已被弃用)。 TIA.
TextureLoader.load()
returns 纹理对象,所以如果您不关心同步负载,那么您可以以相同的方式使用新的 TextureLoader
:
var textureLoader = new THREE.TextureLoader();
var uniforms = {
tOne: {type: "t", value: textureLoader.load("images/cover.png")},
tSec: {type: "t", value: textureLoader.load("images/grass.png")}
};
编辑 #1
对于同步加载,您可以使用 LoadingManager
。目前它不是最优雅的 API,但它应该适用于简单的情况。此示例适用于版本 r84
.
function loadTextures(urls, callback) {
var textures = [];
var onLoad = function() {
callback(null, textures);
};
var onProgress = function() {};
var onError = function(url) {
callback(new Error('Cannot load ' + url));
};
var manager = new THREE.LoadingManager(onLoad, onProgress, onError);
var loader = new THREE.TextureLoader(manager);
for (var i=0; i<urls.length; i++) {
textures.push(loader.load(urls[i]));
}
}
var urls = [
"images/cover.png",
"images/grass.png"
];
loadTextures(urls, function(error, textures) {
if (error) {
console.log(error);
return;
}
// Main code goes here using the textures array
});
我的做法:
let urls = [
'img/right.jpg',//right
'img/left.jpg',//left
'img/top.jpg',//top
'img/top.jpg',//bottom
'img/front.jpg',//front
'img/front.jpg',//back
];
function loadTextures(urls) {
return new Promise((resolve, reject) => {
let textures = [];
let onLoad = function () {
resolve(textures);
};
let onProgress = function () { };
let onError = function (url) {
resolve(false);
};
let manager = new THREE.LoadingManager(onLoad, onProgress, onError);
for (let i = 0; i < urls.length; i++) {
let url = urls[i];
let loader = new THREE.TextureLoader(manager);
textures[i] = loader.load(url);
console.log('textures 0', textures, url);
}
});
}
然后,在初始化函数中:
let init = async function () {
let textures = await loadTextures(urls);
if (textures) {
let materials = [];
for (var i = 0; i < textures.length; i++) {
materials[i] = new THREE.MeshPhongMaterial({
color: 0xf0f0f0,
map: textures[i]
});
}
box = new THREE.Mesh(geometryBox, materials);
scene.add(box);
}
}