【问题标题】:Merging Text geometries in Three.js while keeping individual material colors在 Three.js 中合并文本几何图形,同时保持单独的材质颜色
【发布时间】:2017-02-06 06:09:32
【问题描述】:

我正在尝试在 Three.js (r84) 中合并文本几何。我需要使用 multiMaterial 并为每个文本对象保留单独的颜色。这是一个现场演示。 https://jsfiddle.net/5oydk6nL/

谢谢。

var $win = $( window ) ,
    $container = $( '#webGL-container' ) ,

    scene , camera , cameraTarget , renderer ,
    pointLight , hex ,
    stats , rendererStats ,

    typeface = 'https://cdn.rawgit.com/redwavedesign/ca97268140e8a51633595cd34bb77f16/raw/46ae61687ac8e7e3af01ee2c983580f2b0b0809f/bebas_regular.json';



/* text objects */

var a = {
    text: 'a' ,
    color: 'red' ,
    x: -90
}

var b = {
    text: 'b' ,
    color: 'blue' ,
    x: -60
}

var c = {
    text: 'c' ,
    color: 'green' ,
    x: -30
}

var d = {
    text: 'd' ,
    color: 'yellow' ,
    x: 0
}

var e = {
    text: 'e' ,
    color: 'purple' ,
    x: 30
}

var f = {
    text: 'f' ,
    color: 'orange' ,
    x: 60
}

var g = {
    text: 'g' ,
    color: 'aqua' ,
    x: 90
}




// array with all text objects
var letters = [ a , b , c , d , e , f , g ];




function decimalToHex( d ) {

    var hex = Number( d ).toString( 16 );
    hex = "000000".substr( 0, 6 - hex.length ) + hex;
    return hex.toUpperCase();

}




function init() {


    /* create scene, camera and renderer */
    scene = new THREE.Scene();
    camera =  new THREE.PerspectiveCamera( 40 , window.innerWidth / window.innerHeight , .1 , 1500 );
    renderer = new THREE.WebGLRenderer({ antialias: true });

    /* setup renderer */
    renderer.setClearColor( '#ffffff' );
    renderer.setSize( window.innerWidth , window.innerHeight );
    renderer.shadowMap.enabled = true;
    renderer.shadowMapSoft = true;

    /* setup camera */
    camera.position.x = 0;
    camera.position.y = 0;
    camera.position.z = 500;

    cameraTarget = new THREE.Vector3( 0 , 0 , 0 );

    /* Lights */
    pointLight = new THREE.PointLight( 0xffffff, 2 );
    pointLight.position.set( 20 , -300 , 200 );
    scene.add( pointLight );

    pointLight.color.setStyle( '#EBEBEB' );
    hex = decimalToHex( pointLight.color.getHex() );


    // load each text object from the 'letters' array
    $.each( letters , function( index , letter ) {


        var fontLoader = new THREE.FontLoader();


        // load font
        fontLoader.load( typeface , function ( font ) {


            var geometry = new THREE.TextGeometry( letter.text , {

                    font: font,
                    height: 8 ,
                    size: 28 ,
                    curveSegments: 4 ,
                    bevelThickness: 1,
                    bevelSize: 1.5 ,
                    bevelSegments: 3 ,
                    bevelEnabled: true ,
                    material: 0,
                    extrudeMaterial: 1

            });


            var material = new THREE.MultiMaterial( [
                new THREE.MeshPhongMaterial( { color: letter.color , shading: THREE.FlatShading } ), // front
                new THREE.MeshPhongMaterial( { color: letter.color , shading: THREE.SmoothShading } ) // side
            ] );


            var mesh = new THREE.Mesh( geometry , material );


            mesh.position.set( letter.x , 0 , 0 );


            // add text object to scene
            scene.add( mesh );


        });


    // end of each loop
    });


    // add the rendered element to the page
    $container.append( renderer.domElement );


}




function render() {

    camera.lookAt( cameraTarget );

    renderer.clear();

    renderer.render( scene , camera );

}



function animate() {

    // begin Three.js stats utility
    stats.begin();

    requestAnimationFrame( animate );

    render();

    // update Threex stats plugin
    rendererStats.update( renderer );

    // conclude sample for Three.js stats testing
    stats.end();

}



// performance monitoring

rendererStats = new THREEx.RendererStats();
rendererStats.domElement.style.position = 'absolute'
rendererStats.domElement.style.left = '0px'
rendererStats.domElement.style.bottom = '0px'
document.body.appendChild( rendererStats.domElement );

stats = new Stats();
    stats.showPanel( 0 );
    document.body.appendChild( stats.domElement );
    document.body.appendChild( stats.dom );



// initialize 
init();

// animate
animate();

【问题讨论】:

标签: javascript three.js


【解决方案1】:

Here an updated fiddle.

需要补充几点:

1) 创建多材质并为每个字母添加材质:

var material = new THREE.MeshPhongMaterial({
    color: letter.color,
    shading: THREE.FlatShading
});

multiMaterial.materials.push(material);

2) 为每个字母的所有面添加材质索引:

for (var i = 0, il = geometry.faces.length; i < il; i++) {
    geometry.faces[i].materialIndex = index
}

3) 使用变换矩阵将几何 x 向右平移:

geometry.applyMatrix(
    matrix.makeTranslation(letter.x, 0, 0)
);

4) 将每个字母几何体合并为一个几何体:

mergedGeometry.merge(geometry);

现在你有一个合并的几何:


注意:下次尽量避免在你的小提琴中使用 jQuery,这个额外的库对于你的例子来说不是必需的。另请阅读here in these guidelines for more information

【讨论】:

  • 合并使用不同材料的几何图形没有意义。请注意,您仍然有 7 个绘图调用。
  • @WestLangley 好的,我只是回答了这个问题,这段代码就可以了。但我对你对此的看法很感兴趣。如果在这种情况下使用它“没有意义”,您能否解释一下THREE.MultiMaterial 的目的是什么?是否还有其他使用此类有意义的用户案例?您能否详细说明答案。如果您分享更多有关此的信息,将会很有用。
  • (1) MultiMaterial 的存在是为了方便用户支持支持材料组的 OBJLoader 等加载程序。 (2) GPU 一次只能使用一个着色器,因此每种材质都必须有一个绘制调用。 (3) 合并共享相同材料的几何图形是有意义的。
  • 一个好的shaderMaterial可以在哪里创造奇迹,解决drawcall问题
  • 是的,看看this fiddle,不同的颜色,1个drawcall。这个简单的 shaderMaterial 只有在字母没有在 x 轴上移动时才有效,但为了举例,它应该可以。
猜你喜欢
  • 1970-01-01
  • 2015-01-28
  • 1970-01-01
  • 2019-05-30
  • 2013-04-20
  • 2013-06-11
  • 2015-01-19
  • 2021-10-25
  • 2012-11-20
相关资源
最近更新 更多