Zpět

Vue.js & Babylon.js & Vue-BabylonJS

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

  • 
    <div class="fixed-ratio">
        <!-- Vue-BabylonJS scéna -->
        <Scene main="#ffffff">
    	    <text-plane :text="text" :color="diffuseColor"></text-plane>
        </Scene>
    </div>
    <div>
        <!-- Formulář pro ovládání scény -->
        <form>
    	    <div>
    		    <label>Text</label>
                <!-- Vstup pro text s obousměrným data-bindingem v-model -->
    		    <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>
        </form>
    </div>
    
  • // Inicializace VueBabylonjs
    Vue.use(window.VueBabylonjs);
    
    // Vue komponent pro text ve 3D
    Vue.component('text-plane', Vue.extend({
        props: ['text', 'color'],
        data: function () {
            return {
                text: this.text,
                color: this.color
            }
        },
        methods: {
            initPlane: function (event) {
                var BABYLON = window.VueBabylonjs.BABYLON;
                var scene = event.scene;
                var entity = event.entity;
                entity.material = new BABYLON.StandardMaterial("material", scene);
                entity.material.backFaceCulling = false;
                entity.material.emissiveColor = new BABYLON.Color3(1, 1, 1);
                this.update = function () {
                    var dynamicTexture = new BABYLON.DynamicTexture("dyn", { width: 512, height: 512 }, scene);
                    dynamicTexture.drawText(this.text, (256 - ((this.text.length * 40) / 2)), 256, "bold 70px monospace", this.color || "#000000", null, true, true);
                    dynamicTexture.hasAlpha = true;
                    entity.material.diffuseTexture = dynamicTexture;
                }
                this.update();
            },
        },
        watch: {
            text: function () { if (this.update) { this.update(); } },
            color: function () { if (this.update) { this.update(); } }
        },
        template: '<Plane @entity="initPlane"></Plane>'
    }));
    
    // Vue aplikace
    var app1 = new Vue({
        el: '#app1',
        data: {
            text: 'Hello world!',
            diffuseColor: '#dd3300'
        }
    });
    
{{ diffuseColor }}

Ukázka #2 - Práce s polem

  • 
    <div class="fixed-ratio">
        <!-- X3Dom scéna -->
        <Scene main="#ffffff">
            <!-- Cyklus s využitím directivy v-for pro vykreslení všech kostek -->
    	    <Template v-for="(item, index) in items">
    		    <Entity :position="[((index - ((items.length - 1) / 2)) * 2), 0, 0]">
    			    <Box :scaling="[item.size.x, item.size.y, item.size.z]"
    				     :position="[item.position.x, item.position.y, item.position.z]">
    				    <Material :diffuse="VueBabylonjs.BABYLON.Color3.FromHexString(item.color)">
                        </Material>
    			    </Box>
    		    </Entity>
    	    </Template>
        </Scene>
    </div>
    <div>
        <!-- Formulář pro ovládání scény -->
        <form>
            <ul>
                <!-- Cyklus s využitím directivy v-for pro ovládací panely ke všem kostkám -->
                <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>
                            <!-- Tlačítko napojené na metodu pro smazání kostky -->
                            <a v-on:click="remove(index)">Smazat</a>
                        </div>
                    </div>
                </li>
            </ul>
            <!-- Tlačítko napojené na metodu pro přidání kostky -->
            <a v-on:click="add()" > Přidat nový objekt</a>
        </form>
    </div>
    
  • // Inicializace VueBabylonjs
    Vue.use(window.VueBabylonjs);
    
    // Vue aplikace
    var app2 = new Vue({
        el: '#app2',
        data: {
            items: [],
        },
        methods: {
            // metoda pro přidání kostky
            add: function () {
                this.items.push({
                    size: { x: 1, y: 1, z: 1 },
                    position: { x: 0, y: 0, z: 0 },
                    color: getRandomColor()
                });
            },
            // metoda pro smazání kostky
            remove: function (index) {
                this.items.splice(index, 1);
            }
        },
        // metoda volaná při inicializaci
        created: function () {
            this.add();
            this.add();
        }
    });
    
  • {{ item.color }}
Přidat nový objekt

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

  • 
    <Scene main="#ffffff">
    	<Entity :rotation="[-1.0471975511965976, 0, 0]">
    		<Box :scaling="[16, 0.1, 6]">
    			<Material diffuse="#0D660D"></Material>
    		</Box>
    		<Entity :rotation="[1.5707963268, 0, 0]" :scaling="[8, 8, 8]" :position="[0, 0.06, 1.6]">
    			<text-plane text="LED diody" color="#ff9900"></text-plane>
    		</Entity>
    		<Template v-for="(led, index) in leds">
    			<Entity :position="[((((leds.length - index) - (leds.length / 2)) * 2) - 1), 0, 0]">
    				<Entity :rotation="[1.5707963268, 0, 0]" :scaling="[5, 5, 5]" :position="[0, 0.06, -1]">
    					<text-plane :text="(Math.pow(2, index)).toString()" color="#ff9900"></text-plane>
    				</Entity>
    				<Entity :position="[0, 0.15, 0.2]">
    					<Sphere :scaling="[0.8, 0.8, 0.8]" :position="[0, 0.95, 0]">
    						<Material :diffuse="(led.state ? color : '#CCCCCC')" alpha="0.8"></Material>
    					</Sphere>
    					<Cylinder :position="[0, 0.55, 0]"
    							  :scaling="[0.8, 0.4, 0.8]">
    						<Material :diffuse="(led.state ? color : '#CCCCCC')" alpha="0.8"></Material>
    					</Cylinder>
    					<Cylinder :scaling="[0.9, 0.15, 0.9]">
    						<Material :diffuse="(led.state ? color : '#CCCCCC')" alpha="0.8"></Material>
    					</Cylinder>
    				</Entity>
    				<Entity :position="[0, 0.25, -2]">
    					<Cylinder :position="[0, 0.35, 0]"
    							  :scaling="[0.8, (led.state ? 0.2 : 0.6), 0.8]"
    							  @entity="initButton($event, index)">
    						<Material diffuse="#8080CC"></Material>
    					</Cylinder>
    					<Box :scaling="[1, 0.5, 1]">
    						<Material diffuse="#1A1A1A"></Material>
    					</Box>
    				</Entity>
    			</Entity>
    		</Template>
    	</Entity>
    </Scene>
    
  • // Inicializace VueBabylonJS
    Vue.use(window.VueBabylonjs);
    
    // Vue komponent pro text ve 3D
    Vue.component('text-plane', Vue.extend({
        props: ['text', 'color'],
        data: function () {
            return {
                text: this.text,
                color: this.color
            }
        },
        methods: {
            initPlane: function (event) {
                var BABYLON = window.VueBabylonjs.BABYLON;
                var scene = event.scene;
                var entity = event.entity;
                entity.material = new BABYLON.StandardMaterial("material", scene);
                entity.material.backFaceCulling = false;
                entity.material.emissiveColor = new BABYLON.Color3(1, 1, 1);
                this.update = function () {
                    var dynamicTexture = new BABYLON.DynamicTexture("dyn", { width: 512, height: 512 }, scene);
                    dynamicTexture.drawText(this.text, (256 - ((this.text.length * 40) / 2)), 256, "bold 70px monospace", this.color || "#000000", null, true, true);
                    dynamicTexture.hasAlpha = true;
                    entity.material.diffuseTexture = dynamicTexture;
                }
                this.update();
            },
        },
        watch: {
            text: function () { if (this.update) { this.update(); } },
            color: function () { if (this.update) { this.update(); } }
        },
        template: '<Plane @entity="initPlane"></Plane>'
    }));
    
    // Vue aplikace
    var app3 = new Vue({
        el: '#app3',
        data: {
            leds: [
                { state: false },
                { state: true },
                { state: false },
                { state: false },
                { state: true },
                { state: true },
                { state: false },
                { state: false },
            ],
            color: '#ff0000',
        },
        // dopočítáváné vlastnosti pro hexadecimální a binární zápis
        computed: {
            int: {
                get: function () {
                    var r = 0;
                    for (var i = 0; i < this.leds.length; i++) {
                        r += this.leds[i].state ? Math.pow(2, i) : 0;
                    }
                    return r;
                },
                set: function (v) {
                    var bin = toBin(v);
                    for (var i = 0; i < this.leds.length; i++) {
                        this.leds[this.leds.length - i - 1].state = bin[i] == "1";
                    }
                }
            },
            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); }
            }
        },
        methods: {
            // metoda pro inicializaci tlačítka
            initButton: function (event, index) {
                event.scene.cameras[0].radius = 15;
                var that = this;
                var BABYLON = window.VueBabylonjs.BABYLON;
                var entity = event.entity;
                entity.actionManager = new BABYLON.ActionManager(event.scene);
                entity.actionManager.registerAction(new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger, function () { that.lightSwitch(index); }));
            },
            // metoda pro přepnutí LED diody
            lightSwitch: function (index) {
                this.leds[index].state = !this.leds[index].state;
            }
        }
    });
    
  • 
    <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>
    
{{ color }}