我正在使用InstanceGeometry渲染场景中的数千个基本几何(框)。它是高效的,仅使用一种材质/纹理,但会为每个实例重复图像纹理。
我正在尝试找出如何使纹理分布在x个实例上。假设有8个盒子实例,我希望1/8的纹理出现在每个盒子上。
我认为THREE.Texture上的transformUV函数是我想使用的,但是我不确定如何在这种情况下使用它。或者,纹理映射是否会在Shader本身中发生?
更新
我自己的代码非常复杂,并且使用了适合实例的内置three.js材料,因此让我们仅使用Three.js示例之一作为起点:https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_instancing_dynamic.html
也简短地粘贴在下面。
顶点着色器:
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
// http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}
void main() {
vec3 vPosition = applyQuaternionToVector( orientation, position );
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
}
片段着色器
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( map, vUv );
}
JS:
var instances = 50;
var bufferGeometry = new THREE.BoxBufferGeometry( 2, 2, 2 );
var geometry = new THREE.InstancedBufferGeometry();
geometry.index = bufferGeometry.index;
geometry.attributes.position = bufferGeometry.attributes.position;
geometry.attributes.uv = bufferGeometry.attributes.uv;
// per instance data
var offsets = [];
var orientations = [];
var vector = new THREE.Vector4();
var x, y, z, w;
for ( var i = 0; i < instances; i ++ ) {
// offsets
x = Math.random() * 100 - 50;
y = Math.random() * 100 - 50;
z = Math.random() * 100 - 50;
vector.set( x, y, z, 0 ).normalize();
vector.multiplyScalar( 5 );
offsets.push( x + vector.x, y + vector.y, z + vector.z );
// orientations
x = Math.random() * 2 - 1;
y = Math.random() * 2 - 1;
z = Math.random() * 2 - 1;
w = Math.random() * 2 - 1;
vector.set( x, y, z, w ).normalize();
orientations.push( vector.x, vector.y, vector.z, vector.w );
}
offsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( offsets ), 3 );
orientationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( orientations ), 4 ).setDynamic( true );
geometry.addAttribute( 'offset', offsetAttribute );
geometry.addAttribute( 'orientation', orientationAttribute );
// material
var material = new THREE.ShaderMaterial( {
uniforms: {
map: { value: new THREE.TextureLoader().load( 'textures/crate.gif' ) } },
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
答案 0 :(得分:2)
您将不得不创建一个附加的自定义属性来保存UV的偏移量,就像您要创建一个包含x, y, z
偏移量但带有u, v
的属性一样。
首先,您将其添加到JavaScript中:
var uvOffsets = [];
var u, v;
for ( var i = 0; i < instances; i ++ ) {
//... inside the loop
u = Math.random(); // I'm assigning random, but you can do the math...
v = Math.random(); // ... to make it discrete 1/8th amounts
uvOffsets.push(u, v);
}
// Add new attribute to BufferGeometry
var uvOffsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( uvOffsets ), 2 );
geometry.addAttribute( 'uvOffset', uvOffsetAttribute );
然后,在您的顶点着色器中:
// [...]
attribute vec2 uv;
attribute vec2 uvOffset;
varying vec2 vUv;
void main() {
vec3 vPosition = applyQuaternionToVector( orientation, position );
// Divide uvs by 8, and add assigned offsets
vUv = (uv / 8.0) + uvOffset;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
}
最后,在您的片段着色器中:
precision highp float;
uniform sampler2D map;
uniform vec2 uvOffset;
varying vec2 vUv; // <- these UVs have been transformed by vertex shader.
void main() {
gl_FragColor = texture2D( map, vUv ); // <- Transformation is applied to texture
}