Zpět

Vue.js & Babylon.js

Ukázka #1 - Data-binding do 3D scény

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
        
        var data = {};
    
        // text ve 3D scéně
        var textPlane = new BABYLON.Mesh.CreatePlane("planeForText", 20, scene);
        var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(textPlane, 2048, 2048);
        var text = new BABYLON.GUI.TextBlock();
        text.fontSize = 200;
        text.outlineWidth = 5;
    
        // propojení textu a datového modelu aplikace pomocí mapy
        new MW.TwoWayMap({
            end1: data,
            map1: MAP.TEXT.to3DModel,
            end2: text,
            map2: MAP.TEXT.toDataModel,
            data1: {
                text: 'Hello world!',
                diffuseColor: '#dd3300',
                outlineColor: '#ee9966',
            }
        });
    
        advancedTexture.addControl(text);
    
        // Vue aplikace
        var app1 = new Vue({
            el: '#app1',
            data: data
        });
    
    }
  • 
    <form>
    	<div>
    		<label>Text</label>
    		<input type="text" v-model="text" />
    	</div>
    	<div class="grid">
    		<div>
    			<label>Základní barva</label>
    			<div>
    				<input type="color" v-model="diffuseColor" />
    				<span :style="'color: ' + diffuseColor"> {{ diffuseColor }} </span>
    			</div>
    		</div>
    		<div>
    			<label>Barva lesku</label>
    			<div>
    				<input type="color" v-model="specularColor" />
    				<span :style="'color: ' + specularColor"> {{ specularColor }} </span>
    			</div>
    		</div>
    	</div>
    </form>
    
#dd3300
#ee9966

Ukázka #2 - Práce s polem

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
        
        var group = new BABYLON.AbstractMesh("group", scene);
    
        // fukce pro vytvoření 3D kostky
        function createCube(index) {
            var data = {};
            var material = new BABYLON.StandardMaterial("material" + index, scene);
            var cube = new BABYLON.Mesh.CreateBox("box" + index, 1, scene);
            cube.material = material;
            group.addChild(cube);
    
            // propojení kostky s datovým modelem
            new MW.TwoWayMap({
                end1: data,
                map1: MAP.CUBE.to3DModel,
                end2: cube,
                map2: MAP.CUBE.toDataModel,
                data1: {
                    color: getRandomColor(),
                    element: cube,
                    index: index
                }
            });
    
            group.position.x = - index;
            cube.position.x = index * 2;
            return data;
        }
    
        // Vue aplikace
        var app2 = new Vue({
            el: '#app2',
            data: {
                items: [
                    createCube(0),
                    createCube(1)
                ],
            },
            methods: {
                // metoda pro přidání kostky
                add: function () {
                    this.items.push(createCube(this.items.length));
                },
                // metoda pro smazání kostky
                remove: function (index) {
                    var mesh = this.items[index].element;
                    group.removeChild(mesh);
                    scene.removeMesh(mesh);
                    this.items.splice(index, 1);
                    for (var i = index; i < this.items.length; i++) {
                        var oldX = this.items[i].position.x;
                        this.items[i].index = i;
                        this.items[i].element.position.x = this.items[i].element.position.x - 2;
                    }
                    group.position.x = - (this.items.length - 1);
                }
            }
        });
    
    }
  • 
    <form>
        <ul>
            <li v-for="(item, index) in items">
                <div class="grid">
                    <div>
                        <label>Objekt #{{index + 1}}</label>
                        <div>
                            <input type="color" v-model="item.color" />
                            <span :style="'color: ' + item.color"> {{ item.color }} </span>
                        </div>
                    </div>
                    <div>
                        <label>Šířka {{ Math.floor(item.size.x * 100) }}%</label>
                        <input type="range" v-model="item.size.x" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>Výška {{ Math.floor(item.size.y * 100) }}%</label>
                        <input type="range" v-model="item.size.y" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>Délka {{ Math.floor(item.size.z * 100) }}%</label>
                        <input type="range" v-model="item.size.z" min="0.1" max="2" step="0.1" />
                    </div>
                    <div>
                        <label>X {{ item.position.x }}</label>
                        <input type="range" v-model="item.position.x" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <label>Y {{ item.position.y }}</label>
                        <input type="range" v-model="item.position.y" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <label>Z {{ item.position.z }}</label>
                        <input type="range" v-model="item.position.z" min="-1" max="1" step="0.1" />
                    </div>
                    <div>
                        <a v-on:click="remove(index)">Smazat</a>
                    </div>
                </div>
            </li>
        </ul>
        <a v-on:click="add()" > Přidat nový objekt</a>
    </form>
    
  • #ee2611
  • #02ef23
Přidat nový objekt

Ukázka #3 - Pokročilejší scéna

  • // Předpoklad: Vytvořená základní scéna s kamerou a světelným zdrojem 
    function (scene) {
    
        // "Vlákno" 3D scény
        window.sceneWorker = new MW.SyncWorker(function (worker) {
    
            // optimalizovaná funkce pro odeslání zprávy po kliknutí na tlačítko
            var numberUpdater = getDebounced(function (number) { worker.postMessage({ type: "number", value: number }); }, 50);
    
            var leds = [], number = 0;
    
            // "glow" efekt
            var gl = new BABYLON.GlowLayer("glow", scene, {
                mainTextureSamples: 4,
                renderingGroupId: 0
            });
            gl.intensity = 4;
    
            // základní deska
            var node = new BABYLON.TransformNode("node");
            node.rotation.x = - (Math.PI / 2) * 0.7;
            node.scaling = new BABYLON.Vector3(0.8, 0.8, 0.8);
            var boardMaterial = new BABYLON.StandardMaterial("board", scene);
            boardMaterial.diffuseColor = new BABYLON.Color3(0.05, 0.4, 0.05);
            boardMaterial.maxSimultaneousLights = 10;
            boardMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
            var board = BABYLON.MeshBuilder.CreateBox("board", { width: 16, height: 0.1, depth: 6 }, scene);
            board.material = boardMaterial;
            board.parent = node;
    
            // Zlatý text
            function GoldText(text, size, z) {
                var textPlane = new BABYLON.Mesh.CreatePlane("planeForText", 10, scene);
                textPlane.rotation.x = (Math.PI / 2);
                textPlane.position.y = 0.06;
                textPlane.position.z = z;
                var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateForMesh(textPlane, 1024, 1024);
                var textBlock = new BABYLON.GUI.TextBlock();
                textBlock.text = text;
                textBlock.fontSize = size;
                textBlock.outlineWidth = 0;
                textBlock.color = "#ff9900";
                advancedTexture.addControl(textBlock);
                this.mesh = textPlane;
            }
            var heading = new GoldText("LED Diody (8 bitů)", 100, 1.6);
            heading.mesh.parent = node;
    
            // materiály pro LED diodu
            var ledOffMaterial = new BABYLON.StandardMaterial("ledOff", scene);
            ledOffMaterial.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
            ledOffMaterial.emissiveColor = new BABYLON.Color3(0.6, 0.6, 0.6);
            ledOffMaterial.alpha = 0.8;
            ledOffMaterial.maxSimultaneousLights = 10;
            var ledOnMaterial = new BABYLON.StandardMaterial("ledOn", scene);
            ledOnMaterial.alpha = 0.8;
            ledOnMaterial.maxSimultaneousLights = 10;
    
            // LED Dioda
            function Led(index) {
                var led = new BABYLON.TransformNode("led" + index);
                var sphere = BABYLON.MeshBuilder.CreateSphere("sphere" + index, { diameter: 0.8 }, scene);
                sphere.position.y = 0.86;
                var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder" + index, { diameter: 0.8, height: 0.9 }, scene);
                cylinder.position.y = 0.46;
                var bottom = BABYLON.MeshBuilder.CreateCylinder("cylinder" + index, { diameter: 0.9, height: 0.2 }, scene);
                bottom.position.y = 0.11;
                sphere.parent = led;
                cylinder.parent = led;
                bottom.parent = led;
    
                this.switch = function (state) {
                    if (state) {
                        sphere.material = ledOnMaterial;
                        cylinder.material = ledOnMaterial;
                        bottom.material = ledOnMaterial;
                        gl.addIncludedOnlyMesh(sphere);
                        gl.addIncludedOnlyMesh(cylinder);
                    } else {
                        sphere.material = ledOffMaterial;
                        cylinder.material = ledOffMaterial;
                        bottom.material = ledOffMaterial;
                        gl.removeIncludedOnlyMesh(sphere);
                        gl.removeIncludedOnlyMesh(cylinder);
                    }
                    sphere.markAsDirty();
                    cylinder.markAsDirty();
                    bottom.markAsDirty();
                }
                this.mesh = led;
            }
    
            // materiály pro tlačítko
            var buttonMaterial = new BABYLON.StandardMaterial("button", scene);
            buttonMaterial.diffuseColor = new BABYLON.Color3(0.5, 0.5, 0.8);
            buttonMaterial.maxSimultaneousLights = 10;
            var bottomMaterial = new BABYLON.StandardMaterial("bottom", scene);
            bottomMaterial.diffuseColor = new BABYLON.Color3(0.1, 0.1, 0.1);
    
            // Tlačítko
            function Button(index, switchableLed) {
                var button = new BABYLON.TransformNode("button" + index);
                var cylinder = BABYLON.MeshBuilder.CreateCylinder("buttonCylinder" + index, { diameter: 0.8, height: 0.8, updatable: true }, scene);
                cylinder.position.y = 0.51;
                var bottom = BABYLON.MeshBuilder.CreateBox("buttonBottom" + index, { width: 1, height: 0.5, depth: 1 }, scene);
                bottom.position.y = 0.26;
                cylinder.material = buttonMaterial;
                bottom.material = bottomMaterial;
                cylinder.parent = button;
                bottom.parent = button;
                button.position.z = -2;
    
                cylinder.actionManager = new BABYLON.ActionManager(scene);
                cylinder.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, function () {
                    switchableLed.switch(!switchableLed.state);
                    number = (number * 1) + (Math.pow(2, index) * (switchableLed.state ? 1 : -1));
                    gl.intensity = number == 0 ? 0 : 4;
                    numberUpdater(number);
                }));
    
                this.switch = function (state) {
                    cylinder.scaling.y = state ? 0.5 : 1;
                    cylinder.markAsDirty();
                }
                this.mesh = button;
            }
    
            // LED Dioda s tlačítkem
            function SwitchableLed(index) {
                var group = new BABYLON.TransformNode("group" + i);
                var led = new Led(index);
                var button = new Button(index, this);
                var text = new GoldText((Math.pow(2, index)).toString(), 60, -1);
                led.mesh.parent = group;
                button.mesh.parent = group;
                text.mesh.parent = group;
                group.position.x = ((((8 - index) - (8 / 2)) * 2) - 1);
                group.parent = node;
    
                this.switch = function (state) {
                    led.switch(state);
                    button.switch(state);
                    this.state = state == true;
                }
                this.state = false;
            }
    
            // inicializace LED Diod s tlačítky
            for (var i = 0; i < 8; i++) {
                leds.push(new SwitchableLed(i));
            }
    
            // funkce pro nastavení čísla
            function setNumber(value) {
                number = value;
                var bin = toBin(number);
                gl.intensity = number == 0 ? 0 : 4;
                for (var i = 0; i < leds.length; i++) {
                    leds[leds.length - i - 1].switch(bin[i] == "1");
                }
            }
    
            // funkce pro nastavení barvy světla
            function setColor(value) {
                ledOnMaterial.diffuseColor.copyFrom(BABYLON.Color3.FromHexString(value));
                ledOnMaterial.emissiveColor.copyFrom(BABYLON.Color3.FromHexString(value));
                ledOnMaterial.markAsDirty();
            }
    
            // zpracování přijatých zpráv
            worker.addEventListener("message", function (data) {
                switch (data.type) {
                    case "init":
                        setNumber(data.number * 1);
                        setColor(data.color);
                        break;
                    case "number":
                        setNumber(data.value * 1);
                        break;
                    case "color":
                        setColor(data.value);
                        break;
                    default: break;
                }
            });
    
        });
     
    }
  • // VUE Aplikace v rámci SyncWorker
    function () {
    
        // "Vlákno" Vue aplikace
        window.appWorker = new MW.SyncWorker(function (worker) {
    
            // Optimalizovaná funkce pro odeslání zprávy o změně čísla
            var numberUpdater = getDebounced(function (number) { worker.postMessage({ type: "number", value: number }); }, 50);
    
            // výchozí stav datového modelu
            var data = {
                int: 50,
                color: '#ff0000'
            };
            // pojistka proti nekonzistenci
            var prevent = false;
    
            // zpracování přijatých zpráv
            worker.addEventListener("message", function (message) {
                switch (message.type) {
                    case "number":
                        prevent = true;
                        data.int = message.value;
                        break;
                    default: break;
                }
            });
    
            // Vue aplikace
            var app3 = new Vue({
                el: '#app3',
                data: data,
                // dopočítáváné vlastnosti pro hexadecimální a binární zápis
                computed: {
                    hex: {
                        get: function () { return toHex(this.int); },
                        set: function (v) { this.int = parseInt(v, 16); }
                    },
                    bin: {
                        get: function () { return toBin(this.int); },
                        set: function (v) { this.int = parseInt(v, 2); }
                    }
                },
                // sledování změn čísla a barvy
                watch: {
                    int: function (v) {
                        if (!prevent) {
                            numberUpdater(v);
                        }
                        prevent = false;
                    },
                    color: function (v) {
                        worker.postMessage({ type: "color", value: v });
                    }
                }
            });
    
            worker.postMessage({ type: "init", number: data.int, color: data.color });
        });
    
        // samotné propojení zasílání zpráv
        window.appWorker.addEventListener("message", window.sceneWorker.postMessage);
        window.sceneWorker.addEventListener("message", window.appWorker.postMessage);
    
    }
  • 
    <form>
    	<div>
    		<label>
    			<span class="left">0</span>
    			<span class="right">255</span>
    		</label>
    		<div>
    			<input type="range" v-model="int" min="0" max="255" step="1" />
    		</div>
    	</div>
    	<div>
    		<div class="grid">
    			<div>
    				<label>Číslo</label>
    				<input type="text" v-model="int" />
    			</div>
    			<div>
    				<label>Binární zápis</label>
    				<input type="text" v-model="bin" />
    			</div>
    			<div>
    				<label>Hexadecimální zápis</label>
    				<input type="text" v-model="hex" />
    			</div>
    			<div>
    				<label>Barva světla</label>
    				<input type="color" v-model="color" />
    				<span :style="'color: ' + color"> {{ color }} </span>
    			</div>
    		</div>
    	</div>
    </form>
    
#ff0000