Help us understand the problem. What is going on with this article?

EmissiveMapを使ってマイクラのエンチャントを再現する

More than 1 year has passed since last update.

EmissiveMapとは

テクスチャマップを部分的に光っているようにみせることができるマッピング画像で、Three.jsでは MeshPhongMaterialや、MeshLambertMaterialなどのoptionで指定することができます。
AlphaMapと同じグレイスケールの画像で、白い部分はemissiveプロパティに指定した色で光って見えるようになり、黒い部分は元のまま表示されます。

EmissiveMapは、テクスチャに部分的に色を乗せるイメージではなく、半透明レイヤーのように独立しているイメージです。
またMeshBasicMaterialのようにライティングの影響を受けないため、暗いライティングでも光って見えます。

指定方法

    // マテリアルの作成
    let material = new THREE.MeshLambertMaterial({
        map: texture,
        emissiveMap: emissiveTexture, /// グレイスケールのTHREE.Textureオブジェクト
        emissive: "#FF0000", /// 光らせたい色
    })

ざんねんながら、複数の色は指定できません。

    // マテリアルの作成
    let material = new THREE.MeshLambertMaterial({
        map: texture,
        emissiveMap: [emissiveTexture1, emissiveTexture2], 
        emissive: ["#FF0000", "#0000FF"]
    })
        //////// 何も起きない ////////

See the Pen Minecraft Enchanted item by Urushibara (@pneuma01) on CodePen.

解説のようなもの

モデルの初期化

ゆらめく様にアニメーションさせたいので、あらかじめアニメーション分のEmissiveMapを作成しておきます。

    // Sceneの初期化
    const scene = new THREE.Scene();

    // Geometryの作成
    let img = document.querySelector("#item");
    let canvas = createCanvas(img.width, img.height);
    canvas.context.drawImage(img, 0, 0);
    let geometry = new THREE.PixelArtGeometry(canvas.canvas, 1);
    canvas.canvas.remove();

    // 基本テクスチャの作成
    let texture = new THREE.TextureLoader().load(img.src);
    texture.magFilter = THREE.NearestFilter;
    texture.minFilter = THREE.NearestFilter;
    texture.type = THREE.FloatType;

    // アニメーション Emissive Map の作成
    let emissiveMaps = [];
    for(let i=0; i<56; i++){
        let canvas = drawAnimated(i);
        let texture = new THREE.CanvasTexture(canvas);
        texture.magFilter = THREE.NearestFilter;
        texture.minFilter = THREE.NearestFilter;
        texture.type = THREE.FloatType;
        emissiveMaps.push(texture);
    }

    // マテリアルの作成
    let material = new THREE.MeshLambertMaterial({
        map: texture,
        emissiveMap: emissiveMaps[0],
        emissive: "#7F007F", /// Emissive Color
        transparent: false,
        side: THREE.DoubleSide,
        alphaTest: 0.99 
    })

    // Mesh の作成
    let box = new THREE.Mesh(
        geometry, 
        material
    );
    box.scale.set(10, 10, 10);
    main_object = box;

    // Sceneへ追加
    scene.add(main_object);

アニメーション

描画tick呼び出し時に、emissiveMapを次々と入れ替えます。
CanvasTextureを使ってリアルタイムでEmissiveMapを描画するのも試してみましたが、かなり重たかったのでやめました。

        //// Tick ////
        function tick() {

            // オブジェクトの位置
            pos_cycle = pos_cycle < 360 ? pos_cycle + 1 : 0;
            var y = Math.sin(deg2rad(pos_cycle * 2)) * 20;
            main_object.position.set(0, -y, 0);
            main_object.rotation.set(0, deg2rad(pos_cycle * 1), 0);

            // Emissive Map の切り替え
            main_object.material.emissiveMap = emissiveMaps[Math.floor(glint_cycle)];
            glint_cycle = glint_cycle < emissiveMaps.length ? glint_cycle + 0.1 : 0;

            // 描画
            renderer.render(scene, camera);
            requestAnimationFrame(tick);
        }
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away