Skip to content

Commit

Permalink
MeshPhysicalMaterial: Support iridescence / thin-film materials (#23869)
Browse files Browse the repository at this point in the history
* Add iridescence parameters to Physical Material

* Add iridescence fragment shader code

* Iridescence shader integration and glTF loading

* Update iridescence default values

* Add KHR_materials_iridescence to supported extensions in GLTFLoader docu

* Enable iridescence in Editor

* Update build results

* Remove build files from PR

* Honor iridescence parameters in program cache

* Use range for iridescence thin-film thickness

* Fixed linting errors

* Fix always-true conditional

* Add iridescence to glTF export

* Instantiate iridescenceThicknessRange in GLTFLoader if undefined

* Make iridescence Fresnel consistent for IBL

* Rename iridescenceIOR to iridescenceIor

* Rename iridescenceIor back to iridescenceIOR except for glTF extension
  • Loading branch information
PascalSchoen authored May 25, 2022
1 parent 70e0000 commit 12f550e
Show file tree
Hide file tree
Showing 27 changed files with 929 additions and 25 deletions.
1 change: 1 addition & 0 deletions docs/examples/en/loaders/GLTFLoader.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ <h2>Extensions</h2>
<li>KHR_materials_pbrSpecularGlossiness</li>
<li>KHR_materials_specular</li>
<li>KHR_materials_transmission</li>
<li>KHR_materials_iridescence</li>
<li>KHR_materials_unlit</li>
<li>KHR_materials_volume</li>
<li>KHR_mesh_quantization</li>
Expand Down
1 change: 1 addition & 0 deletions docs/examples/zh/loaders/GLTFLoader.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ <h2>扩展</h2>
<li>KHR_materials_pbrSpecularGlossiness</li>
<li>KHR_materials_specular</li>
<li>KHR_materials_transmission</li>
<li>KHR_materials_iridescence</li>
<li>KHR_materials_unlit</li>
<li>KHR_materials_volume</li>
<li>KHR_mesh_quantization</li>
Expand Down
52 changes: 51 additions & 1 deletion editor/js/Sidebar.Material.MapProperty.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as THREE from 'three';

import { UICheckbox, UINumber, UIRow, UIText } from './libs/ui.js';
import { UICheckbox, UIDiv, UINumber, UIRow, UIText } from './libs/ui.js';
import { UITexture } from './libs/ui.three.js';
import { SetMaterialMapCommand } from './commands/SetMaterialMapCommand.js';
import { SetMaterialValueCommand } from './commands/SetMaterialValueCommand.js';
import { SetMaterialRangeCommand } from './commands/SetMaterialRangeCommand.js';
import { SetMaterialVectorCommand } from './commands/SetMaterialVectorCommand.js';

function SidebarMaterialMapProperty( editor, property, name ) {
Expand Down Expand Up @@ -51,6 +52,36 @@ function SidebarMaterialMapProperty( editor, property, name ) {

}

let rangeMin, rangeMax;

if ( property === 'iridescenceThicknessMap' ) {

const range = new UIDiv().setMarginLeft( '3px' );
container.add( range );

const rangeMinRow = new UIRow().setMarginBottom( '0px' ).setStyle( 'min-height', '0px' );
range.add( rangeMinRow );

rangeMinRow.add( new UIText( 'min:' ).setWidth( '35px' ) );

rangeMin = new UINumber().setWidth( '40px' ).onChange( onRangeChange );
rangeMinRow.add( rangeMin );

const rangeMaxRow = new UIRow().setMarginBottom( '6px' ).setStyle( 'min-height', '0px' );
range.add( rangeMaxRow );

rangeMaxRow.add( new UIText( 'max:' ).setWidth( '35px' ) );

rangeMax = new UINumber().setWidth( '40px' ).onChange( onRangeChange );
rangeMaxRow.add( rangeMax );

// Additional settings for iridescenceThicknessMap
// Please add conditional if more maps are having a range property
rangeMin.setPrecision( 0 ).setRange( 0, Infinity ).setNudge( 1 ).setStep( 10 ).setUnit( 'nm' );
rangeMax.setPrecision( 0 ).setRange( 0, Infinity ).setNudge( 1 ).setStep( 10 ).setUnit( 'nm' );

}

let object = null;
let material = null;

Expand Down Expand Up @@ -127,6 +158,18 @@ function SidebarMaterialMapProperty( editor, property, name ) {

}

function onRangeChange() {

const value = [ rangeMin.getValue(), rangeMax.getValue() ];

if ( material[ `${ mapType }Range` ][ 0 ] !== value[ 0 ] || material[ `${ mapType }Range` ][ 1 ] !== value[ 1 ] ) {

editor.execute( new SetMaterialRangeCommand( editor, object, `${ mapType }Range`, value[ 0 ], value[ 1 ], 0 /* TODOL currentMaterialSlot */ ) );

}

}

function update() {

if ( object === null ) return;
Expand Down Expand Up @@ -164,6 +207,13 @@ function SidebarMaterialMapProperty( editor, property, name ) {

}

if ( rangeMin !== undefined ) {

rangeMin.setValue( material[ `${ mapType }Range` ][ 0 ] );
rangeMax.setValue( material[ `${ mapType }Range` ][ 1 ] );

}

container.setDisplay( '' );

} else {
Expand Down
66 changes: 66 additions & 0 deletions editor/js/Sidebar.Material.RangeValueProperty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { UINumber, UIRow, UIText } from './libs/ui.js';
import { SetMaterialRangeCommand } from './commands/SetMaterialRangeCommand.js';

function SidebarMaterialRangeValueProperty( editor, property, name, isMin, range = [ - Infinity, Infinity ], precision = 2, step = 1, nudge = 0.01, unit = '' ) {

const signals = editor.signals;

const container = new UIRow();
container.add( new UIText( name ).setWidth( '90px' ) );

const number = new UINumber().setWidth( '60px' ).setRange( range[ 0 ], range[ 1 ] ).setPrecision( precision ).setStep( step ).setNudge( nudge ).setUnit( unit ).onChange( onChange );
container.add( number );

let object = null;
let material = null;

function onChange() {

if ( material[ property ][ isMin ? 0 : 1 ] !== number.getValue() ) {

const minValue = isMin ? number.getValue() : material[ property ][ 0 ];
const maxValue = isMin ? material[ property ][ 1 ] : number.getValue();

editor.execute( new SetMaterialRangeCommand( editor, object, property, minValue, maxValue, 0 /* TODO: currentMaterialSlot */ ) );

}

}

function update() {

if ( object === null ) return;
if ( object.material === undefined ) return;

material = object.material;

if ( property in material ) {

number.setValue( material[ property ][ isMin ? 0 : 1 ] );
container.setDisplay( '' );

} else {

container.setDisplay( 'none' );

}

}

//

signals.objectSelected.add( function ( selected ) {

object = selected;

update();

} );

signals.materialChanged.add( update );

return container;

}

export { SidebarMaterialRangeValueProperty };
26 changes: 26 additions & 0 deletions editor/js/Sidebar.Material.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SidebarMaterialColorProperty } from './Sidebar.Material.ColorProperty.j
import { SidebarMaterialConstantProperty } from './Sidebar.Material.ConstantProperty.js';
import { SidebarMaterialMapProperty } from './Sidebar.Material.MapProperty.js';
import { SidebarMaterialNumberProperty } from './Sidebar.Material.NumberProperty.js';
import { SidebarMaterialRangeValueProperty } from './Sidebar.Material.RangeValueProperty.js';
import { SidebarMaterialProgram } from './Sidebar.Material.Program.js';

function SidebarMaterial( editor ) {
Expand Down Expand Up @@ -130,6 +131,21 @@ function SidebarMaterial( editor ) {
const materialClearcoatRoughness = new SidebarMaterialNumberProperty( editor, 'clearcoatRoughness', strings.getKey( 'sidebar/material/clearcoatroughness' ), [ 0, 1 ] );
container.add( materialClearcoatRoughness );

// iridescence

const materialIridescence = new SidebarMaterialNumberProperty( editor, 'iridescence', strings.getKey( 'sidebar/material/iridescence' ), [ 0, 1 ] );
container.add( materialIridescence );

// iridescenceIOR

const materialIridescenceIOR = new SidebarMaterialNumberProperty( editor, 'iridescenceIOR', strings.getKey( 'sidebar/material/iridescenceIOR' ), [ 1, 5 ] );
container.add( materialIridescenceIOR );

// iridescenceThicknessMax

const materialIridescenceThicknessMax = new SidebarMaterialRangeValueProperty( editor, 'iridescenceThicknessRange', strings.getKey( 'sidebar/material/iridescenceThicknessMax' ), false, [ 0, Infinity ], 0, 10, 1, 'nm' );
container.add( materialIridescenceThicknessMax );

// transmission

const materialTransmission = new SidebarMaterialNumberProperty( editor, 'transmission', strings.getKey( 'sidebar/material/transmission' ), [ 0, 1 ] );
Expand Down Expand Up @@ -220,6 +236,16 @@ function SidebarMaterial( editor ) {
const materialMetalnessMap = new SidebarMaterialMapProperty( editor, 'metalnessMap', strings.getKey( 'sidebar/material/metalnessmap' ) );
container.add( materialMetalnessMap );

// iridescence map

const materialIridescenceMap = new SidebarMaterialMapProperty( editor, 'iridescenceMap', strings.getKey( 'sidebar/material/iridescencemap' ) );
container.add( materialIridescenceMap );

// iridescence thickness map

const materialIridescenceThicknessMap = new SidebarMaterialMapProperty( editor, 'iridescenceThicknessMap', strings.getKey( 'sidebar/material/iridescencethicknessmap' ) );
container.add( materialIridescenceThicknessMap );

// env map

const materialEnvMap = new SidebarMaterialMapProperty( editor, 'envMap', strings.getKey( 'sidebar/material/envmap' ) );
Expand Down
5 changes: 5 additions & 0 deletions editor/js/Strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ function Strings( config ) {
'sidebar/material/shininess': 'Shininess',
'sidebar/material/clearcoat': 'Clearcoat',
'sidebar/material/clearcoatroughness': 'Clearcoat Roughness',
'sidebar/material/iridescence': 'Iridescence',
'sidebar/material/iridescenceIOR': 'Thin-Film IOR',
'sidebar/material/iridescenceThicknessMax': 'Thin-Film Thickness',
'sidebar/material/transmission': 'Transmission',
'sidebar/material/attenuationDistance': 'Attenuation Distance',
'sidebar/material/attenuationColor': 'Attenuation Color',
Expand All @@ -272,6 +275,8 @@ function Strings( config ) {
'sidebar/material/roughnessmap': 'Rough. Map',
'sidebar/material/metalnessmap': 'Metal. Map',
'sidebar/material/specularmap': 'Specular Map',
'sidebar/material/iridescencemap': 'Irid. Map',
'sidebar/material/iridescencethicknessmap': 'Thin-Film Thickness Map',
'sidebar/material/envmap': 'Env Map',
'sidebar/material/lightmap': 'Light Map',
'sidebar/material/aomap': 'AO Map',
Expand Down
83 changes: 83 additions & 0 deletions editor/js/commands/SetMaterialRangeCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Command } from '../Command.js';

/**
* @param editor Editor
* @param object THREE.Object3D
* @param attributeName string
* @param newMinValue number
* @param newMaxValue number
* @constructor
*/
class SetMaterialRangeCommand extends Command {

constructor( editor, object, attributeName, newMinValue, newMaxValue, materialSlot ) {

super( editor );

this.type = 'SetMaterialRangeCommand';
this.name = `Set Material.${attributeName}`;
this.updatable = true;

this.object = object;
this.material = this.editor.getObjectMaterial( object, materialSlot );

this.oldRange = ( this.material !== undefined && this.material[ attributeName ] !== undefined ) ? [ ...this.material[ attributeName ] ] : undefined;
this.newRange = [ newMinValue, newMaxValue ];

this.attributeName = attributeName;

}

execute() {

this.material[ this.attributeName ] = [ ...this.newRange ];
this.material.needsUpdate = true;

this.editor.signals.objectChanged.dispatch( this.object );
this.editor.signals.materialChanged.dispatch( this.material );

}

undo() {

this.material[ this.attributeName ] = [ ...this.oldRange ];
this.material.needsUpdate = true;

this.editor.signals.objectChanged.dispatch( this.object );
this.editor.signals.materialChanged.dispatch( this.material );

}

update( cmd ) {

this.newRange = [ ...cmd.newRange ];

}

toJSON() {

const output = super.toJSON( this );

output.objectUuid = this.object.uuid;
output.attributeName = this.attributeName;
output.oldRange = [ ...this.oldRange ];
output.newRange = [ ...this.newRange ];

return output;

}

fromJSON( json ) {

super.fromJSON( json );

this.attributeName = json.attributeName;
this.oldRange = [ ...json.oldRange ];
this.newRange = [ ...json.newRange ];
this.object = this.editor.objectByUuid( json.objectUuid );

}

}

export { SetMaterialRangeCommand };
Loading

0 comments on commit 12f550e

Please sign in to comment.