Bladeren bron

Merge pull request #7768 from Popov72/inspector-linearcolor

Inspector: Handle PBR colors as colors in linear space
mergify[bot] 5 jaren geleden
bovenliggende
commit
f1e1278f7d

+ 4 - 0
dist/preview release/what's new.md

@@ -16,6 +16,10 @@
 
 - Allow logging of shader code when a compilation error occurs ([Popov72](https://github.com/Popov72))
 
+### Inspector
+
+- Handle PBR colors as colors in linear space ([Popov72](https://github.com/Popov72))
+
 ### Cameras
 
 - Added flag to TargetCamera to invert rotation direction and multiplier to adjust speed ([Exolun](https://github.com/Exolun))

+ 22 - 11
inspector/src/components/actionTabs/lines/color3LineComponent.tsx

@@ -13,6 +13,7 @@ export interface IColor3LineComponentProps {
     target: any;
     propertyName: string;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    isLinear?: boolean;
 }
 
 export class Color3LineComponent extends React.Component<IColor3LineComponentProps, { isExpanded: boolean, color: Color3 }> {
@@ -21,10 +22,16 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
         super(props);
 
         this.state = { isExpanded: false, color: this.props.target[this.props.propertyName].clone() };
+
+        if (props.isLinear) {
+            this.state.color.toGammaSpaceToRef(this.state.color);
+        }
+
+        props.target._isLinearColor = props.isLinear; // so that replayRecorder can append toLinearSpace() as appropriate
     }
 
     shouldComponentUpdate(nextProps: IColor3LineComponentProps, nextState: { color: Color3 }) {
-        const currentState = nextProps.target[nextProps.propertyName];
+        const currentState = this.props.isLinear ? nextProps.target[nextProps.propertyName].toGammaSpace() : nextProps.target[nextProps.propertyName];
 
         if (!currentState.equals(nextState.color) || this._localChange) {
             nextState.color = currentState.clone();
@@ -34,6 +41,14 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
         return false;
     }
 
+    setPropertyValue(newColor: Color3) {
+        this.props.target[this.props.propertyName] = newColor;
+
+        if (this.props.isLinear) {
+            this.props.target[this.props.propertyName] = newColor.toLinearSpace();
+        }
+    }
+
     onChange(newValue: string) {
         this._localChange = true;
         const newColor = Color3.FromHexString(newValue);
@@ -43,11 +58,11 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
                 object: this.props.target,
                 property: this.props.propertyName,
                 value: newColor,
-                initialValue: this.state.color
+                initialValue: this.state.color,
             });
         }
 
-        this.props.target[this.props.propertyName] = newColor;
+        this.setPropertyValue(newColor);
 
         this.setState({ color: newColor });
     }
@@ -58,7 +73,6 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
     }
 
     raiseOnPropertyChanged(previousValue: Color3) {
-
         if (!this.props.onPropertyChangedObservable) {
             return;
         }
@@ -66,7 +80,7 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
             object: this.props.target,
             property: this.props.propertyName,
             value: this.state.color,
-            initialValue: previousValue
+            initialValue: previousValue,
         });
     }
 
@@ -74,9 +88,8 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].x = value;
         this.state.color.r = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);
@@ -86,9 +99,8 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].g = value;
         this.state.color.g = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);
@@ -98,9 +110,8 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].b = value;
         this.state.color.b = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);

+ 33 - 15
inspector/src/components/actionTabs/lines/color4LineComponent.tsx

@@ -14,6 +14,7 @@ export interface IColor4LineComponentProps {
     propertyName: string;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     onChange?: () => void;
+    isLinear?: boolean;
 }
 
 export class Color4LineComponent extends React.Component<IColor4LineComponentProps, { isExpanded: boolean, color: Color4 }> {
@@ -24,12 +25,22 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
         let value = this.props.target[this.props.propertyName];
         let currentColor = value.getClassName() === "Color4" ? value.clone() : new Color4(value.r, value.g, value.b, 1.0);
         this.state = { isExpanded: false, color: currentColor };
+
+        if (props.isLinear) {
+            this.state.color.toGammaSpaceToRef(this.state.color);
+        }
+
+        props.target._isLinearColor = props.isLinear; // so that replayRecorder can append toLinearSpace() as appropriate
     }
 
     shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: { color: Color4 }) {
         let value = this.props.target[this.props.propertyName];
         let currentColor = value.getClassName() === "Color4" ? value : new Color4(value.r, value.g, value.b, 1.0);
 
+        if (this.props.isLinear) {
+            currentColor.toGammaSpaceRef(currentColor);
+        }
+
         if (!currentColor.equals(nextState.color) || this._localChange) {
             nextState.color = currentColor.clone();
             this._localChange = false;
@@ -38,6 +49,14 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
         return false;
     }
 
+    setPropertyValue(newColor: Color4) {
+        this.props.target[this.props.propertyName] = newColor;
+
+        if (this.props.isLinear) {
+            this.props.target[this.props.propertyName] = newColor.toLinearSpace();
+        }
+    }
+
     onChange(newValue: string) {
         this._localChange = true;
         const newColor = Color3.FromHexString(newValue);
@@ -47,13 +66,15 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
                 object: this.props.target,
                 property: this.props.propertyName,
                 value: newColor,
-                initialValue: this.state.color
+                initialValue: this.state.color,
             });
         }
 
-        this.props.target[this.props.propertyName] = new Color4(newColor.r, newColor.g, newColor.b, this.props.target[this.props.propertyName].a);
+        const newColor4 = new Color4(newColor.r, newColor.g, newColor.b, this.props.target[this.props.propertyName].a);
+
+        this.setPropertyValue(newColor4);
 
-        this.setState({ color: this.props.target[this.props.propertyName] });
+        this.setState({ color: newColor4 });
 
         if (this.props.onChange) {
             this.props.onChange();
@@ -73,7 +94,7 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
             object: this.props.target,
             property: this.props.propertyName,
             value: this.state.color,
-            initialValue: previousValue
+            initialValue: previousValue,
         });
     }
 
@@ -81,9 +102,8 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].x = value;
         this.state.color.r = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);
@@ -93,9 +113,8 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].g = value;
         this.state.color.g = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);
@@ -105,9 +124,8 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
         this._localChange = true;
 
         const store = this.state.color.clone();
-        this.props.target[this.props.propertyName].b = value;
         this.state.color.b = value;
-        this.props.target[this.props.propertyName] = this.state.color;
+        this.setPropertyValue(this.state.color);
         this.setState({ color: this.state.color });
 
         this.raiseOnPropertyChanged(store);
@@ -143,7 +161,7 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
 
     render() {
 
-        const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />
+        const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />;
         const colorAsColor3 = new Color3(this.state.color.r, this.state.color.g, this.state.color.b);
 
         return (
@@ -165,10 +183,10 @@ export class Color4LineComponent extends React.Component<IColor4LineComponentPro
                 {
                     this.state.isExpanded &&
                     <div className="secondLine">
-                        <NumericInputComponent label="r" value={this.state.color.r} onChange={value => this.updateStateR(value)} />
-                        <NumericInputComponent label="g" value={this.state.color.g} onChange={value => this.updateStateG(value)} />
-                        <NumericInputComponent label="b" value={this.state.color.b} onChange={value => this.updateStateB(value)} />
-                        <NumericInputComponent label="a" value={this.state.color.a} onChange={value => this.updateStateA(value)} />
+                        <NumericInputComponent label="r" value={this.state.color.r} onChange={(value) => this.updateStateR(value)} />
+                        <NumericInputComponent label="g" value={this.state.color.g} onChange={(value) => this.updateStateG(value)} />
+                        <NumericInputComponent label="b" value={this.state.color.b} onChange={(value) => this.updateStateB(value)} />
+                        <NumericInputComponent label="a" value={this.state.color.a} onChange={(value) => this.updateStateA(value)} />
                     </div>
                 }
             </div>

+ 8 - 8
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -141,11 +141,11 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                 <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 {this.renderTextures(this._onDebugSelectionChangeObservable)}
                 <LineContainerComponent globalState={this.props.globalState} title="LIGHTING & COLORS">
-                    <Color3LineComponent label="Albedo" target={material} propertyName="albedoColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Reflectivity" target={material} propertyName="reflectivityColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <Color3LineComponent label="Albedo" target={material} propertyName="albedoColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true}/>
+                    <Color3LineComponent label="Reflectivity" target={material} propertyName="reflectivityColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                     <SliderLineComponent label="Micro-surface" target={material} propertyName="microSurface" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Ambient" target={material} propertyName="ambientColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
+                    <Color3LineComponent label="Ambient" target={material} propertyName="ambientColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                     <CheckBoxLineComponent label="Use physical light falloff" target={material} propertyName="usePhysicalLightFalloff" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="METALLIC WORKFLOW">
@@ -175,7 +175,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                             <CheckBoxLineComponent label="Tint" target={material.clearCoat} propertyName="isTintEnabled" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             {
                                 material.clearCoat.isEnabled && material.clearCoat.isTintEnabled &&
-                                <Color3LineComponent label="Tint Color" target={material.clearCoat} propertyName="tintColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                                <Color3LineComponent label="Tint Color" target={material.clearCoat} propertyName="tintColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                             }
                             {
                                 material.clearCoat.isEnabled && material.clearCoat.isTintEnabled &&
@@ -214,7 +214,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                         <div className="fragment">
                             <CheckBoxLineComponent label="Link to Albedo" target={material.sheen} propertyName="linkSheenWithAlbedo" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <SliderLineComponent label="Intensity" target={material.sheen} propertyName="intensity" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <Color3LineComponent label="Color" target={material.sheen} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <Color3LineComponent label="Color" target={material.sheen} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                             <TextureLinkLineComponent label="Texture" texture={material.sheen.texture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} />
                             <CheckBoxLineComponent label="Use roughness" target={material.sheen} propertyName="_useRoughness" />
                             { (material.sheen as any)._useRoughness &&
@@ -231,7 +231,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                     <CheckBoxLineComponent label="Mask From Thickness" target={material.subSurface} propertyName="useMaskFromThicknessTexture"
                         onValueChanged={() => this.forceUpdate()}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Tint Color" target={material.subSurface} propertyName="tintColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <Color3LineComponent label="Tint Color" target={material.subSurface} propertyName="tintColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
 
                     <CheckBoxLineComponent label="Refraction Enabled" target={material.subSurface} propertyName="isRefractionEnabled"
                         onValueChanged={() => this.forceUpdate()}
@@ -253,7 +253,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                         material.subSurface.isTranslucencyEnabled &&
                         <div className="fragment">
                             <SliderLineComponent label="Intensity" target={material.subSurface} propertyName="translucencyIntensity" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <Color3LineComponent label="Diffusion Distance" target={material.subSurface} propertyName="diffusionDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <Color3LineComponent label="Diffusion Distance" target={material.subSurface} propertyName="diffusionDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                         </div>
                     }
                 </LineContainerComponent>

+ 2 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMetallicRoughnessMaterialPropertyGridComponent.tsx

@@ -52,8 +52,8 @@ export class PBRMetallicRoughnessMaterialPropertyGridComponent extends React.Com
                 <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 {this.renderTextures()}
                 <LineContainerComponent globalState={this.props.globalState} title="LIGHTING & COLORS">
-                    <Color3LineComponent label="Base" target={material} propertyName="baseColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <Color3LineComponent label="Base" target={material} propertyName="baseColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
+                    <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="LEVELS" closed={true}>
                     <SliderLineComponent label="Metallic" target={material} propertyName="metallic" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 2 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrSpecularGlossinessMaterialPropertyGridComponent.tsx

@@ -52,8 +52,8 @@ export class PBRSpecularGlossinessMaterialPropertyGridComponent extends React.Co
                 <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 {this.renderTextures()}
                 <LineContainerComponent globalState={this.props.globalState} title="LIGHTING & COLORS">
-                    <Color3LineComponent label="Diffuse" target={material} propertyName="diffuseColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <Color3LineComponent label="Specular" target={material} propertyName="specularColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <Color3LineComponent label="Diffuse" target={material} propertyName="diffuseColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
+                    <Color3LineComponent label="Specular" target={material} propertyName="specularColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} isLinear={true} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="LEVELS" closed={true}>
                     <SliderLineComponent label="Glossiness" target={material} propertyName="glossiness" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 6 - 0
inspector/src/components/replayRecorder.ts

@@ -62,8 +62,14 @@ export class ReplayRecorder {
                 value = `new BABYLON.Vector2(${value.x}, ${value.y})`;
             } else if (value.a !== undefined) { // Color4
                 value = `new BABYLON.Color4(${value.r}, ${value.g}, ${value.b}, ${value.a})`;
+                if (event.object._isLinearColor) {
+                    value += '.toLinearSpace()';
+                }
             } else if (value.b !== undefined) { // Color3
                 value = `new BABYLON.Color3(${value.r}, ${value.g}, ${value.b})`;
+                if (event.object._isLinearColor) {
+                    value += '.toLinearSpace()';
+                }
             } else if (value.getClassName) {
                 value = this._getIndirectData(value);
             }