如何在BufferGeometry面上添加纹理?

Sar*_*ath 6 javascript texture-mapping three.js

我创建了一个bufferGeometry,它由5个平面组成,(100x25)每个平面带有两个三角形。

在此处输入图片说明


function createGeometry() {
  var geometry = new THREE.PlaneGeometry(100, 25, 1);
  return geometry;
}

function createScene() {

    var bufferGeometry = new THREE.BufferGeometry();
    var radius = 125;
    var count = 5;

    var positions = [];
    var normals = [];
    var colors = [];

    var vector = new THREE.Vector3();
    var color = new THREE.Color( 0xffffff );
    var heartGeometry = createGeometry();
    var geometry = new THREE.Geometry();

    var step = 0;
    for ( var i = 1, l = count; i <= l; i ++ ) {

        geometry.copy( heartGeometry );

        const y = i * 30
        geometry.translate(-100, y, 0);

        // color.setHSL( ( i / l ), 1.0, 0.7 );

        geometry.faces.forEach( function ( face ) {
            positions.push( geometry.vertices[ face.a ].x );
            positions.push( geometry.vertices[ face.a ].y );
            positions.push( geometry.vertices[ face.a ].z );
            positions.push( geometry.vertices[ face.b ].x );
            positions.push( geometry.vertices[ face.b ].y );
            positions.push( geometry.vertices[ face.b ].z );
            positions.push( geometry.vertices[ face.c ].x );
            positions.push( geometry.vertices[ face.c ].y );
            positions.push( geometry.vertices[ face.c ].z );

            normals.push( face.normal.x );
            normals.push( face.normal.y );
            normals.push( face.normal.z );
            normals.push( face.normal.x );
            normals.push( face.normal.y );
            normals.push( face.normal.z );
            normals.push( face.normal.x );
            normals.push( face.normal.y );
            normals.push( face.normal.z );

            colors.push( color.r );
            colors.push( color.g );
            colors.push( color.b );
            colors.push( color.r );
            colors.push( color.g );
            colors.push( color.b );
            colors.push( color.r );
            colors.push( color.g );
            colors.push( color.b );

        });
    }
    bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
    bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
    bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );


    var material = new THREE.MeshBasicMaterial({
        vertexColors: THREE.VertexColors,
        side: THREE.FrontSide
    });

    var mesh = new THREE.Mesh( bufferGeometry, material );
    scene.add( mesh );

}

Run Code Online (Sandbox Code Playgroud)

现在,除了给每个平面着色之外,我如何向每个平面添加文本。假设我只想在每个平面的中心显示1,2,3,4,5。

我知道的是,必须执行以下操作才能添加纹理。

  • 从画布生成纹理
  • 使用以下方法将材质更改为“着色器材质” map:texture
  • uvs 添加到bufferGeometry。

但是uvs和纹理之间是什么关系。

我有纹理创建功能

//not sure for each character or one texture as a single texture
function createTexture(ch){

  var fontSize = 20;
  var c = document.createElement('canvas');
  c.width = 100;
  c.height = 25;
  var ctx = c.getContext('2d');
  ctx.font = fontSize+'px Monospace';
  ctx.fillText(ch, c.width/2, c.height/2);

  var texture = new THREE.Texture(c);
  texture.flipY = false;
  texture.needsUpdate = true;

  return texture;
}
Run Code Online (Sandbox Code Playgroud)

完整的演示代码

编辑

我认为性能是该实验的最高优先级。我们可以为每个文本添加每个网格,但这会增加屏幕中的网格数量并降低性能。我正在寻找与示例相同的单个网格的任何想法

我发现的最接近的是这个,但我不了解他们使用的确切技术。

Rab*_*d76 3

您必须从 中复制.faceVertexUvs属性的第一个 uv 通道THREE.Geometry,类似于使用顶点坐标和法向量:

for ( var i = 1, l = count; i <= l; i ++ ) {

    geometry.copy( heartGeometry );

    const y = i * 30
    geometry.translate(-100, y, 0);

    geometry.faces.forEach( function ( face ) {
        let f = [face.a, face.b, face.c];
        for (let i=0; i < 3; ++i) {
            positions.push( ...geometry.vertices[f[i]].toArray() );
            normals.push( ...face.normal.toArray() );
            colors.push( ...color.toArray() );
        }
    } );

    geometry.faceVertexUvs[0].forEach( function ( faceUvs ) {
        for (let i=0; i < 3; ++i) {
            uv.push( ...faceUvs[i].toArray() );
        }
    } );
}
Run Code Online (Sandbox Code Playgroud)

如果您想为一个几何体定义多个纹理,那么您必须THREE.Material为一个几何体使用多个纹理THREE.Mesh

为定义组(请参阅.addGroupTHREE.BufferGeometry。每个组将一定范围的顶点与材质相关联。

var bufferGeometry = new THREE.BufferGeometry();
bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
bufferGeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );

let materials = []
let v_per_group= positions.length / 3 / count;
for ( var i = 0; i < count; i ++ ) {
    bufferGeometry.addGroup(i * v_per_group, v_per_group, i);

    let material = new THREE.MeshBasicMaterial({ 
        vertexColors: THREE.VertexColors,
        side: THREE.FrontSide,
        map : createTexture("button" + (i+1))
    });
    materials.push(material);
}

var mesh = new THREE.Mesh( bufferGeometry, materials );
scene.add( mesh );  
Run Code Online (Sandbox Code Playgroud)

var camera, scene, renderer, controls, stats;
init();
animate();


function init() {
  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera( 45.0, window.innerWidth / window.innerHeight, 100, 1500.0 );
  camera.position.z = 480.0;
  scene.add( camera );
  controls = new THREE.TrackballControls( camera, renderer.domElement );
  controls.minDistance = 100.0;
  controls.maxDistance = 800.0;
  controls.dynamicDampingFactor = 0.1;
  
  scene.add( new THREE.AmbientLight( 0xffffff, 1 ) );
  
  createScene();
  //stats = new Stats();
  //document.body.appendChild( stats.dom );
  window.addEventListener( 'resize', onWindowResize, false );
}

function createGeometry() {
  var geometry = new THREE.PlaneGeometry(100, 25, 1);
  return geometry;
}

function createTexture(ch){

  var fontSize = 20;
  var c = document.createElement('canvas');
  c.width = 128;
  c.height = 32;
  var ctx = c.getContext('2d');
  
  ctx.beginPath();
  ctx.rect(0, 0, 128, 32);
  ctx.fillStyle = "white";
  ctx.fill();

  ctx.fillStyle = "black";
  ctx.font = fontSize+'px Monospace';
  ctx.fillText(ch, 20, 24);

  var texture = new THREE.Texture(c);
  texture.flipY = true;
  texture.needsUpdate = true;

  return texture;
}

function createScene() {
  
  var radius = 125;
  var count = 5;
  
  var vector = new THREE.Vector3();
  var color = new THREE.Color( 0xffffff );
  var heartGeometry = createGeometry();
  var geometry = new THREE.Geometry();
  
  var positions = [];
  var normals = [];
  var colors = [];
  var uv = [];

  for ( var i = 1, l = count; i <= l; i ++ ) {

      geometry.copy( heartGeometry );

      const y = i * 30
      geometry.translate(-100, y, 0);

      geometry.faces.forEach( function ( face ) {
          let f = [face.a, face.b, face.c];
          for (let i=0; i < 3; ++i) {
              positions.push( ...geometry.vertices[f[i]].toArray() );
              normals.push( ...face.normal.toArray() );
              colors.push( ...color.toArray() );
          }
      } );

      geometry.faceVertexUvs[0].forEach( function ( faceUvs ) {
          for (let i=0; i < 3; ++i) {
              uv.push( ...faceUvs[i].toArray() );
          }
      } );
  }

  var bufferGeometry = new THREE.BufferGeometry();
  bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
  bufferGeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
  bufferGeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
  bufferGeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv, 2 ) );

  let materials = []
  let v_per_group = positions.length / 3 / count;
  for ( var i = 0; i < count; i ++ ) {
      bufferGeometry.addGroup(i * v_per_group, v_per_group, i);
      
      let material = new THREE.MeshBasicMaterial({ 
          vertexColors: THREE.VertexColors,
          side: THREE.FrontSide,
          map : createTexture("button" + (i+1))
      });
      materials.push(material);
  }
      
  var mesh = new THREE.Mesh( bufferGeometry, materials );
  scene.add( mesh );   
}
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
  requestAnimationFrame( animate );
  controls.update();
  //stats.update();
  renderer.render( scene, camera );
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
Run Code Online (Sandbox Code Playgroud)