Javascript Three.js:将纹理数组传递给shaderMaterial

Javascript Three.js:将纹理数组传递给shaderMaterial,javascript,opengl-es,three.js,glsl,shader,Javascript,Opengl Es,Three.js,Glsl,Shader,简短问题:如何将纹理列表传递给着色器并访问片段着色器中的第n个纹理(其中n是作为顶点着色器的变量传递的值) 更长的问题:我正在开发一个表示多个图像的Three.js。每个图像使用多个纹理中的一个,每个纹理是一个包含多个缩略图的图集。我正在努力实现自定义着色器材质以优化性能,但对如何在着色器中使用多个纹理感到困惑 我的目标是传递一个纹理列表和一个表示每个纹理的顶点数的数字,以便我可以识别应该用于每个图像顶点/像素的纹理。我想我可以通过传递以下数据来实现这一点: // Create a textur

简短问题:如何将纹理列表传递给着色器并访问片段着色器中的第n个纹理(其中n是作为顶点着色器的变量传递的值)

更长的问题:我正在开发一个表示多个图像的Three.js。每个图像使用多个纹理中的一个,每个纹理是一个包含多个缩略图的图集。我正在努力实现自定义着色器材质以优化性能,但对如何在着色器中使用多个纹理感到困惑

我的目标是传递一个纹理列表和一个表示每个纹理的顶点数的数字,以便我可以识别应该用于每个图像顶点/像素的纹理。我想我可以通过传递以下数据来实现这一点:

// Create a texture loader so we can load our image file
var loader = new THREE.TextureLoader();

// specify the url to the texture
var catUrl = 'https://s3.amazonaws.com/duhaime/blog/tsne-webgl/assets/cat.jpg';
var dogUrl = 'https://s3.amazonaws.com/duhaime/blog/tsne-webgl/assets/dog.jpg';

var material = new THREE.ShaderMaterial({  
  uniforms: {

    verticesPerTexture: new Float32Array([4.0]), // count of vertices per texture

    textures: {
      type: 'tv', // type for texture array
      value: [loader.load(catUrl), loader.load(dogUrl)],
    }
  },
  vertexShader: document.getElementById('vertex-shader').textContent,
  fragmentShader: document.getElementById('fragment-shader').textContent
});
但是,如果我这样做,顶点着色器似乎无法使用一致性来告诉片段着色器应该使用哪个纹理,因为顶点着色器显然无法将采样2D对象作为变量传递给片段着色器。如何将纹理列表传递给着色器

完整代码(未成功传递纹理列表):

/**
*生成具有背景色的场景对象
**/
函数getScene(){
var scene=new THREE.scene();
scene.background=新的三种颜色(0xffffff);
返回场景;
}
/**
*生成要在场景中使用的摄影机。摄像机参数:
*[0]视野:标识场景的部分
*随时可见(以度为单位)
*[1]纵横比:标识图像的纵横比
*场景的宽度/高度
*[2]近剪裁平面:比近剪裁平面更近的对象
*剪裁平面将从场景中剔除
*[3]远剪裁平面:比远剪裁平面更远的对象
*剪裁平面将从场景中剔除
**/
函数getCamera(){
var aspectRatio=window.innerWidth/window.innerHeight;
var摄像机=新的三视角摄像机(75,aspectRatio,0.11000);
摄像机位置设置(0,1,10);
返回摄像机;
}
/**
*生成要在场景中使用的渲染器
**/
函数getRenderer(){
//使用渲染器创建画布
var renderer=new THREE.WebGLRenderer({antialas:true});
//添加对视网膜显示的支持
renderer.setPixelRatio(window.devicePixelRatio);
//指定画布的大小
renderer.setSize(window.innerWidth、window.innerHeight);
//将画布添加到DOM中
document.body.appendChild(renderer.doElement);
返回渲染器;
}
/**
*生成要在场景中使用的控件
*@param{obj}camera:用于场景的三个.js摄影机
*@param{obj}渲染器:场景的三个.js渲染器
**/
函数控件(摄影机、渲染器){
var controls=新的三个.trackball控件(摄影机、渲染器.domElement);
controls.zoomSpeed=0.4;
控制点速度=0.4;
返回控制;
}
/**
*加载图像
**/
函数loadImage(){
var geometry=new THREE.BufferGeometry();
/*
现在我们需要将一些顶点推入该几何体,以确定几何体应该覆盖的坐标
*/
//确定图像大小
var imageSize={宽度:10,高度:7.5};
//确定图像应放置的x、y、z坐标
var-coords={x:-5,y:-3.75,z:0};
//使用
//以下顺序:左下、右下、右上、左上
var顶点=新数组([
coords.x,coords.y,coords.z,//左下角
coords.x+imageSize.width,coords.y,coords.z,//右下角
coords.x+imageSize.width,coords.y+imageSize.height,coords.z,//右上角
coords.x,coords.y+imageSize.height,coords.z,//左上角
])
//设置此长方体的UV;这些UV标识以下角点:
//左下、右下、右上、左上
var uvs=新的浮点数组([
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
])
//存储要渲染的每个对象的纹理索引
var textureIndices=新的Float32Array([0.0,0.0,0.0,0.0]);
//索引=用作顶点的“顶点”中的索引位置序列
//我们制作了两个三角形,但只在对象中使用了4个不同的顶点
//THREE.BufferAttribute的第二个参数是元素数
//在每个顶点的第一个参数中
geometry.setIndex([0,1,2,2,3,0])
geometry.addAttribute('position',新的三个.BufferAttribute(顶点,3));
geometry.addAttribute('uv',新的三个.BufferAttribute(uvs,2));
//创建一个纹理加载器,这样我们就可以加载我们的图像文件
var loader=new THREE.TextureLoader();
//指定纹理的url
var catUrl=https://s3.amazonaws.com/duhaime/blog/tsne-webgl/assets/cat.jpg';
var dogUrl=https://s3.amazonaws.com/duhaime/blog/tsne-webgl/assets/dog.jpg';
//为着色器指定自定义制服和属性
//统一类型:https://github.com/mrdoob/three.js/wiki/Uniforms-types
var material=new THREE.ShaderMaterial({
制服:{
verticesPerTexture:new Float32Array([4.0]),//存储每个纹理的顶点数
cat_纹理:{
类型:“t”,
值:loader.load(catUrl),
},
狗纹:{
类型:“t”,
值:loader.load(dogUrl),
},
纹理:{
类型:“tv”,//纹理数组的类型
值:[loader.load(catUrl),loader.load(dogUrl)],
}
},
vertexShader:document.getElementById('vertex-shader').textContent,
fragmentShader:document.getElementById('fragment-shader').textContent
});
//将图像几何体和材质组合成网格
var mesh=新的三个网格(几何体、材质);
//设置图像网格在x、y、z标注中的位置
网格位置设置(0,0,0)
//将图像添加到场景中
场景。添加(网格);
}
/**
*渲染!
**/
函数render(){
请求动画帧(渲染);
渲染器。渲染(场景、摄影机);
控件更新();
};
var scene=getScene();
var-camera=getCamera();
var renderer=getRenderer();
var controls=getControl
geometry.addAttribute( 'texIndex', new THREE.BufferAttribute( [ 0, 0, 0, 0, 1, 1, 1, 1 ], 1 ) )
attribute int texIndex;
varying int vTexIndex;
void main () { vTexIndex = texIndex; }
varying int vTexIndex;
uniform sampler2D textures[ 2 ];
...
sampler2D tex = textures[ vTexIndex ];
function createMaterial ( texture ) {
    return new ShaderMaterial({
        uniforms: {
            texture: { value: texture }
        }
    })
}

var mat1 = createMaterial( dogTexture );
var mat2 = createMaterial( catTexture );

geometry.faces[ 0 ].materialIndex = 0;
geometry.faces[ 1 ].materialIndex = 0;
geometry.faces[ 2 ].materialIndex = 1;
geometry.faces[ 3 ].materialIndex = 1;

var mesh = new Mesh( geometry, [ mat1, mat2 ] );