Pārlūkot izejas kodu

Merge pull request #9284 from Popov72/nme-color-spaceconversion

NME: Add space conversion to input colors3/4
David Catuhe 4 gadi atpakaļ
vecāks
revīzija
798730d97c

+ 51 - 37
nodeEditor/src/diagram/properties/inputNodePropertyComponent.tsx

@@ -24,46 +24,46 @@ import { Nullable } from 'babylonjs/types';
 import { Observer } from 'babylonjs/Misc/observable';
 
 export class InputPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-    
+
     private onValueChangedObserver: Nullable<Observer<InputBlock>>;
 
     constructor(props: IPropertyComponentProps) {
-        super(props)
+        super(props);
     }
 
-    componentDidMount() {        
+    componentDidMount() {
         let inputBlock = this.props.block as InputBlock;
         this.onValueChangedObserver = inputBlock.onValueChangedObservable.add(() => {
-            this.forceUpdate()
+            this.forceUpdate();
             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
         });
     }
 
     componentWillUnmount() {
-        
+
         let inputBlock = this.props.block as InputBlock;
         if (this.onValueChangedObserver) {
             inputBlock.onValueChangedObservable.remove(this.onValueChangedObserver);
             this.onValueChangedObserver = null;
         }
-    }    
+    }
 
     renderValue(globalState: GlobalState) {
         let inputBlock = this.props.block as InputBlock;
         switch (inputBlock.type) {
             case NodeMaterialBlockConnectionPointTypes.Float: {
-                let cantDisplaySlider = (isNaN(inputBlock.min) || isNaN(inputBlock.max) || inputBlock.min === inputBlock.max);            
+                let cantDisplaySlider = (isNaN(inputBlock.min) || isNaN(inputBlock.max) || inputBlock.min === inputBlock.max);
                 return (
                     <>
                         <CheckBoxLineComponent label="Is boolean" target={inputBlock} propertyName="isBoolean" />
                         {
                             inputBlock.isBoolean &&
                             <CheckBoxLineComponent label="Value" isSelected={() => {
-                                return inputBlock.value === 1
+                                return inputBlock.value === 1;
                             }} onSelect={(value) => {
                                 inputBlock.value = value ? 1 : 0;
                                 if (inputBlock.isConstant) {
-                                    this.props.globalState.onRebuildRequiredObservable.notifyObservers();    
+                                    this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                                 }
                                 this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                             }}/>
@@ -74,17 +74,17 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         }
                         {
                             !inputBlock.isBoolean &&
-                            <FloatLineComponent globalState={this.props.globalState} label="Max" target={inputBlock} propertyName="max" onChange={() => this.forceUpdate()}></FloatLineComponent>      
+                            <FloatLineComponent globalState={this.props.globalState} label="Max" target={inputBlock} propertyName="max" onChange={() => this.forceUpdate()}></FloatLineComponent>
                         }
                         {
                             !inputBlock.isBoolean && cantDisplaySlider &&
                             <FloatPropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
-                        }        
+                        }
                         {
                             !inputBlock.isBoolean && !cantDisplaySlider &&
                             <SliderLineComponent label="Value" globalState={this.props.globalState} target={inputBlock} propertyName="value" step={Math.abs(inputBlock.max - inputBlock.min) / 100.0} minimum={Math.min(inputBlock.min, inputBlock.max)} maximum={inputBlock.max} onChange={() => {
                                 if (inputBlock.isConstant) {
-                                    this.props.globalState.onRebuildRequiredObservable.notifyObservers();    
+                                    this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                                 }
                             }}/>
                         }
@@ -96,17 +96,31 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                     <Vector2PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
                 );
             case NodeMaterialBlockConnectionPointTypes.Color3:
-                return (
-                    <Color3PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
-                );
+                return (<>
+                        <Color3PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
+                        <CheckBoxLineComponent label="Convert to gamma space" propertyName="convertToGammaSpace" target={this.props.block} onValueChanged={() => {
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }}/>
+                        <CheckBoxLineComponent label="Convert to linear space" propertyName="convertToLinearSpace" target={this.props.block} onValueChanged={() => {
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }}/>
+                        </>
+            );
             case NodeMaterialBlockConnectionPointTypes.Color4:
-                return (
-                    <Color4PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
+                return (<>
+                        <Color4PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
+                        <CheckBoxLineComponent label="Convert to gamma space" propertyName="convertToGammaSpace" target={this.props.block} onValueChanged={() => {
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }}/>
+                        <CheckBoxLineComponent label="Convert to linear space" propertyName="convertToLinearSpace" target={this.props.block} onValueChanged={() => {
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }}/>
+                        </>
                 );
             case NodeMaterialBlockConnectionPointTypes.Vector3:
                 return (
                     <Vector3PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
-                );            
+                );
             case NodeMaterialBlockConnectionPointTypes.Vector4:
                 return (
                     <Vector4PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
@@ -114,7 +128,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
             case NodeMaterialBlockConnectionPointTypes.Matrix:
                 return (
                     <MatrixPropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
-                );                
+                );
         }
 
         return null;
@@ -132,16 +146,16 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
         var attributeOptions: {label: string, value: string}[] = [];
         var animationOptions: {label: string, value: AnimatedInputBlockTypes}[] = [];
 
-        switch(inputBlock.type) {      
+        switch (inputBlock.type) {
             case NodeMaterialBlockConnectionPointTypes.Float:
                 animationOptions = [
                     { label: "None", value: AnimatedInputBlockTypes.None },
                     { label: "Time", value: AnimatedInputBlockTypes.Time },
                 ];
-                systemValuesOptions = [ 
+                systemValuesOptions = [
                     { label: "Delta time", value: NodeMaterialSystemValues.DeltaTime }
-                ]
-                break;      
+                ];
+                break;
             case NodeMaterialBlockConnectionPointTypes.Matrix:
                 systemValuesOptions = [
                     { label: "World", value: NodeMaterialSystemValues.World },
@@ -167,7 +181,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                     { label: "uv", value: "uv" },
                     { label: "uv2", value: "uv2" },
                 ];
-                break;                
+                break;
             case NodeMaterialBlockConnectionPointTypes.Vector3:
                 systemValuesOptions = [
                     { label: "Camera position", value: NodeMaterialSystemValues.CameraPosition }
@@ -175,7 +189,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                 attributeOptions = [
                     { label: "position", value: "position" },
                     { label: "normal", value: "normal" },
-                    { label: "tangent", value: "tangent" },        
+                    { label: "tangent", value: "tangent" },
                 ];
                 break;
             case NodeMaterialBlockConnectionPointTypes.Vector4:
@@ -183,7 +197,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         { label: "matricesIndices", value: "matricesIndices" },
                         { label: "matricesWeights", value: "matricesWeights" }
                     ];
-                    break;                
+                    break;
         }
 
         var modeOptions = [
@@ -210,7 +224,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                 <LineContainerComponent title="PROPERTIES">
                     {
                         inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&
-                        <OptionsLineComponent label="Type" options={typeOptions} target={inputBlock} 
+                        <OptionsLineComponent label="Type" options={typeOptions} target={inputBlock}
                             noDirectUpdate={true}
                             getSelection={(block) => {
                                 if (block.visibleInInspector) {
@@ -241,18 +255,18 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                                 this.forceUpdate();
                                 this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                                 this.props.globalState.onRebuildRequiredObservable.notifyObservers();
-                            }} />                        
-                    }      
+                            }} />
+                    }
                     {
                         inputBlock.visibleInInspector &&
-                        <TextInputLineComponent globalState={this.props.globalState} label="Group" propertyName="groupInInspector" target={this.props.block} 
+                        <TextInputLineComponent globalState={this.props.globalState} label="Group" propertyName="groupInInspector" target={this.props.block}
                             onChange={() => {
                                 this.forceUpdate();
                                 this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                                 this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                             }} />
-                    }     
-                    <OptionsLineComponent label="Mode" options={modeOptions} target={inputBlock} 
+                    }
+                    <OptionsLineComponent label="Mode" options={modeOptions} target={inputBlock}
                         noDirectUpdate={true}
                         getSelection={(block) => {
                             if (block.isAttribute) {
@@ -279,7 +293,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                                     inputBlock.setAsSystemValue(systemValuesOptions[0].value);
                                     break;
                             }
-                            this.forceUpdate();                            
+                            this.forceUpdate();
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                             this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                         }} />
@@ -288,7 +302,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         <OptionsLineComponent label="Attribute" valuesAreStrings={true} options={attributeOptions} target={inputBlock} propertyName="name" onSelect={(value: any) => {
                             inputBlock.setAsAttribute(value);
                             this.forceUpdate();
-                            
+
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                             this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                         }} />
@@ -297,11 +311,11 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         inputBlock.isUniform && animationOptions.length > 0 &&
                         <OptionsLineComponent label="Animation type" options={animationOptions} target={inputBlock} propertyName="animationType" onSelect={(value: any) => {
                             this.forceUpdate();
-                            
+
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                             this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                         }} />
-                    }   
+                    }
                     {
                         inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&
                         this.renderValue(this.props.globalState)
@@ -311,7 +325,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         <OptionsLineComponent label="System value" options={systemValuesOptions} target={inputBlock} propertyName="systemValue" onSelect={(value: any) => {
                             inputBlock.setAsSystemValue(value);
                             this.forceUpdate();
-                            
+
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                             this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                         }} />

+ 55 - 5
src/Materials/Node/Blocks/Input/inputBlock.ts

@@ -10,7 +10,7 @@ import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPo
 import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
 import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
 import { _TypeStore } from '../../../../Misc/typeStore';
-import { Color3, Color4 } from '../../../../Maths/math';
+import { Color3, Color4, TmpColors } from '../../../../Maths/math';
 import { AnimatedInputBlockTypes } from './animatedInputBlockTypes';
 import { Observable } from '../../../../Misc/observable';
 import { MaterialHelper } from '../../../../Materials/materialHelper';
@@ -69,6 +69,12 @@ export class InputBlock extends NodeMaterialBlock {
     /** Gets an observable raised when the value is changed */
     public onValueChangedObservable = new Observable<InputBlock>();
 
+    /** Gets or sets a boolean indicating if content needs to be converted to gamma space (for color3/4 only) */
+    public convertToGammaSpace = false;
+
+    /** Gets or sets a boolean indicating if content needs to be converted to linear space (for color3/4 only) */
+    public convertToLinearSpace = false;
+
     /**
      * Gets or sets the connection point type (default is float)
      */
@@ -417,9 +423,23 @@ export class InputBlock extends NodeMaterialBlock {
             case NodeMaterialBlockConnectionPointTypes.Vector4:
                 return `vec4(${this.value.x}, ${this.value.y}, ${this.value.z}, ${this.value.w})`;
             case NodeMaterialBlockConnectionPointTypes.Color3:
-                return `vec3(${this.value.r}, ${this.value.g}, ${this.value.b})`;
+                TmpColors.Color3[0].set(this.value.r, this.value.g, this.value.b);
+                if (this.convertToGammaSpace) {
+                    TmpColors.Color3[0].toGammaSpaceToRef(TmpColors.Color3[0]);
+                }
+                if (this.convertToLinearSpace) {
+                    TmpColors.Color3[0].toLinearSpaceToRef(TmpColors.Color3[0]);
+                }
+                return `vec3(${TmpColors.Color3[0].r}, ${TmpColors.Color3[0].g}, ${TmpColors.Color3[0].b})`;
             case NodeMaterialBlockConnectionPointTypes.Color4:
-                return `vec4(${this.value.r}, ${this.value.g}, ${this.value.b}, ${this.value.a})`;
+                TmpColors.Color4[0].set(this.value.r, this.value.g, this.value.b, this.value.a);
+                if (this.convertToGammaSpace) {
+                    TmpColors.Color4[0].toGammaSpaceToRef(TmpColors.Color4[0]);
+                }
+                if (this.convertToLinearSpace) {
+                    TmpColors.Color4[0].toLinearSpaceToRef(TmpColors.Color4[0]);
+                }
+                return `vec4(${TmpColors.Color4[0].r}, ${TmpColors.Color4[0].g}, ${TmpColors.Color4[0].b}, ${TmpColors.Color4[0].a})`;
         }
 
         return "";
@@ -588,10 +608,24 @@ export class InputBlock extends NodeMaterialBlock {
                 effect.setInt(variableName, value);
                 break;
             case NodeMaterialBlockConnectionPointTypes.Color3:
-                effect.setColor3(variableName, value);
+                TmpColors.Color3[0].set(this.value.r, this.value.g, this.value.b);
+                if (this.convertToGammaSpace) {
+                    TmpColors.Color3[0].toGammaSpaceToRef(TmpColors.Color3[0]);
+                }
+                if (this.convertToLinearSpace) {
+                    TmpColors.Color3[0].toLinearSpaceToRef(TmpColors.Color3[0]);
+                }
+                effect.setColor3(variableName, TmpColors.Color3[0]);
                 break;
             case NodeMaterialBlockConnectionPointTypes.Color4:
-                effect.setDirectColor4(variableName, value);
+                TmpColors.Color4[0].set(this.value.r, this.value.g, this.value.b, this.value.a);
+                if (this.convertToGammaSpace) {
+                    TmpColors.Color4[0].toGammaSpaceToRef(TmpColors.Color4[0]);
+                }
+                if (this.convertToLinearSpace) {
+                    TmpColors.Color4[0].toLinearSpaceToRef(TmpColors.Color4[0]);
+                }
+                effect.setDirectColor4(variableName, TmpColors.Color4[0]);
                 break;
             case NodeMaterialBlockConnectionPointTypes.Vector2:
                 effect.setVector2(variableName, value);
@@ -647,9 +681,21 @@ export class InputBlock extends NodeMaterialBlock {
                     break;
                 case NodeMaterialBlockConnectionPointTypes.Color3:
                     valueString = `new BABYLON.Color3(${this.value.r}, ${this.value.g}, ${this.value.b})`;
+                    if (this.convertToGammaSpace) {
+                        valueString += ".toGammaSpace()";
+                    }
+                    if (this.convertToLinearSpace) {
+                        valueString += ".toLinearSpace()";
+                    }
                     break;
                 case NodeMaterialBlockConnectionPointTypes.Color4:
                     valueString = `new BABYLON.Color4(${this.value.r}, ${this.value.g}, ${this.value.b}, ${this.value.a})`;
+                    if (this.convertToGammaSpace) {
+                        valueString += ".toGammaSpace()";
+                    }
+                    if (this.convertToLinearSpace) {
+                        valueString += ".toLinearSpace()";
+                    }
                     break;
                 case NodeMaterialBlockConnectionPointTypes.Matrix:
                     valueString = `BABYLON.Matrix.FromArray([${(this.value as Matrix).m}])`;
@@ -701,6 +747,8 @@ export class InputBlock extends NodeMaterialBlock {
         serializationObject.matrixMode = this.matrixMode;
         serializationObject.isConstant = this.isConstant;
         serializationObject.groupInInspector = this.groupInInspector;
+        serializationObject.convertToGammaSpace = this.convertToGammaSpace;
+        serializationObject.convertToLinearSpace = this.convertToLinearSpace;
 
         if (this._storedValue != null && this._mode === NodeMaterialBlockConnectionPointMode.Uniform) {
             if (this._storedValue.asArray) {
@@ -729,6 +777,8 @@ export class InputBlock extends NodeMaterialBlock {
         this.matrixMode = serializationObject.matrixMode || 0;
         this.isConstant = !!serializationObject.isConstant;
         this.groupInInspector = serializationObject.groupInInspector || "";
+        this.convertToGammaSpace = !!serializationObject.convertToGammaSpace;
+        this.convertToLinearSpace = !!serializationObject.convertToLinearSpace;
 
         if (!serializationObject.valueType) {
             return;