Three.jsを使ってEveOnlineのStarmapを表示してみた その2

スクリーンショット 2014-07-27 17.53.51
Javascript
2

前回はEveOnlineのStarMapを表示するところまで行った。ただ、点だけ表示されてもそれがどこの場所であるかがわからないので、文字を表示するようにしてみる。
Textを表示するにはTHREE.TextGeometryを使用する。使い方についてはググればいろいろ出てくるので割愛。

とりあえずHello Three.js! と表示するプログラムを書いてみる。


var textGeo = new THREE.TextGeometry( 'Hello Three.js!', {
size: 5000000000000000,
curveSegments: 8,
height:10,
bevelEnabled: false,
bevelSize: 3,
bevelThickness: 5,
bevelSegments: 2
});

var greenMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } );
text = new THREE.Mesh( textGeo, greenMaterial );
text.position.x = 1000;
text.position.y = 1000;
text.position.z = 1000;
text.doubleSided = false;
scene.add( text );

var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position = new THREE.Vector3(0, 0, 0);
spotLight.position.x = 20000;
spotLight.position.y = 20000;
spotLight.position.z = 20000;
spotLight.lookAt(text.position);
spotLight.intensity = 10e20;
spotLight.shadowCameraVisible = true;
scene.add(spotLight);

さて、実際に表示してみると文字が正面に表示されてなくて非常にみづらいため、常に文字は正面になるようにrender()に下記コードを追加する。


function render() {
stats.update();

var delta = clock.getDelta();
trackballControls.update(delta);

text.rotation.setFromRotationMatrix( camera.matrix ); //これを追加

requestAnimationFrame(render);
webGLRenderer.render(scene, camera);
}

ほかにもいろいろな方法がありそうだが、とりあえずこれで前を向くようになった。

ちなみに正面を向かせる処理はビルボード処理というらしい。こちらもググればいろいろでてくる。

さて、これで完成かなと思い表示されていろいろ回転とかしてみたが、どうもうまく表示されなかった。

具体的には回転させたときに文字がかけた。なんでかけたのか原因をみていたら、どうも回転させた時にライトがあたっておらず、あたらない部分が真っ暗になるということがわかった。

AmbientLightを使い、ライトがあたってない部分を赤く表示してみたところよくわかった。

スクリーンショット 2014-07-27 17.12.54

文字の正面表示でうまくいかない例

これを解消するために、spotLightではなくdirectionalLightを、カメラを動かしたときにdirectionalLightも一緒に移動するように修正。

function createText()
{
    var textGeo = new THREE.TextGeometry( 'Hello Three.js!', {
      size: 5000000000000000,
      curveSegments: 8,
      height:10,
      bevelEnabled: false,
      bevelSize: 3,
      bevelThickness: 5,
      bevelSegments: 2
      });

    var greenMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } );
    text = new THREE.Mesh( textGeo, greenMaterial );
    text.position.x = 1000;
    text.position.y = 1000;
    text.position.z = 1000;
    text.doubleSided = false;

    scene.add( text );

    //修正 Start
    directionalLight = new THREE.DirectionalLight(
      0xffffff,       // 光の色
      3               // 光の強さ
      );

    directionalLight.position.set(camera.position.x,camera.position.y,camera.position.z);
    scene.add( directionalLight );
    //修正 End
}

function render() {
    stats.update();

    var delta = clock.getDelta();
    trackballControls.update(delta);

    text.rotation.setFromRotationMatrix( camera.matrix );
    directionalLight.position = camera.position; //これを追加
    requestAnimationFrame(render);
    webGLRenderer.render(scene, camera);
}

これで無事うまく表示されるようになった。

文字の正面表示でうまくいかない例改良版

さて、ここまでの事をふまえて EveOnlineのスターマップに場所を一緒に表示してみた結果が下記

スクリーンショット 2014-07-27 17.53.51

スターマップの上に文字を表示してみた

ただ、残念ながら全部表示してみようとすると読み込みが終わらず表示できず、、、
場所の表示はリージョン毎のマップ表示のときにしかでないようにするとかするしかないのかも。

全ソースを下記に乗っけとく。

<!DOCTYPE html>

<html>

<head>
    <title>Maptest009</title>
    <script type="text/javascript" src="./libs/three.js"></script>
    <script type="text/javascript" src="./libs/jquery-1.9.0.js"></script>
    <script type="text/javascript" src="./libs/stats.js"></script>
    <script type="text/javascript" src="./libs/dat.gui.js"></script>
    <script type="text/javascript" src="./libs/TrackballControls.js"></script>
    <script type="text/javascript" src="./libs/helvetiker_regular.typeface.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

    <div id="Stats-output">
    </div>
    <div id="WebGL-output">
    </div>
    <script type="text/javascript">
        $(function () {
            var stats = initStats();
            var scene = new THREE.Scene();
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000000);

            var webGLRenderer = new THREE.WebGLRenderer();
            webGLRenderer.setClearColorHex(0x000000, 1.0);
            webGLRenderer.setSize(window.innerWidth, window.innerHeight);

            camera.position.x = 500000000000000000;
            camera.position.y = 500000000000000000;
            camera.position.z = 500000000000000000;

            var trackballControls = new THREE.TrackballControls(camera);
            trackballControls.rotateSpeed = 1.0;
            trackballControls.zoomSpeed = 3.0;
            trackballControls.panSpeed = 1.0;
            trackballControls.noZoom=false;
            trackballControls.noPan=false;
            trackballControls.staticMoving = true;
            var clock = new THREE.Clock();
            var star_text = [];
            var directionalLight = null;

            $("#WebGL-output").append(webGLRenderer.domElement);

            stars_position = getStarsData();
            createStars(stars_position);
            createAxies();
            render();

            function createStars(starsDatas) {
                var geom = new THREE.Geometry();

                var texture_star = THREE.ImageUtils.loadTexture("./assets2/Stars001.png");
                var material = new THREE.ParticleBasicMaterial(
                {
                    size: 10.0e15
                    ,vertexColors: true
                    ,blending: THREE.AdditiveBlending
                    ,map: texture_star
                    ,sizeAttenuation: true //sizeがカメラに影響しない
                    , color: 0xffffff
                    , transparent: true
                });

                for (var p = 0; p < starsDatas.length; p++)
                {
                    //limit
                    //10000001    Derelik
                    //10000002    The Forge
                    //10000003    Vale of the Silent
                    //10000004    UUA-F4
                    //10000005    Detorid
                    //10000006    Wicked Creek
                    //10000043    Domain
                    var limit = [10000002,10000043];
                    if (limit.indexOf(starsDatas[p].regionID) > -1)
                    {
                        var particle = new THREE.Vector3(starsDatas[p].x,starsDatas[p].y, starsDatas[p].z);
                        geom.vertices.push(particle);
                        if(starsDatas[p].solarSystemName == "Jita"){
                            geom.colors.push(new THREE.Color(0xff0000));
                        }else{
                            geom.colors.push(new THREE.Color(0x00ffff));
                        }

                        //show solarSystemName
                        var textGeo = new THREE.TextGeometry(
                           starsDatas[p].solarSystemName,
                           {
                              size: 2.0e15,
                              curveSegments: 8,
                              height:10,
                              bevelEnabled: false, bevelSize: 3, bevelThickness: 5, bevelSegments: 2
                          });
                        var textMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff } );
                        var sText = new THREE.Mesh( textGeo, textMaterial );
                        sText.position.set(starsDatas[p].x,starsDatas[p].y, starsDatas[p].z);
                        star_text.push(sText);
                        scene.add(sText);

                        //debug
                        console.log("Load " + p);
                        //max load
                        if(p > 2000){
                            break;
                        }
                    }
                }

                var system = new THREE.ParticleSystem(geom, material);
                scene.add(system);

                //light
                directionalLight = new THREE.DirectionalLight(
                  0xffffff,       // 光の色
                  3               // 光の強さ
                  );

                directionalLight.position.set(camera.position.x,camera.position.y,camera.position.z);
                scene.add( directionalLight );
            }

            function createAxies(){
                var axes = new THREE.AxisHelper( 100000000000000000 );
                scene.add(axes);
            }

            function render() {
                stats.update();

                var delta = clock.getDelta();
                trackballControls.update(delta);

                //text billboard
                for (var i = 0; i < star_text.length; i++)
                {
                    star_text[i].rotation.setFromRotationMatrix( camera.matrix );
                }

                directionalLight.position = camera.position;
                requestAnimationFrame(render);
                webGLRenderer.render(scene, camera);
            }

            function initStats()
            {
                var stats = new Stats();
                stats.setMode(0); // 0: fps, 1: ms

                // Align top-left
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';

                $("#Stats-output").append(stats.domElement);

                return stats;
            }

            function getStarsData()
            {
                return loadLocalJsonFile("./data/EveMapData_json.json");
            }

            //ローカルのJSONファイルを読み込む
            function loadLocalJsonFile(filepath)
            {
                var result;
                //非同期から同期にする
                $.ajaxSetup({ async: false });
                $.getJSON( filepath , function(json)
                {
                    result = json;
                });
                // 非同期に戻す
                $.ajaxSetup({ async: true });
                return result;
            }

        });
</script>
</body>
</html>

文字を常に正面に表示させる方法大変を探していてとても助かりました。
TextGeometryのfontの扱い方が変わっているようでTextGeometry自体を使うのに少し苦労しました。
ありがとうございました

2件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

AWS
Docker
ECS+ALBの動的ポートマッピングでダウンタイムのないデプロイを試してみた

はじめに 少し前に個人で作成しているWebサービスのインフラにDockerを使い始めました。 複数台 …

スクリーンショット 2016-08-16 0.43.10
AngularJS
クライアントAngularJS サーバーサイドRails5 におけるOmniauth 認証を試してみる

去年にEOPESを公開してから1年半。 初めての外部公開サービスだったが、ソースは結構ごり押し部分も …

スクリーンショット 2016-01-09 20.02.08
Ruby on Rails
Capistrano3を利用してBitbucketプライベートリポジトリにあるRailsアプリをデプロイしてみた

Railsアプリを配置する際、毎回手作業で頑張って配置してきたが、そろそろ自動デプロイを・・・ とい …