草庐IT

javascript - 如何为 BufferGeometry 面添加纹理。?

coder 2025-01-04 原文

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


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 );

}

现在不用为每个平面着色我如何向每个平面添加文本。假设我只想在每个平面的中心显示 1、2、3、4、5。

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

  • 从 Canvas 生成纹理
  • 使用 map:texture 将 Material 更改为 Shader Material
  • uv 添加到 bufferGeometry。

但是uv和texture有什么关系。

我有纹理创建功能

//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;
}

完整 DEMO Code

编辑

我正在考虑将性能作为此实验的高优先级。我们可以为每个文本添加每个网格,但这会增加屏幕中的网格数量并降低性能。我正在寻找在我的示例中使用单个网格的任何想法

我找到的最接近的是 this ,但我不明白他们使用的确切技术。

最佳答案

您必须复制 .faceVertexUvs 的第一个 uv channel 属性形式 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() );
        }
    } );
}

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

.addGroup 定义组(参见 THREE.BufferGeometry) .每个组将一系列顶点与 Material 相关联。

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 );  

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 );
}
<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>

关于javascript - 如何为 BufferGeometry 面添加纹理。?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55472178/

有关javascript - 如何为 BufferGeometry 面添加纹理。?的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  3. ruby - 如何为 emacs 安装 ruby​​-mode - 2

    我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby​​提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

  6. ruby - 如何在 Ruby 中向现有方法定义添加语句 - 2

    我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca

  7. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  8. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  9. ruby-on-rails - 在 Ruby on Rails 中添加 boolean 列值 - 2

    我正在开发一个创建网络博客的RubyonRails项目。我希望将一个名为featured的boolean数据库字段添加到Post模型中。该字段应该可以通过我添加的事件管理界面进行编辑。我使用了以下代码,但我什至没有在网站上显示另一列。$railsgeneratemigrationaddFeaturedfeatured:boolean$rakedb:migrate我是RubyonRails的新手,非常感谢任何帮助。我的index.html.erb文件中的相关代码(views):FeaturedPost架构.rb:ActiveRecord::Schema.define(:version=>

  10. ruby - 如何将便捷类方法添加到 ruby​​ 中的 Singleton 类 - 2

    假设我有一个这样的单例类:classSettingsincludeSingletondeftimeout#lazy-loadtimeoutfromconfigfile,orwhateverendend现在,如果我想知道使用什么超时,我需要编写如下内容:Settings.instance.timeout但我宁愿将其缩短为Settings.timeout使这项工作有效的一个明显方法是将设置的实现修改为:classSettingsincludeSingletondefself.timeoutinstance.timeoutenddeftimeout#lazy-loadtimeoutfromc

随机推荐