Sidebar.Material.MapProperty.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import * as THREE from 'three';
  2. import { UICheckbox, UIDiv, UINumber, UIRow, UIText } from './libs/ui.js';
  3. import { UITexture } from './libs/ui.three.js';
  4. import { SetMaterialMapCommand } from './commands/SetMaterialMapCommand.js';
  5. import { SetMaterialValueCommand } from './commands/SetMaterialValueCommand.js';
  6. import { SetMaterialRangeCommand } from './commands/SetMaterialRangeCommand.js';
  7. import { SetMaterialVectorCommand } from './commands/SetMaterialVectorCommand.js';
  8. function SidebarMaterialMapProperty( editor, property, name ) {
  9. const signals = editor.signals;
  10. const container = new UIRow();
  11. container.add( new UIText( name ).setClass( 'Label' ) );
  12. const enabled = new UICheckbox( false ).setMarginRight( '8px' ).onChange( onChange );
  13. container.add( enabled );
  14. const map = new UITexture( editor ).onChange( onMapChange );
  15. container.add( map );
  16. const mapType = property.replace( 'Map', '' );
  17. const colorMaps = [ 'map', 'emissiveMap', 'sheenColorMap', 'specularColorMap', 'envMap' ];
  18. let intensity;
  19. if ( property === 'aoMap' ) {
  20. intensity = new UINumber( 1 ).setWidth( '30px' ).setRange( 0, 1 ).onChange( onIntensityChange );
  21. container.add( intensity );
  22. }
  23. let scale;
  24. if ( property === 'bumpMap' || property === 'displacementMap' ) {
  25. scale = new UINumber().setWidth( '30px' ).onChange( onScaleChange );
  26. container.add( scale );
  27. }
  28. let scaleX, scaleY;
  29. if ( property === 'normalMap' || property === 'clearcoatNormalMap' ) {
  30. scaleX = new UINumber().setWidth( '30px' ).onChange( onScaleXYChange );
  31. container.add( scaleX );
  32. scaleY = new UINumber().setWidth( '30px' ).onChange( onScaleXYChange );
  33. container.add( scaleY );
  34. }
  35. let rangeMin, rangeMax;
  36. if ( property === 'iridescenceThicknessMap' ) {
  37. const range = new UIDiv().setMarginLeft( '3px' );
  38. container.add( range );
  39. const rangeMinRow = new UIRow().setMarginBottom( '0px' ).setStyle( 'min-height', '0px' );
  40. range.add( rangeMinRow );
  41. rangeMinRow.add( new UIText( 'min:' ).setWidth( '35px' ) );
  42. rangeMin = new UINumber().setWidth( '40px' ).onChange( onRangeChange );
  43. rangeMinRow.add( rangeMin );
  44. const rangeMaxRow = new UIRow().setMarginBottom( '6px' ).setStyle( 'min-height', '0px' );
  45. range.add( rangeMaxRow );
  46. rangeMaxRow.add( new UIText( 'max:' ).setWidth( '35px' ) );
  47. rangeMax = new UINumber().setWidth( '40px' ).onChange( onRangeChange );
  48. rangeMaxRow.add( rangeMax );
  49. // Additional settings for iridescenceThicknessMap
  50. // Please add conditional if more maps are having a range property
  51. rangeMin.setPrecision( 0 ).setRange( 0, Infinity ).setNudge( 1 ).setStep( 10 ).setUnit( 'nm' );
  52. rangeMax.setPrecision( 0 ).setRange( 0, Infinity ).setNudge( 1 ).setStep( 10 ).setUnit( 'nm' );
  53. }
  54. let object = null;
  55. let materialSlot = null;
  56. let material = null;
  57. function onChange() {
  58. const newMap = enabled.getValue() ? map.getValue() : null;
  59. if ( material[ property ] !== newMap ) {
  60. if ( newMap !== null ) {
  61. const geometry = object.geometry;
  62. if ( geometry.hasAttribute( 'uv' ) === false ) console.warn( 'Geometry doesn\'t have uvs:', geometry );
  63. if ( property === 'envMap' ) newMap.mapping = THREE.EquirectangularReflectionMapping;
  64. }
  65. editor.execute( new SetMaterialMapCommand( editor, object, property, newMap, materialSlot ) );
  66. }
  67. }
  68. function onMapChange( texture ) {
  69. if ( texture !== null ) {
  70. if ( colorMaps.includes( property ) && texture.isDataTexture !== true && texture.colorSpace !== THREE.SRGBColorSpace ) {
  71. texture.colorSpace = THREE.SRGBColorSpace;
  72. material.needsUpdate = true;
  73. }
  74. }
  75. enabled.setDisabled( false );
  76. onChange();
  77. }
  78. function onIntensityChange() {
  79. if ( material[ `${ property }Intensity` ] !== intensity.getValue() ) {
  80. editor.execute( new SetMaterialValueCommand( editor, object, `${ property }Intensity`, intensity.getValue(), materialSlot ) );
  81. }
  82. }
  83. function onScaleChange() {
  84. if ( material[ `${ mapType }Scale` ] !== scale.getValue() ) {
  85. editor.execute( new SetMaterialValueCommand( editor, object, `${ mapType }Scale`, scale.getValue(), materialSlot ) );
  86. }
  87. }
  88. function onScaleXYChange() {
  89. const value = [ scaleX.getValue(), scaleY.getValue() ];
  90. if ( material[ `${ mapType }Scale` ].x !== value[ 0 ] || material[ `${ mapType }Scale` ].y !== value[ 1 ] ) {
  91. editor.execute( new SetMaterialVectorCommand( editor, object, `${ mapType }Scale`, value, materialSlot ) );
  92. }
  93. }
  94. function onRangeChange() {
  95. const value = [ rangeMin.getValue(), rangeMax.getValue() ];
  96. if ( material[ `${ mapType }Range` ][ 0 ] !== value[ 0 ] || material[ `${ mapType }Range` ][ 1 ] !== value[ 1 ] ) {
  97. editor.execute( new SetMaterialRangeCommand( editor, object, `${ mapType }Range`, value[ 0 ], value[ 1 ], materialSlot ) );
  98. }
  99. }
  100. function update( currentObject, currentMaterialSlot = 0 ) {
  101. object = currentObject;
  102. materialSlot = currentMaterialSlot;
  103. if ( object === null ) return;
  104. if ( object.material === undefined ) return;
  105. material = editor.getObjectMaterial( object, materialSlot );
  106. if ( property in material ) {
  107. if ( material[ property ] !== null ) {
  108. map.setValue( material[ property ] );
  109. }
  110. enabled.setValue( material[ property ] !== null );
  111. enabled.setDisabled( map.getValue() === null );
  112. if ( intensity !== undefined ) {
  113. intensity.setValue( material[ `${ property }Intensity` ] );
  114. }
  115. if ( scale !== undefined ) {
  116. scale.setValue( material[ `${ mapType }Scale` ] );
  117. }
  118. if ( scaleX !== undefined ) {
  119. scaleX.setValue( material[ `${ mapType }Scale` ].x );
  120. scaleY.setValue( material[ `${ mapType }Scale` ].y );
  121. }
  122. if ( rangeMin !== undefined ) {
  123. rangeMin.setValue( material[ `${ mapType }Range` ][ 0 ] );
  124. rangeMax.setValue( material[ `${ mapType }Range` ][ 1 ] );
  125. }
  126. container.setDisplay( '' );
  127. } else {
  128. container.setDisplay( 'none' );
  129. }
  130. }
  131. //
  132. signals.objectSelected.add( function ( selected ) {
  133. map.setValue( null );
  134. update( selected );
  135. } );
  136. signals.materialChanged.add( update );
  137. return container;
  138. }
  139. export { SidebarMaterialMapProperty };