Browse Source

MapGraph done

David Catuhe 7 năm trước cách đây
mục cha
commit
1153c5653f

BIN
Playground/textures/mercator2.jpg


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6843 - 6843
dist/preview release/babylon.d.ts


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/babylon.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
dist/preview release/babylon.max.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
dist/preview release/babylon.no-module.max.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 2 - 2
dist/preview release/es6.js


+ 22 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -1555,6 +1555,15 @@ declare module BABYLON.GUI {
             protected _getTypeName(): string;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            /**
+                * Utility function to easily create a radio button with a header
+                * @param title defines the label to use for the header
+                * @param group defines the group to use for the radio button
+                * @param isChecked defines the initial state of the radio button
+                * @param onValueChanged defines the callback to call when value changes
+                * @returns a StackPanel containing the radio button and a textBlock
+                */
+            static AddRadioButtonWithHeader(title: string, group: string, isChecked: boolean, onValueChanged: (button: RadioButton, value: boolean) => void): StackPanel;
     }
 }
 declare module BABYLON.GUI {
@@ -2299,6 +2308,7 @@ declare module BABYLON.GUI {
             INNERGLOW: boolean;
             BORDER: boolean;
             HOVERLIGHT: boolean;
+            TEXTURE: boolean;
             constructor();
     }
     /**
@@ -2353,6 +2363,7 @@ declare module BABYLON.GUI {
                 * Gets or sets the hover light position in world space (default is BABYLON.Vector3.Zero())
                 */
             hoverPosition: BABYLON.Vector3;
+            albedoTexture: BABYLON.Nullable<BABYLON.BaseTexture>;
             /**
                 * Creates a new Fluent material
                 * @param name defines the name of the material
@@ -2547,12 +2558,22 @@ declare module BABYLON.GUI {
         * @see http://doc.babylonjs.com/how_to/chart3d#mapgraph
         */
     export class MapGraph extends Chart {
+            /** Gets or sets the offset (in world unit) on X axis to apply to all elements */
+            xOffset: number;
+            /** Gets or sets the offset (in world unit) on Y axis to apply to all elements */
+            yOffset: number;
             /** Gets or sets the tesselation used to build the cylinders */
             cylinderTesselation: number;
             /** Gets or sets the size of the world map (this will define the width) */
             worldMapSize: number;
             updateHoverLabel: (meshLabel: BABYLON.Mesh) => void;
             /**
+                * Gets the material used to render the world map
+                */
+            readonly worldMapMaterial: BABYLON.Nullable<BABYLON.Material>;
+            /** Sets the texture url to use for the world map */
+            worldMapUrl: string;
+            /**
                 * Creates a new MapGraph
                 * @param name defines the name of the graph
                 * @param scene defines the hosting scene
@@ -2561,5 +2582,6 @@ declare module BABYLON.GUI {
             protected _createCylinderMesh(name: string, scene: BABYLON.Scene): BABYLON.Mesh;
             refresh(): MapGraph;
             protected _clean(): void;
+            dispose(): void;
     }
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/gui/babylon.gui.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 46 - 1
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1670,6 +1670,7 @@ declare module 'babylonjs-gui/2D/controls/radioButton' {
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { Observable, Vector2 } from "babylonjs";
     import { Measure } from "babylonjs-gui/2D/measure";
+    import { StackPanel } from "babylonjs-gui/2D/controls";
     /**
         * Class used to create radio button controls
         */
@@ -1695,6 +1696,15 @@ declare module 'babylonjs-gui/2D/controls/radioButton' {
             protected _getTypeName(): string;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+            /**
+                * Utility function to easily create a radio button with a header
+                * @param title defines the label to use for the header
+                * @param group defines the group to use for the radio button
+                * @param isChecked defines the initial state of the radio button
+                * @param onValueChanged defines the callback to call when value changes
+                * @returns a StackPanel containing the radio button and a textBlock
+                */
+            static AddRadioButtonWithHeader(title: string, group: string, isChecked: boolean, onValueChanged: (button: RadioButton, value: boolean) => void): StackPanel;
     }
 }
 
@@ -2510,6 +2520,7 @@ declare module 'babylonjs-gui/3D/materials/fluentMaterial' {
             INNERGLOW: boolean;
             BORDER: boolean;
             HOVERLIGHT: boolean;
+            TEXTURE: boolean;
             constructor();
     }
     /**
@@ -2564,6 +2575,7 @@ declare module 'babylonjs-gui/3D/materials/fluentMaterial' {
                 * Gets or sets the hover light position in world space (default is Vector3.Zero())
                 */
             hoverPosition: Vector3;
+            albedoTexture: Nullable<BaseTexture>;
             /**
                 * Creates a new Fluent material
                 * @param name defines the name of the material
@@ -2763,18 +2775,28 @@ declare module 'babylonjs-gui/3D/charting/barGraph' {
 
 declare module 'babylonjs-gui/3D/charting/mapGraph' {
     import { Chart } from "babylonjs-gui/3D/charting";
-    import { Scene, Nullable, Mesh } from "babylonjs";
+    import { Scene, Nullable, Mesh, Material } from "babylonjs";
     /**
         * Class used to render bar graphs
         * @see http://doc.babylonjs.com/how_to/chart3d#mapgraph
         */
     export class MapGraph extends Chart {
+            /** Gets or sets the offset (in world unit) on X axis to apply to all elements */
+            xOffset: number;
+            /** Gets or sets the offset (in world unit) on Y axis to apply to all elements */
+            yOffset: number;
             /** Gets or sets the tesselation used to build the cylinders */
             cylinderTesselation: number;
             /** Gets or sets the size of the world map (this will define the width) */
             worldMapSize: number;
             updateHoverLabel: (meshLabel: Mesh) => void;
             /**
+                * Gets the material used to render the world map
+                */
+            readonly worldMapMaterial: Nullable<Material>;
+            /** Sets the texture url to use for the world map */
+            worldMapUrl: string;
+            /**
                 * Creates a new MapGraph
                 * @param name defines the name of the graph
                 * @param scene defines the hosting scene
@@ -2783,6 +2805,7 @@ declare module 'babylonjs-gui/3D/charting/mapGraph' {
             protected _createCylinderMesh(name: string, scene: Scene): Mesh;
             refresh(): MapGraph;
             protected _clean(): void;
+            dispose(): void;
     }
 }
 
@@ -4344,6 +4367,15 @@ declare module BABYLON.GUI {
             protected _getTypeName(): string;
             _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
             _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+            /**
+                * Utility function to easily create a radio button with a header
+                * @param title defines the label to use for the header
+                * @param group defines the group to use for the radio button
+                * @param isChecked defines the initial state of the radio button
+                * @param onValueChanged defines the callback to call when value changes
+                * @returns a StackPanel containing the radio button and a textBlock
+                */
+            static AddRadioButtonWithHeader(title: string, group: string, isChecked: boolean, onValueChanged: (button: RadioButton, value: boolean) => void): StackPanel;
     }
 }
 declare module BABYLON.GUI {
@@ -5088,6 +5120,7 @@ declare module BABYLON.GUI {
             INNERGLOW: boolean;
             BORDER: boolean;
             HOVERLIGHT: boolean;
+            TEXTURE: boolean;
             constructor();
     }
     /**
@@ -5142,6 +5175,7 @@ declare module BABYLON.GUI {
                 * Gets or sets the hover light position in world space (default is BABYLON.Vector3.Zero())
                 */
             hoverPosition: BABYLON.Vector3;
+            albedoTexture: BABYLON.Nullable<BABYLON.BaseTexture>;
             /**
                 * Creates a new Fluent material
                 * @param name defines the name of the material
@@ -5336,12 +5370,22 @@ declare module BABYLON.GUI {
         * @see http://doc.babylonjs.com/how_to/chart3d#mapgraph
         */
     export class MapGraph extends Chart {
+            /** Gets or sets the offset (in world unit) on X axis to apply to all elements */
+            xOffset: number;
+            /** Gets or sets the offset (in world unit) on Y axis to apply to all elements */
+            yOffset: number;
             /** Gets or sets the tesselation used to build the cylinders */
             cylinderTesselation: number;
             /** Gets or sets the size of the world map (this will define the width) */
             worldMapSize: number;
             updateHoverLabel: (meshLabel: BABYLON.Mesh) => void;
             /**
+                * Gets the material used to render the world map
+                */
+            readonly worldMapMaterial: BABYLON.Nullable<BABYLON.Material>;
+            /** Sets the texture url to use for the world map */
+            worldMapUrl: string;
+            /**
                 * Creates a new MapGraph
                 * @param name defines the name of the graph
                 * @param scene defines the hosting scene
@@ -5350,5 +5394,6 @@ declare module BABYLON.GUI {
             protected _createCylinderMesh(name: string, scene: BABYLON.Scene): BABYLON.Mesh;
             refresh(): MapGraph;
             protected _clean(): void;
+            dispose(): void;
     }
 }

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 34 - 0
gui/src/2D/controls/radioButton.ts

@@ -1,6 +1,7 @@
 import { Control } from "./control";
 import { Observable, Vector2 } from "babylonjs";
 import { Measure } from "../measure";
+import { StackPanel, TextBlock } from ".";
 
 /**
  * Class used to create radio button controls
@@ -169,4 +170,37 @@ export class RadioButton extends Control {
 
         return true;
     }
+
+    /**
+     * Utility function to easily create a radio button with a header
+     * @param title defines the label to use for the header
+     * @param group defines the group to use for the radio button
+     * @param isChecked defines the initial state of the radio button
+     * @param onValueChanged defines the callback to call when value changes
+     * @returns a StackPanel containing the radio button and a textBlock
+     */
+    public static AddRadioButtonWithHeader(title: string, group: string, isChecked: boolean, onValueChanged: (button: RadioButton, value: boolean) => void): StackPanel {
+        var panel = new StackPanel();
+        panel.isVertical = false;
+        panel.height = "30px";
+
+        var radio = new RadioButton();
+        radio.width = "20px";
+        radio.height = "20px";
+        radio.isChecked = isChecked;
+        radio.color = "green";
+        radio.group = group;
+        radio.onIsCheckedChangedObservable.add((value) => onValueChanged(radio, value));
+        panel.addControl(radio);    
+    
+        var header = new TextBlock();
+        header.text = title;
+        header.width = "180px";
+        header.paddingLeft = "5px";
+        header.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        header.color = "white";
+        panel.addControl(header); 
+
+        return panel;
+    }
 }   

+ 36 - 35
gui/src/3D/charting/chart.ts

@@ -21,6 +21,7 @@ export abstract class Chart {
     protected _defaultMaterial: Nullable<Material>; 
     private _labelDimension: string;
     private _displayLabels = true;
+    private _activeBar: Nullable<Mesh>;
 
     private _glowLayer: Nullable<GlowLayer>;
     private _onElementEnterObserver: Nullable<Observer<AbstractMesh>>;
@@ -201,16 +202,6 @@ export abstract class Chart {
         }
 
         if (this._glowLayer) {
-            if (this._onElementEnterObserver) {
-                this.onElementEnterObservable.remove(this._onElementEnterObserver);
-                this._onElementEnterObserver = null;
-            }
-    
-            if (this._onElementOutObserver) {
-                this.onElementOutObservable.remove(this._onElementOutObserver);
-                this._onElementOutObserver = null;
-            } 
-
             this._glowLayer.dispose();
             this._glowLayer = null;
             return;
@@ -218,32 +209,8 @@ export abstract class Chart {
 
         this._glowLayer = new GlowLayer("glow", this._scene);
 
-        let activeBar: Nullable<Mesh>;
-        this._onElementEnterObserver = this.onElementEnterObservable.add(mesh => {
-            activeBar = <Mesh>mesh;
-
-            this._hoverLabel = this._addLabel(activeBar.metadata.value.toString(), this._elementWidth);
-
-            this._hoverLabel.position = activeBar.position.clone();
-            this._hoverLabel.position.y = activeBar.scaling.y + 1.0;
-            this._hoverLabel.scaling.x = this._elementWidth;     
-            
-            if (this.updateHoverLabel) {
-                this.updateHoverLabel(this._hoverLabel);
-            }
-        });
-
-        this._onElementOutObserver = this.onElementOutObservable.add(mesh => {
-            activeBar = null;
-
-            if (this._hoverLabel) {
-                this._removeLabel(this._hoverLabel);
-                this._hoverLabel = null;
-            }
-        });
-
         this._glowLayer.customEmissiveColorSelector = (mesh, subMesh, material, result) => {
-            if (mesh === activeBar) {
+            if (mesh === this._activeBar) {
                 let chartColor = this._dataSource!.color.scale(0.75);
                 result.set(chartColor.r, chartColor.g, chartColor.b, 1.0);
             } else {
@@ -297,6 +264,30 @@ export abstract class Chart {
             this.onPickedPointChangedObservable.notifyObservers(pi.pickInfo.pickedPoint);
         });
 
+        this._onElementEnterObserver = this.onElementEnterObservable.add(mesh => {
+            this._activeBar = <Mesh>mesh;
+
+            this._hoverLabel = this._addLabel(this._activeBar.metadata.value.toString(), this._elementWidth);
+
+            this._hoverLabel.position = this._activeBar.position.clone();
+            this._hoverLabel.position.y = this._activeBar.scaling.y + 1.0;
+            this._hoverLabel.scaling.x = this._elementWidth;     
+            
+            if (this.updateHoverLabel) {
+                this.updateHoverLabel(this._hoverLabel);
+            }
+        });
+
+        this._onElementOutObserver = this.onElementOutObservable.add(mesh => {
+            this._activeBar = null;
+
+            if (this._hoverLabel) {
+                this._removeLabel(this._hoverLabel);
+                this._hoverLabel = null;
+            }
+        });
+
+
         this.glowHover = true;
     }
 
@@ -405,6 +396,16 @@ export abstract class Chart {
 
         this.labelCreationFunction = null;
 
+        if (this._onElementEnterObserver) {
+            this.onElementEnterObservable.remove(this._onElementEnterObserver);
+            this._onElementEnterObserver = null;
+        }
+
+        if (this._onElementOutObserver) {
+            this.onElementOutObservable.remove(this._onElementOutObserver);
+            this._onElementOutObserver = null;
+        }         
+
         if (this._pointerObserver) {
             this._scene.onPointerObservable.remove(this._pointerObserver);
             this._pointerObserver = null;

+ 87 - 11
gui/src/3D/charting/mapGraph.ts

@@ -1,5 +1,6 @@
 import { Chart } from ".";
-import { Engine, Scene, Nullable, Mesh, Animation, StandardMaterial, Texture, Matrix } from "babylonjs";
+import { Engine, Scene, Nullable, Mesh, Animation, Texture, Matrix, Observer, Vector3, Material } from "babylonjs";
+import { FluentMaterial } from "../materials";
 
 /** 
  * Class used to render bar graphs 
@@ -10,9 +11,42 @@ export class MapGraph extends Chart {
     private _cylinderMeshes: Nullable<Array<Mesh>>;
     private _maxCylinderHeight = 10;
     private _worldMap: Nullable<Mesh>;
-    private _mercatorMaterial: Nullable<StandardMaterial>;
+    private _mercatorMaterial: Nullable<FluentMaterial>;
     private _worldMapSize = 40;   
     private _cylinderTesselation = 16;
+    private _xOffset = 0;
+    private _yOffset = 0;
+    private _worldMapPickedPointObserver: Nullable<Observer<Vector3>>;  
+
+    /** Gets or sets the offset (in world unit) on X axis to apply to all elements */
+    public get xOffset(): number {
+        return this._xOffset;
+    }
+
+    public set xOffset(value: number) {
+        if (this._xOffset === value) {
+            return;
+        }
+
+        this._xOffset = value;
+
+        this.refresh();
+    }    
+    
+    /** Gets or sets the offset (in world unit) on Y axis to apply to all elements */
+    public get yOffset(): number {
+        return this._yOffset;
+    }
+
+    public set yOffset(value: number) {
+        if (this._yOffset === value) {
+            return;
+        }
+
+        this._yOffset = value;
+
+        this.refresh();
+    }       
 
     /** Gets or sets the tesselation used to build the cylinders */
     public get cylinderTesselation(): number {
@@ -53,6 +87,44 @@ export class MapGraph extends Chart {
 
         meshLabel.position.y += 1.5;
     }
+
+    /**
+     * Gets the material used to render the world map
+     */
+    public get worldMapMaterial(): Nullable<Material> {
+        return this._mercatorMaterial;
+    }
+
+    /** Sets the texture url to use for the world map */
+    public set worldMapUrl(value: string) {
+        const scene = this._scene;
+        if (!this._mercatorMaterial) {
+            this._mercatorMaterial = new FluentMaterial("WorldMap", scene!);
+    
+            this._mercatorMaterial.backFaceCulling = false;
+    
+            this._mercatorMaterial.renderHoverLight = true;
+            this._mercatorMaterial.hoverRadius = 3;
+    
+            this._worldMapPickedPointObserver = this.onPickedPointChangedObservable.add(pickedPoint => {
+                if (pickedPoint) {
+                    this._mercatorMaterial!.hoverPosition = pickedPoint;
+                    this._mercatorMaterial!.hoverColor.a = 1.0;
+                } else {
+                    this._mercatorMaterial!.hoverColor.a = 0;
+                }
+            });
+        }
+
+        if (this._mercatorMaterial.albedoTexture) {
+            this._mercatorMaterial.albedoTexture.dispose();
+        }
+
+        const texture = new Texture(value, scene, false, true, Texture.LINEAR_LINEAR_MIPLINEAR, () => {
+            this.refresh();
+        });
+        this._mercatorMaterial.albedoTexture = texture;
+    }
     
     /**
      * Creates a new MapGraph
@@ -62,12 +134,7 @@ export class MapGraph extends Chart {
     constructor(name: string, mapUrl: string, scene: Nullable<Scene> = Engine.LastCreatedScene) {
         super(name, scene);
 
-        this._mercatorMaterial = new StandardMaterial("WorldMap", scene!);
-        this._mercatorMaterial.emissiveTexture = new Texture(mapUrl, scene, false, true, Texture.LINEAR_LINEAR_MIPLINEAR, () => {
-            this.refresh();
-        });
-        this._mercatorMaterial.disableLighting = true;
-        this._mercatorMaterial.backFaceCulling = false;
+        this.worldMapUrl = mapUrl;
     }
 
     protected _createCylinderMesh(name: string, scene: Scene): Mesh {
@@ -78,7 +145,7 @@ export class MapGraph extends Chart {
     }
 
     public refresh(): MapGraph {
-        if (this._blockRefresh || !this._mercatorMaterial || !this._mercatorMaterial.emissiveTexture!.isReady()) {
+        if (this._blockRefresh || !this._mercatorMaterial || !this._mercatorMaterial.albedoTexture!.isReady()) {
             return this;
         }
 
@@ -117,7 +184,7 @@ export class MapGraph extends Chart {
 
         this._removeLabels();
         
-        const worldMaptextureSize = this._mercatorMaterial.emissiveTexture!.getSize();
+        const worldMaptextureSize = this._mercatorMaterial.albedoTexture!.getSize();
         const worldMapWidth = this._worldMapSize;
         const worldMapHeight = worldMapWidth * worldMaptextureSize.height / worldMaptextureSize.width;
 
@@ -128,6 +195,7 @@ export class MapGraph extends Chart {
         this._worldMap = Mesh.CreateGround("WorldMap", worldMapWidth, worldMapHeight, 1, scene);
         this._worldMap.parent = this._rootNode;
         this._worldMap.material = this._mercatorMaterial;
+        this._worldMap.enablePointerMoveEvents = true;
 
         // Default material
         if (!this._defaultMaterial) {
@@ -160,7 +228,7 @@ export class MapGraph extends Chart {
             const latRad = latitude * Math.PI / 180;
             const mercN = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
             const z = worldMapWidth * mercN / (2 * Math.PI);
-            cylinderMesh.position.set(x, 0, z);
+            cylinderMesh.position.set(x + this._xOffset, 0.01, z + this._yOffset);
 
             var easing = new BABYLON.CircleEase();
             Animation.CreateAndStartAnimation("entryScale", cylinderMesh, "scaling.y", 30, 30, currentScalingYState, entry.value * ratio, 0, easing);
@@ -187,4 +255,12 @@ export class MapGraph extends Chart {
         this._worldMap = null;
         this._cylinderMeshes = null;
     }
+
+    public dispose() {
+        super.dispose();
+        if (this._worldMapPickedPointObserver) {
+            this.onPickedPointChangedObservable.remove(this._worldMapPickedPointObserver);
+            this._worldMapPickedPointObserver = null;    
+        }
+    }
 }

+ 22 - 2
gui/src/3D/materials/fluentMaterial.ts

@@ -1,4 +1,4 @@
-import { MaterialDefines, PushMaterial, serialize, expandToProperty, serializeAsColor3, Color3, serializeAsColor4, Color4, serializeAsVector3, Vector3, Scene, Nullable, BaseTexture, AbstractMesh, SubMesh, VertexBuffer, MaterialHelper, EffectCreationOptions, Matrix, Mesh, Tmp, SerializationHelper } from "babylonjs";
+import { MaterialDefines, PushMaterial, serialize, expandToProperty, serializeAsColor3, Color3, serializeAsColor4, Color4, serializeAsVector3, Vector3, Scene, Nullable, BaseTexture, AbstractMesh, SubMesh, VertexBuffer, MaterialHelper, EffectCreationOptions, Matrix, Mesh, Tmp, SerializationHelper, serializeAsTexture } from "babylonjs";
 
 import { registerShader } from "./shaders/fluent";
 
@@ -10,6 +10,7 @@ export class FluentMaterialDefines extends MaterialDefines {
     public INNERGLOW = false;
     public BORDER = false;
     public HOVERLIGHT = false;
+    public TEXTURE = false;
 
     constructor() {
         super();
@@ -97,6 +98,11 @@ export class FluentMaterial extends PushMaterial {
     @serializeAsVector3()
     public hoverPosition = Vector3.Zero();
 
+    @serializeAsTexture("albedoTexture")
+    private _albedoTexture: Nullable<BaseTexture>;
+    @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
+    public albedoTexture: Nullable<BaseTexture>;    
+
     /**
      * Creates a new Fluent material
      * @param name defines the name of the material
@@ -141,6 +147,16 @@ export class FluentMaterial extends PushMaterial {
             defines.INNERGLOW = this.innerGlowColorIntensity > 0;
             defines.BORDER = this.renderBorders;
             defines.HOVERLIGHT = this.renderHoverLight;
+
+            if (this._albedoTexture) {
+                if (!this._albedoTexture.isReadyOrNotBlocking()) {
+                    return false;
+                } else {
+                    defines.TEXTURE = true;
+                }
+            } else {
+                defines.TEXTURE = false;
+            }
         }
 
         var engine = scene.getEngine();
@@ -160,7 +176,7 @@ export class FluentMaterial extends PushMaterial {
                 "hoverColor", "hoverPosition", "hoverRadius"
             ];
 
-            var samplers = new Array<String>();
+            var samplers = ["albedoSampler"];
             var uniformBuffers = new Array<string>();
 
             MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
@@ -237,6 +253,10 @@ export class FluentMaterial extends PushMaterial {
                 this._activeEffect.setFloat("hoverRadius", this.hoverRadius);
                 this._activeEffect.setVector3("hoverPosition", this.hoverPosition);
             }
+
+            if (defines.TEXTURE) {
+                this._activeEffect.setTexture("albedoSampler", this._albedoTexture)
+            }
         }
 
         this._afterBind(mesh, this._activeEffect);

+ 8 - 0
gui/src/3D/materials/shaders/fluent.fragment.fx

@@ -22,11 +22,19 @@ uniform vec4 hoverColor;
 uniform float hoverRadius;
 #endif
 
+#ifdef TEXTURE
+uniform sampler2D albedoSampler;
+#endif
+
 void main(void) {
 
 	vec3 albedo = albedoColor.rgb;
 	float alpha = albedoColor.a;
 
+#ifdef TEXTURE
+	albedo = texture(albedoSampler, vUV).rgb;
+#endif
+
 #ifdef HOVERLIGHT
 	float pointToHover = (1.0 - clamp(length(hoverPosition - worldPosition) / hoverRadius, 0., 1.)) * hoverColor.a;
 	albedo = clamp(albedo + hoverColor.rgb * pointToHover, 0., 1.);