InstanceGeometry 中的three.js 纹理 [英] three.js texture across InstanceGeometry

查看:26
本文介绍了InstanceGeometry 中的three.js 纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 InstanceGeometry 在场景中渲染数千个基本几何图形(框).它很高效并且只使用 1 种材质/纹理,但对每个实例重复图像纹理.

I'm using InstanceGeometry to render thousands of base geometries (boxes) in a scene. It's efficient and uses only 1 material/texture, but repeats the image texture for every instance.

我想弄清楚如何将纹理分布在 x 个实例上.比如说有 8 个盒子实例,我希望 1/8 的纹理出现在每个盒子上.

I'm trying to figure out how to have the texture spread out over x number of instances. Say for example there's 8 box instances, I'd like to 1/8 of the texture to appear on every box.

我认为 THREE.Texture 上的 transformUV 函数是我想要使用的,但我不确定如何在这种情况下使用它.或者,纹理映射会在着色器本身中发生吗?

I think the transformUV function on THREE.Texture is what I'd want to use, but I'm not sure how to use it in this context. OR, would the texture mapping happen in the Shader itself?

更新

我自己的代码比较复杂,使用了适合实例的内置three.js材料,所以我们只使用三个.js示例之一作为起点:https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_instancing_dynamic.html

My own code is pretty involved and uses the built-in three.js materials adapted for instances, so let's just use one of the three.js examples as a starting point: 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 );

推荐答案

您将不得不创建一个额外的自定义属性来保存 UV 的偏移量,就像您创建一个保存 的属性一样x, y, z 偏移,但带有 u, v.

You're going to have to create an additional custom attribute that holds the offset of UVs, just like you're creating an attribute that holds the x, y, z offsets, but with 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
}

这篇关于InstanceGeometry 中的three.js 纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆