Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

sebavan 5 năm trước cách đây
mục cha
commit
159f16cbeb

+ 3 - 1
dist/preview release/what's new.md

@@ -9,7 +9,7 @@
 - Reflection probes can now be used to give accurate shading with PBR ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Added SubSurfaceScattering on PBR materials ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Added editing of PBR materials, Post processes and Particle fragment shaders in the node material editor ([Popov72](https://github.com/Popov72))
-- Added Curve editor to manage selected entity's animations and edit animation groups in Inspector ([pixelspace](https://github.com/devpixelspace))
+- Added Curve editor to manage entity's animations and edit animation groups in Inspector ([pixelspace](https://github.com/devpixelspace))
 - Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
 - Added support for **thin instances** for faster mesh instances. [Doc](https://doc.babylonjs.com/how_to/how_to_use_thininstances) ([Popov72](https://github.com/Popov72))
 
@@ -31,6 +31,7 @@
 - Don't log a message in `CustomProceduralTexture` if the `texturePath` is not a JSON path ([Popov72](https://github.com/Popov72))
 - Added an alternate option to the mesh edge renderer to generate edges faster / more accurately for unusual geometries (like the ones generated by CSG) ([Popov72](https://github.com/Popov72))
 - Added an option when creating the engine to switch matrix computation to 64 bits ([Popov72](https://github.com/Popov72))
+- Added support for the alpha component to the SSR post-process ([Popov72](https://github.com/Popov72))
 
 ### Engine
 
@@ -106,6 +107,7 @@
 - Use min/max values from position accessors (when available) to set the bounding box of meshes ([Popov72](https://github.com/Popov72))
 - Added missing "pluginExtension" parameter to SceneLoader.ImportAnimations. ([phenry20](https://github.com/phenry20))
 - Added support for .glb file loading through a base64 encoded filename ([Popov72](https://github.com/Popov72))
+- Fixed issue with loading screen hiding too early when loading multiple assets concurrently. ([bghgary](https://github.com/bghgary))
 
 ### Serializers
 

+ 196 - 100
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -38,8 +38,8 @@ interface ICanvasAxis {
 }
 
 export interface IActionableKeyFrame {
-  frame: number;
-  value: any;
+  frame?: number | string;
+  value?: any;
 }
 
 interface ICurveData {
@@ -90,6 +90,7 @@ export class AnimationCurveEditorComponent extends React.Component<
   private _svgKeyframes: IKeyframeSvgPoint[] = [];
   private _isPlaying: boolean = false;
   private _graphCanvas: React.RefObject<HTMLDivElement>;
+
   //private _selectedCurve: React.RefObject<SVGPathElement>;
   private _svgCanvas: React.RefObject<SvgDraggableArea>;
   private _isTargetedAnimation: boolean;
@@ -101,9 +102,8 @@ export class AnimationCurveEditorComponent extends React.Component<
   constructor(props: IAnimationCurveEditorComponentProps) {
     super(props);
     this._entityName = (this.props.entity as any).id;
-    // Review is we really need this refs
+
     this._graphCanvas = React.createRef();
-    //this._selectedCurve = React.createRef();
     this._svgCanvas = React.createRef();
 
     this._pixelFrameUnit = 10;
@@ -183,7 +183,7 @@ export class AnimationCurveEditorComponent extends React.Component<
       panningY: 0,
       panningX: 0,
       repositionCanvas: false,
-      actionableKeyframe: { frame: 0, value: 0 },
+      actionableKeyframe: { frame: undefined, value: undefined },
     };
   }
 
@@ -296,24 +296,59 @@ export class AnimationCurveEditorComponent extends React.Component<
     }
   }
 
+  encodeCurveId(animationName: string, coordinate: number) {
+    return animationName + '_' + coordinate;
+  }
+
+  decodeCurveId(id: string) {
+    const order = parseInt(id.split('_')[3]);
+    const coordinate = parseInt(id.split('_')[2]);
+    return { order, coordinate };
+  }
+
+  getKeyframeValueFromAnimation(id: string) {
+    const animation = this.state.selected as Animation;
+    const { order, coordinate } = this.decodeCurveId(id);
+    const keys = [...animation.getKeys()];
+
+    const key = keys.find((_, i) => i === order);
+
+    if (key) {
+      const valueAsArray = this.getValueAsArray(animation.dataType, key.value);
+      return { frame: key?.frame, value: valueAsArray[coordinate] };
+    } else {
+      return undefined;
+    }
+  }
+
   /**
    * Keyframe Manipulation
    * This section handles events from SvgDraggableArea.
    */
   selectKeyframe(id: string, multiselect: boolean) {
-    let selectedKeyFrame = this.state.svgKeyframes?.find((kf) => kf.id === id)
+    const frameValue = this.getKeyframeValueFromAnimation(id);
+    const selectedKeyFrame = this.state.svgKeyframes?.find((kf) => kf.id === id)
       ?.selected;
     if (!multiselect) {
       this.deselectKeyframes();
     }
 
-    let updatedKeyframes = this.state.svgKeyframes?.map((kf) => {
+    const updatedKeyframes = this.state.svgKeyframes?.map((kf) => {
       if (kf.id === id) {
         kf.selected = !selectedKeyFrame;
       }
       return kf;
     });
-    this.setState({ svgKeyframes: updatedKeyframes });
+    this.setState({
+      svgKeyframes: updatedKeyframes,
+      actionableKeyframe: frameValue ?? this.state.actionableKeyframe,
+    });
+  }
+
+  resetActionableKeyframe() {
+    this.setState({
+      actionableKeyframe: { frame: undefined, value: undefined },
+    });
   }
 
   selectedControlPoint(type: string, id: string) {
@@ -341,7 +376,10 @@ export class AnimationCurveEditorComponent extends React.Component<
       kf.selected = false;
       return kf;
     });
-    this.setState({ svgKeyframes: updatedKeyframes });
+    this.setState({
+      svgKeyframes: updatedKeyframes,
+      actionableKeyframe: { frame: undefined, value: undefined },
+    });
   }
 
   updateValuePerCoordinate(
@@ -443,10 +481,8 @@ export class AnimationCurveEditorComponent extends React.Component<
 
   renderPoints(updatedSvgKeyFrame: IKeyframeSvgPoint, id: string) {
     let animation = this.state.selected as Animation;
-    // Bug: After play/stop we get an extra keyframe at 0
-    let index = parseInt(id.split('_')[3]);
 
-    let coordinate = parseInt(id.split('_')[2]);
+    const { order: index, coordinate } = this.decodeCurveId(id);
 
     let keys = [...animation.getKeys()];
 
@@ -492,13 +528,15 @@ export class AnimationCurveEditorComponent extends React.Component<
         this._heightScale) *
       2; // this value comes inverted svg from 0 = 100 to 100 = 0
 
-    keys[index].value = this.updateValuePerCoordinate(
+    const updatedValueInCoordinate = this.updateValuePerCoordinate(
       animation.dataType,
       keys[index].value,
       updatedValue,
       coordinate
     );
 
+    keys[index].value = updatedValueInCoordinate;
+
     this.updateLeftControlPoint(
       updatedSvgKeyFrame,
       keys[index],
@@ -514,6 +552,10 @@ export class AnimationCurveEditorComponent extends React.Component<
 
     animation.setKeys(keys);
 
+    this.setState({
+      actionableKeyframe: { frame: newFrame, value: updatedValueInCoordinate },
+    });
+
     this.selectAnimation(animation, coordinate);
   }
 
@@ -594,81 +636,81 @@ export class AnimationCurveEditorComponent extends React.Component<
     }
   }
 
-  /**
-   * Actions
-   * This section handles events from GraphActionsBar.
-   */
   handleFrameChange(event: React.ChangeEvent<HTMLInputElement>) {
     event.preventDefault();
-    let frame = 0;
 
-    if (
-      isNaN(event.target.valueAsNumber) ||
-      event.target.value.indexOf('.') !== -1
-    ) {
-      this.setState({
-        notification: 'Frame input only accepts integer values',
-      });
+    let frame;
+    if (event.target.value === '') {
+      frame = '';
     } else {
-      if (this.state.selected !== null) {
-        let animation = this.state.selected;
-        let keys = animation.getKeys();
-        frame = parseInt(event.target.value);
-
-        let isKeyframe = keys.find((k) => k.frame === frame);
-
-        let value = this.state.actionableKeyframe.value;
-
-        if (isKeyframe) {
-          value = isKeyframe.value;
-        }
-
-        this.setState({
-          actionableKeyframe: {
-            frame: frame,
-            value: value,
-          },
-        });
-      }
+      frame = parseInt(event.target.value);
     }
+
+    this.setState({
+      actionableKeyframe: {
+        frame: frame,
+        value: this.state.actionableKeyframe.value,
+      },
+    });
   }
 
   handleValueChange(event: React.ChangeEvent<HTMLInputElement>) {
     event.preventDefault();
 
-    if (isNaN(event.target.valueAsNumber)) {
+    let value;
+
+    if (event.target.value !== undefined) {
+      if (event.target.value !== '') {
+        value = parseFloat(event.target.value);
+      } else {
+        value = '';
+      }
+
       this.setState({
-        notification: 'Value input only numeric values',
-      });
-    } else {
-      this.setState(
-        {
-          actionableKeyframe: {
-            frame: this.state.actionableKeyframe.frame,
-            value: parseFloat(parseFloat(event.target.value).toFixed(3)),
-          },
+        actionableKeyframe: {
+          frame: this.state.actionableKeyframe.frame,
+          value: value,
         },
-        () => {
-          if (this.state.selected !== null) {
-            let animation = this.state.selected;
-            let keys = animation.getKeys();
+      });
+    }
+  }
 
-            let isKeyframe = keys.find(
-              (k) => k.frame === this.state.actionableKeyframe.frame
-            );
-            if (isKeyframe) {
-              let updatedKeys = keys.map((k) => {
-                if (k.frame === this.state.actionableKeyframe.frame) {
-                  k.value = this.state.actionableKeyframe.value;
-                }
-                return k;
-              });
-              this.state.selected.setKeys(updatedKeys);
-              this.selectAnimation(animation);
-            }
+  setKeyframeValue() {
+    if (
+      this.state.actionableKeyframe.frame !== '' &&
+      this.state.actionableKeyframe.frame !== undefined &&
+      this.state.actionableKeyframe.value !== '' &&
+      this.state.actionableKeyframe.value !== undefined
+    ) {
+      if (this.state.selected !== null) {
+        let currentSelected = this.state.svgKeyframes?.find(
+          (kf) => kf.selected
+        );
+        if (currentSelected) {
+          let { order, coordinate } = this.decodeCurveId(currentSelected.id);
+          let animation = this.state.selected;
+          let keys = animation.getKeys();
+
+          let isKeyframe = keys.find((_, i) => i === order);
+          if (isKeyframe) {
+            let updatedKeys = keys.map((k, i) => {
+              if (i === order) {
+                k.frame = this.state.actionableKeyframe.frame as number;
+
+                const currentValue = this.getValueAsArray(
+                  animation.dataType,
+                  k.value
+                );
+                currentValue[coordinate] = this.state.actionableKeyframe.value;
+                k.value = currentValue;
+              }
+              return k;
+            });
+            this.state.selected.setKeys(updatedKeys);
+            this.selectAnimation(animation);
           }
         }
-      );
+      }
     }
   }
 
@@ -713,18 +755,46 @@ export class AnimationCurveEditorComponent extends React.Component<
     if (this.state.selected !== null) {
       let currentAnimation = this.state.selected;
 
-      if (currentAnimation.dataType === Animation.ANIMATIONTYPE_FLOAT) {
-        let keys = currentAnimation.getKeys();
-        let x = this.state.actionableKeyframe.frame;
-        let y = this.state.actionableKeyframe.value;
+      let keys = currentAnimation.getKeys();
+      let x = this.state.currentFrame;
+      let y = this.state.actionableKeyframe.value ?? 1;
+      // check if value exists...
+      let arrayValue: any = [];
+      let emptyValue = this.returnZero(currentAnimation.dataType);
+      let existValue = keys.find((k) => k.frame === x);
+      if (existValue !== undefined) {
+        arrayValue = this.getValueAsArray(
+          currentAnimation.dataType,
+          existValue.value
+        );
+      } else {
+        // Set empty if doesn't exist
+        if (emptyValue) {
+          arrayValue = this.getValueAsArray(
+            currentAnimation.dataType,
+            emptyValue
+          );
+        }
+      }
 
-        keys.push({ frame: x, value: y, inTangent: 0, outTangent: 0 });
-        keys.sort((a, b) => a.frame - b.frame);
+      arrayValue[this.state.selectedCoordinate] = y;
 
-        currentAnimation.setKeys(keys);
+      let actualValue = this.setValueAsType(
+        currentAnimation.dataType,
+        arrayValue
+      );
 
-        this.selectAnimation(currentAnimation);
-      }
+      keys.push({
+        frame: x,
+        value: actualValue,
+        inTangent: emptyValue,
+        outTangent: emptyValue,
+      });
+      keys.sort((a, b) => a.frame - b.frame);
+
+      currentAnimation.setKeys(keys);
+
+      this.selectAnimation(currentAnimation, this.state.selectedCoordinate);
     }
   }
 
@@ -868,31 +938,24 @@ export class AnimationCurveEditorComponent extends React.Component<
   }
 
   returnZero(dataType: number) {
-    let type;
     switch (dataType) {
       case Animation.ANIMATIONTYPE_FLOAT:
-        type = 0;
-        break;
+        return 0;
       case Animation.ANIMATIONTYPE_VECTOR3:
-        type = Vector3.Zero();
-        break;
+        return Vector3.Zero();
       case Animation.ANIMATIONTYPE_VECTOR2:
-        type = Vector2.Zero();
-        break;
+        return Vector2.Zero();
       case Animation.ANIMATIONTYPE_QUATERNION:
-        type = Quaternion.Zero();
-        break;
+        return Quaternion.Zero();
       case Animation.ANIMATIONTYPE_COLOR3:
-        type = new Color3(0, 0, 0);
-        break;
+        return new Color3(0, 0, 0);
       case Animation.ANIMATIONTYPE_COLOR4:
-        type = new Color4(0, 0, 0, 0);
-        break;
+        return new Color4(0, 0, 0, 0);
       case Animation.ANIMATIONTYPE_SIZE:
-        type = new Size(0, 0);
-        break;
+        return new Size(0, 0);
+      default:
+        return 0;
     }
-    return type;
   }
 
   getValueAsArray(
@@ -926,6 +989,37 @@ export class AnimationCurveEditorComponent extends React.Component<
     return valueAsArray;
   }
 
+  setValueAsType(valueType: number, arrayValue: number[]) {
+    switch (valueType) {
+      case Animation.ANIMATIONTYPE_FLOAT:
+        return arrayValue[0];
+      case Animation.ANIMATIONTYPE_VECTOR3:
+        return new Vector3(arrayValue[0], arrayValue[1], arrayValue[2]);
+      case Animation.ANIMATIONTYPE_VECTOR2:
+        return new Vector2(arrayValue[0], arrayValue[1]);
+      case Animation.ANIMATIONTYPE_QUATERNION:
+        return new Quaternion(
+          arrayValue[0],
+          arrayValue[1],
+          arrayValue[2],
+          arrayValue[3]
+        );
+      case Animation.ANIMATIONTYPE_COLOR3:
+        return new Color3(arrayValue[0], arrayValue[1], arrayValue[2]);
+      case Animation.ANIMATIONTYPE_COLOR4:
+        return new Color4(
+          arrayValue[0],
+          arrayValue[1],
+          arrayValue[2],
+          arrayValue[3]
+        );
+      case Animation.ANIMATIONTYPE_SIZE:
+        return new Size(arrayValue[0], arrayValue[1]);
+      default:
+        return arrayValue[0];
+    }
+  }
+
   getPathData(animation: Animation | null) {
     if (animation === null) {
       return undefined;
@@ -1077,7 +1171,7 @@ export class AnimationCurveEditorComponent extends React.Component<
   ) {
     keyframes.forEach((key, i) => {
       // Create a unique id for curve
-      const curveId = animationName + '_' + i;
+      const curveId = this.encodeCurveId(animationName, i);
 
       // identify type of value and split...
       const keyframe_valueAsArray = this.getValueAsArray(type, key.value)[
@@ -1472,7 +1566,7 @@ export class AnimationCurveEditorComponent extends React.Component<
 
         this.setState({
           currentFrame: frame,
-          currentValue: parseFloat(currentValue.toFixed(3)),
+          currentValue: currentValue,
           currentPoint: currentP,
           isPlaying: false,
         });
@@ -1603,6 +1697,7 @@ export class AnimationCurveEditorComponent extends React.Component<
           close={() => this.clearNotification()}
         />
         <GraphActionsBar
+          setKeyframeValue={() => this.setKeyframeValue()}
           enabled={
             this.state.selected === null || this.state.selected === undefined
               ? false
@@ -1683,6 +1778,7 @@ export class AnimationCurveEditorComponent extends React.Component<
                   canvasPositionEnded={() =>
                     this.setState({ repositionCanvas: false })
                   }
+                  resetActionableKeyframe={() => this.resetActionableKeyframe()}
                 >
                   {/* Multiple Curves  */}
                   {this.state.selectedPathData?.map((curve, i) => (

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationListTree.tsx

@@ -122,7 +122,7 @@ export class AnimationListTree extends React.Component<
     index: number
   ) {
     this.setState({ selectedCoordinate: coordinate, selectedAnimation: index });
-    this.props.selectAnimation(animation, SelectedCoordinate.x);
+    this.props.selectAnimation(animation, coordinate);
   }
 
   coordinateItem(

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/curveEditor.scss

@@ -485,7 +485,7 @@
       align-items: center;
       margin-right: 8px;
       input {
-        width: 75px;
+        width: 78px;
         height: 24px;
         color: white;
         font-size: 12px;

+ 50 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx

@@ -16,11 +16,53 @@ interface IGraphActionsBarProps {
   title: string;
   close: (event: any) => void;
   enabled: boolean;
+  setKeyframeValue: () => void;
 }
 
 export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
+  private _frameInput: React.RefObject<HTMLInputElement>;
+  private _valueInput: React.RefObject<HTMLInputElement>;
   constructor(props: IGraphActionsBarProps) {
     super(props);
+    this._frameInput = React.createRef();
+    this._valueInput = React.createRef();
+  }
+
+  componentDidMount() {
+    this._frameInput.current?.addEventListener(
+      'keyup',
+      this.isEnterKeyUp.bind(this)
+    );
+    this._valueInput.current?.addEventListener(
+      'keyup',
+      this.isEnterKeyUp.bind(this)
+    );
+  }
+
+  componentWillUnmount() {
+    this._frameInput.current?.removeEventListener(
+      'keyup',
+      this.isEnterKeyUp.bind(this)
+    );
+    this._valueInput.current?.removeEventListener(
+      'keyup',
+      this.isEnterKeyUp.bind(this)
+    );
+  }
+
+  isEnterKeyUp(event: KeyboardEvent) {
+    event.preventDefault();
+
+    if (event.key === 'Enter') {
+      this.props.setKeyframeValue();
+    }
+  }
+
+  onBlur(event: React.FocusEvent<HTMLInputElement>) {
+    event.preventDefault();
+    if (event.target.value !== '') {
+      this.props.setKeyframeValue();
+    }
   }
 
   render() {
@@ -36,18 +78,24 @@ export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
         >
           <div className='action-input frame-input'>
             <input
+              ref={this._frameInput}
               type='number'
               onChange={this.props.handleFrameChange}
-              value={this.props.actionableKeyframe.frame}
+              value={this.props.actionableKeyframe.frame?.toString() || ''}
               step='1'
+              disabled={this.props.actionableKeyframe.frame === undefined}
+              onBlur={(e) => this.onBlur(e)}
             />
           </div>
           <div className='action-input'>
             <input
+              ref={this._valueInput}
               type='number'
-              value={this.props.actionableKeyframe.value}
+              value={this.props.actionableKeyframe.value || ''}
               onChange={this.props.handleValueChange}
               step='0.01'
+              disabled={this.props.actionableKeyframe.value === undefined}
+              onBlur={(e) => this.onBlur(e)}
             />
           </div>
           <IconButtonLineComponent

+ 5 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/svgDraggableArea.tsx

@@ -17,6 +17,7 @@ interface ISvgDraggableAreaProps {
   positionCanvas?: number;
   repositionCanvas?: boolean;
   canvasPositionEnded: () => void;
+  resetActionableKeyframe: () => void;
 }
 
 export class SvgDraggableArea extends React.Component<
@@ -251,13 +252,15 @@ export class SvgDraggableArea extends React.Component<
     this._draggableArea.current?.focus();
 
     if ((e.target as SVGSVGElement).className.baseVal == 'linear pannable') {
-      if (this.isControlPointActive()) {
+      if (this.isNotControlPointActive()) {
         this.props.deselectKeyframes();
       }
+
+      this.props.resetActionableKeyframe();
     }
   }
 
-  isControlPointActive() {
+  isNotControlPointActive() {
     const activeControlPoints = this.props.keyframeSvgPoints.filter(
       (x) => x.isLeftActive || x.isRightActive
     );

+ 8 - 16
src/Loading/sceneLoader.ts

@@ -352,6 +352,8 @@ export class SceneLoader {
 
     private static _registeredPlugins: { [extension: string]: IRegisteredPlugin } = {};
 
+    private static _showingLoadingScreen = false;
+
     private static _getDefaultPlugin(): IRegisteredPlugin {
         return SceneLoader._registeredPlugins[".babylon"];
     }
@@ -785,8 +787,13 @@ export class SceneLoader {
             return null;
         }
 
-        if (SceneLoader.ShowLoadingScreen) {
+        if (SceneLoader.ShowLoadingScreen && !this._showingLoadingScreen) {
+            this._showingLoadingScreen = true;
             scene.getEngine().displayLoadingUI();
+            scene.executeWhenReady(() => {
+                scene.getEngine().hideLoadingUI();
+                this._showingLoadingScreen = false;
+            });
         }
 
         var loadingToken = {};
@@ -794,9 +801,6 @@ export class SceneLoader {
 
         var disposeHandler = () => {
             scene._removePendingData(loadingToken);
-            if (SceneLoader.ShowLoadingScreen) {
-                scene.getEngine().hideLoadingUI();
-            }
         };
 
         var errorHandler = (message: Nullable<string>, exception?: any) => {
@@ -851,12 +855,6 @@ export class SceneLoader {
                     errorHandler(error.message, error);
                 });
             }
-
-            if (SceneLoader.ShowLoadingScreen) {
-                scene.executeWhenReady(() => {
-                    scene.getEngine().hideLoadingUI();
-                });
-            }
         }, progressHandler, errorHandler, disposeHandler, pluginExtension);
     }
 
@@ -976,12 +974,6 @@ export class SceneLoader {
             } else {
                 errorHandler("LoadAssetContainer is not supported by this plugin. Plugin did not provide a loadAssetContainer or loadAssetContainerAsync method.");
             }
-
-            if (SceneLoader.ShowLoadingScreen) {
-                scene.executeWhenReady(() => {
-                    scene.getEngine().hideLoadingUI();
-                });
-            }
         }, progressHandler, errorHandler, disposeHandler, pluginExtension);
     }
 

+ 4 - 3
src/Shaders/screenSpaceReflection.fragment.fx

@@ -126,10 +126,11 @@ void main()
 {
     #ifdef SSR_SUPPORTED
         // Intensity
-        vec3 albedo = texture2D(textureSampler, vUV).rgb;
+        vec4 albedoFull = texture2D(textureSampler, vUV);
+        vec3 albedo = albedoFull.rgb;
         float spec = texture2D(reflectivitySampler, vUV).r;
         if (spec == 0.0) {
-            gl_FragColor = vec4(albedo, 1.0);
+            gl_FragColor = albedoFull;
             return;
         }
         
@@ -157,7 +158,7 @@ void main()
         float albedoMultiplier = 1.0 - reflectionMultiplier;
         vec3 SSR = info.color * fresnel;
 
-        gl_FragColor = vec4((albedo * albedoMultiplier) + (SSR * reflectionMultiplier), 1.0);
+        gl_FragColor = vec4((albedo * albedoMultiplier) + (SSR * reflectionMultiplier), albedoFull.a);
     #else
         gl_FragColor = texture2D(textureSampler, vUV);
     #endif