threepipe
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
2 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
3 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. import {IMaterial} from '../IMaterial'
  2. import {UiObjectConfig} from 'uiconfig.js'
  3. import {makeSamplerUi} from '../../ui/image-ui'
  4. import {
  5. AdditiveBlending,
  6. AlwaysDepth,
  7. BackSide,
  8. Blending, CustomBlending,
  9. DepthModes,
  10. DoubleSide,
  11. EqualDepth,
  12. FrontSide,
  13. GreaterDepth,
  14. GreaterEqualDepth,
  15. LessDepth,
  16. LessEqualDepth,
  17. MultiplyBlending,
  18. NeverDepth,
  19. NoBlending,
  20. NormalBlending,
  21. NormalMapTypes,
  22. NotEqualDepth,
  23. ObjectSpaceNormalMap,
  24. OneFactor,
  25. OneMinusDstAlphaFactor,
  26. OneMinusDstColorFactor,
  27. OneMinusSrcAlphaFactor,
  28. OneMinusSrcColorFactor,
  29. Side,
  30. SrcAlphaFactor,
  31. SrcAlphaSaturateFactor,
  32. SrcColorFactor,
  33. SubtractiveBlending,
  34. TangentSpaceNormalMap,
  35. ZeroFactor,
  36. BlendingEquation,
  37. BlendingSrcFactor,
  38. MinEquation,
  39. ConstantAlphaFactor, ConstantColorFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor,
  40. ReverseSubtractEquation,
  41. SubtractEquation, AddEquation, MaxEquation, DstAlphaFactor, DstColorFactor,
  42. } from 'three'
  43. import {downloadBlob, uploadFile} from 'ts-browser-helpers'
  44. import {PhysicalMaterial} from './PhysicalMaterial'
  45. import {getEmptyMeta} from '../../utils'
  46. import {LegacyPhongMaterial} from './LegacyPhongMaterial'
  47. import {generateUUID} from '../../three/utils'
  48. declare module '../IMaterial' {
  49. interface IMaterial {
  50. __matExtUiConfigs?: Record<string, UiObjectConfig|undefined>
  51. }
  52. }
  53. export const iMaterialUI = {
  54. base: (material: IMaterial): UiObjectConfig[] => [
  55. {
  56. type: 'input',
  57. property: [material, 'name'],
  58. },
  59. // {
  60. // type: 'monitor',
  61. // property: [material, 'uuid'],
  62. // },
  63. {
  64. type: 'checkbox',
  65. property: [material, 'wireframe'],
  66. },
  67. {
  68. type: 'checkbox',
  69. property: [material, 'vertexColors'],
  70. },
  71. {
  72. type: 'color',
  73. property: [material, 'color'],
  74. },
  75. material.flatShading !== undefined ? {
  76. type: 'checkbox',
  77. property: [material, 'flatShading'],
  78. } : {},
  79. {
  80. type: 'image',
  81. property: [material, 'map'],
  82. },
  83. makeSamplerUi(material, 'map'),
  84. ],
  85. blending: (material: IMaterial): UiObjectConfig => (
  86. {
  87. type: 'folder',
  88. label: 'Blending',
  89. children: [
  90. {
  91. type: 'slider',
  92. bounds: [0, 1],
  93. property: [material, 'opacity'],
  94. },
  95. {
  96. type: 'checkbox',
  97. property: [material, 'transparent'],
  98. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  99. },
  100. {
  101. type: 'dropdown',
  102. property: [material, 'depthFunc'],
  103. children: ([
  104. ['Never', NeverDepth],
  105. ['Always', AlwaysDepth],
  106. ['Less', LessDepth],
  107. ['LessEqual', LessEqualDepth],
  108. ['Equal', EqualDepth],
  109. ['GreaterEqual', GreaterEqualDepth],
  110. ['Greater', GreaterDepth],
  111. ['NotEqual', NotEqualDepth],
  112. ] as [string, DepthModes][]).map(value => ({
  113. label: value[0],
  114. value: value[1],
  115. })),
  116. },
  117. {
  118. type: 'checkbox',
  119. property: [material, 'depthTest'],
  120. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  121. },
  122. {
  123. type: 'checkbox',
  124. property: [material, 'depthWrite'],
  125. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  126. },
  127. {
  128. type: 'checkbox',
  129. property: [material, 'colorWrite'],
  130. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  131. },
  132. {
  133. type: 'slider',
  134. bounds: [0, 1],
  135. stepSize: 0.001,
  136. property: [material, 'alphaTest'],
  137. },
  138. {
  139. type: 'checkbox',
  140. property: [material, 'alphaHash'],
  141. },
  142. {
  143. type: 'checkbox',
  144. property: [material, 'dithering'],
  145. },
  146. {
  147. type: 'dropdown',
  148. label: 'Blending',
  149. property: [material, 'blending'],
  150. children: ([
  151. ['None', NoBlending],
  152. ['Normal', NormalBlending],
  153. ['Additive', AdditiveBlending],
  154. ['Subtractive', SubtractiveBlending],
  155. ['Multiply', MultiplyBlending],
  156. ['Custom', CustomBlending],
  157. ] as [string, Blending][]).map(value => ({
  158. label: value[0],
  159. value: value[1],
  160. })),
  161. },
  162. {
  163. type: 'dropdown',
  164. hidden: ()=>material.blending !== CustomBlending,
  165. property: [material, 'blendingEquation'],
  166. children: ([
  167. ['Add', AddEquation],
  168. ['Subtract', SubtractEquation],
  169. ['Reverse Subtract', ReverseSubtractEquation],
  170. ['Min', MinEquation],
  171. ['Max', MaxEquation],
  172. ] as [string, BlendingEquation][]).map(value => ({
  173. label: value[0],
  174. value: value[1],
  175. })),
  176. },
  177. {
  178. type: 'dropdown',
  179. property: [material, 'blendSrc'],
  180. hidden: ()=>material.blending !== CustomBlending,
  181. children: ([
  182. ['Zero', ZeroFactor],
  183. ['One', OneFactor],
  184. ['Src Color', SrcColorFactor],
  185. ['One Minus Src Color', OneMinusSrcColorFactor],
  186. ['Src Alpha', SrcAlphaFactor],
  187. ['One Minus Src Alpha', OneMinusSrcAlphaFactor],
  188. ['Dst Alpha', DstAlphaFactor],
  189. ['One Minus Dst Alpha', OneMinusDstAlphaFactor],
  190. ['Dst Color', DstColorFactor],
  191. ['One Minus Dst Color', OneMinusDstColorFactor],
  192. ['Src Alpha Saturate', SrcAlphaSaturateFactor],
  193. ['Constant Color', ConstantColorFactor],
  194. ['One Minus Constant Color', OneMinusConstantColorFactor],
  195. ['Constant Alpha', ConstantAlphaFactor],
  196. ['One Minus Constant Alpha', OneMinusConstantAlphaFactor],
  197. ] as [string, BlendingSrcFactor][]).map(value => ({
  198. label: value[0],
  199. value: value[1],
  200. })),
  201. },
  202. {
  203. type: 'dropdown',
  204. property: [material, 'blendDst'],
  205. hidden: ()=>material.blending !== CustomBlending,
  206. children: ([
  207. ['Zero', ZeroFactor],
  208. ['One', OneFactor],
  209. ['Src Color', SrcColorFactor],
  210. ['One Minus Src Color', OneMinusSrcColorFactor],
  211. ['Src Alpha', SrcAlphaFactor],
  212. ['One Minus Src Alpha', OneMinusSrcAlphaFactor],
  213. ['Dst Alpha', DstAlphaFactor],
  214. ['One Minus Dst Alpha', OneMinusDstAlphaFactor],
  215. ['Dst Color', DstColorFactor],
  216. ['One Minus Dst Color', OneMinusDstColorFactor],
  217. // ['Src Alpha Saturate', SrcAlphaSaturateFactor],
  218. ['Constant Color', ConstantColorFactor],
  219. ['One Minus Constant Color', OneMinusConstantColorFactor],
  220. ['Constant Alpha', ConstantAlphaFactor],
  221. ['One Minus Constant Alpha', OneMinusConstantAlphaFactor],
  222. ] as [string, BlendingSrcFactor][]).map(value => ({
  223. label: value[0],
  224. value: value[1],
  225. })),
  226. },
  227. {
  228. type: 'slider',
  229. bounds: [0, 1],
  230. hidden: ()=>material.blending !== CustomBlending,
  231. property: [material, 'blendSrcAlpha'],
  232. },
  233. {
  234. type: 'slider',
  235. bounds: [0, 1],
  236. hidden: ()=>material.blending !== CustomBlending,
  237. property: [material, 'blendDstAlpha'],
  238. },
  239. {
  240. type: 'color',
  241. hidden: ()=>material.blending !== CustomBlending ||
  242. material.blendSrc !== ConstantColorFactor &&
  243. material.blendSrc !== OneMinusConstantColorFactor &&
  244. material.blendDst !== ConstantColorFactor &&
  245. material.blendDst !== OneMinusConstantColorFactor,
  246. property: [material, 'blendColor'],
  247. },
  248. {
  249. type: 'slider',
  250. hidden: ()=>material.blending !== CustomBlending ||
  251. material.blendSrc !== ConstantAlphaFactor &&
  252. material.blendSrc !== OneMinusConstantAlphaFactor &&
  253. material.blendDst !== ConstantAlphaFactor &&
  254. material.blendDst !== OneMinusConstantAlphaFactor,
  255. bounds: [0, 1],
  256. property: [material, 'blendAlpha'],
  257. },
  258. material.alphaMap !== undefined ? {
  259. type: 'image',
  260. property: [material, 'alphaMap'],
  261. } : {},
  262. material.alphaMap !== undefined ? makeSamplerUi(material, 'alphaMap') : {},
  263. {
  264. type: 'checkbox',
  265. label: 'Render to Gbuffer',
  266. // hidden: ()=>!material.transparent && material.transmission < 0.001,
  267. getValue: ()=>material.userData.renderToGBuffer === true,
  268. setValue: (v: boolean)=>{
  269. if (!v && !material.userData.renderToGBuffer) return
  270. material.userData.renderToGBuffer = v
  271. material.setDirty()
  272. },
  273. },
  274. {
  275. type: 'checkbox',
  276. label: 'Render to Depth',
  277. hidden: ()=>material.userData.renderToDepth !== undefined,
  278. getValue: ()=>material.userData.renderToDepth === true,
  279. setValue: (v: boolean)=>{
  280. if (!v && !material.userData.renderToDepth) return
  281. material.userData.renderToDepth = v
  282. material.setDirty()
  283. },
  284. },
  285. material.isPhysicalMaterial ? {
  286. type: 'checkbox',
  287. label: 'Inverse AlphaMap',
  288. hidden: ()=>!material.transparent,
  289. getValue: ()=>material.userData.inverseAlphaMap === true,
  290. setValue: (v: boolean)=>{
  291. material.userData.inverseAlphaMap = v ? v : undefined
  292. material.setDirty()
  293. },
  294. } : {},
  295. ],
  296. }
  297. ),
  298. polygonOffset: (material: IMaterial): UiObjectConfig => (
  299. {
  300. type: 'folder',
  301. label: 'Polygon Offset',
  302. children: [
  303. {
  304. type: 'checkbox',
  305. label: 'Polygon Offset',
  306. property: [material, 'polygonOffset'],
  307. },
  308. {
  309. type: 'slider',
  310. label: 'Polygon Offset Factor',
  311. bounds: [-10, 10],
  312. property: [material, 'polygonOffsetFactor'],
  313. },
  314. {
  315. type: 'slider',
  316. label: 'Polygon Offset Units',
  317. bounds: [-10, 10],
  318. property: [material, 'polygonOffsetUnits'],
  319. },
  320. ],
  321. }
  322. ),
  323. aoLightMap: (material: IMaterial): UiObjectConfig => (
  324. {
  325. type: 'folder',
  326. label: 'AO/Lightmap',
  327. children: [
  328. {
  329. type: 'slider',
  330. bounds: [0, 2],
  331. property: [material, 'aoMapIntensity'],
  332. },
  333. {
  334. type: 'image',
  335. property: [material, 'aoMap'],
  336. },
  337. makeSamplerUi(material, 'aoMap'),
  338. {
  339. type: 'slider',
  340. bounds: [0, 2],
  341. property: [material, 'lightMapIntensity'],
  342. },
  343. {
  344. type: 'image',
  345. property: [material, 'lightMap'],
  346. },
  347. makeSamplerUi(material, 'lightMap'),
  348. ],
  349. }
  350. ),
  351. environment: (material: IMaterial): UiObjectConfig => (
  352. {
  353. type: 'folder',
  354. label: 'Environment',
  355. children: [
  356. {
  357. type: 'checkbox',
  358. label: 'Override Environment',
  359. // property: [material.userData, 'separateEnvMapIntensity'],
  360. getValue: ()=>material.userData.separateEnvMapIntensity === true,
  361. setValue: (v: boolean)=>{
  362. material.userData.separateEnvMapIntensity = v
  363. if (!v) delete material.userData.separateEnvMapIntensity
  364. },
  365. // onChange: material.setDirty,
  366. },
  367. {
  368. type: 'slider',
  369. bounds: [0, 20],
  370. hidden: ()=>!material.userData.separateEnvMapIntensity,
  371. label: 'Environment Intensity',
  372. property: [material, 'envMapIntensity'],
  373. },
  374. {
  375. type: 'dropdown',
  376. hidden: ()=>!material.userData.separateEnvMapIntensity && !material.userData.envMapSlotKey,
  377. label: 'Environment Map',
  378. children: ['', 'environment1', 'environment2'].map((i)=>({label: i || 'default', value: i})),
  379. getValue: ()=>material.userData.envMapSlotKey || '',
  380. setValue: (v: string)=>{
  381. material.userData.envMapSlotKey = v
  382. if (!v) delete material.userData.envMapSlotKey
  383. material.setDirty()
  384. },
  385. },
  386. ],
  387. }
  388. ),
  389. misc: (material: IMaterial): UiObjectConfig[] => [
  390. ()=>material.materialExtensions?.map(v=>{
  391. v.uuid = v.uuid || generateUUID()
  392. material.__matExtUiConfigs = material.__matExtUiConfigs || {}
  393. if (!material.__matExtUiConfigs[v.uuid]) material.__matExtUiConfigs[v.uuid] = v.getUiConfig?.(material, material.uiConfig?.uiRefresh)
  394. return material.__matExtUiConfigs[v.uuid]
  395. }).filter(v=>v),
  396. {
  397. type: 'dropdown',
  398. label: 'Side',
  399. property: [material, 'side'],
  400. children: ([
  401. ['Front', FrontSide],
  402. ['Back', BackSide],
  403. ['Double', DoubleSide],
  404. ] as [string, Side][]).map(value => ({
  405. label: value[0],
  406. value: value[1],
  407. })),
  408. },
  409. {
  410. type: 'input',
  411. label: 'Mesh count',
  412. getValue: ()=>material.appliedMeshes.size || 0,
  413. disabled: true,
  414. },
  415. {
  416. type: 'button',
  417. label: `Download ${material.constructor.TypeSlug}`,
  418. value: ()=>{
  419. const blob = new Blob([JSON.stringify(material.toJSON(), null, 2)], {type: 'application/json'})
  420. downloadBlob(blob, `material.${material.constructor.TypeSlug}`)
  421. },
  422. },
  423. {
  424. type: 'button',
  425. label: `Select ${material.constructor.TypeSlug}`,
  426. value: async()=>uploadFile(false, false, material.constructor.TypeSlug).then(async(files)=>files?.[0]?.text()).then((text)=>{
  427. if (!text) return
  428. const json = JSON.parse(text)
  429. if (json.uuid) delete json.uuid // just copy the material properties
  430. const currentJson = material.toJSON()
  431. material.fromJSON(json, getEmptyMeta())
  432. return {
  433. undo: ()=>material.fromJSON(currentJson, getEmptyMeta()),
  434. redo: ()=>material.fromJSON(json, getEmptyMeta()),
  435. }
  436. }),
  437. },
  438. ],
  439. roughMetal: (material: PhysicalMaterial): UiObjectConfig => (
  440. {
  441. type: 'folder',
  442. label: 'Rough/Metal',
  443. children: [
  444. {
  445. type: 'slider',
  446. bounds: [0, 1],
  447. property: [material, 'roughness'],
  448. },
  449. {
  450. type: 'slider',
  451. bounds: [0, 1],
  452. property: [material, 'metalness'],
  453. },
  454. {
  455. type: 'image',
  456. property: [material, 'roughnessMap'],
  457. },
  458. makeSamplerUi(material, 'roughnessMap'),
  459. {
  460. type: 'image',
  461. property: [material, 'metalnessMap'],
  462. },
  463. makeSamplerUi(material, 'metalnessMap'),
  464. ],
  465. }
  466. ),
  467. bumpNormal: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => (
  468. {
  469. type: 'folder',
  470. // uuid: 'bump_normal',
  471. label: 'Bump/Normal',
  472. children: [
  473. {
  474. type: 'slider',
  475. bounds: [-500, 500],
  476. stepSize: 0.001,
  477. property: [material, 'bumpScale'],
  478. hidden: ()=>!material.bumpMap,
  479. },
  480. {
  481. type: 'image',
  482. property: [material, 'bumpMap'],
  483. },
  484. makeSamplerUi(material, 'bumpMap'),
  485. {
  486. type: 'image',
  487. property: [material, 'normalMap'],
  488. },
  489. {
  490. type: 'vec2',
  491. property: [material, 'normalScale'],
  492. hidden: ()=>!material.normalMap,
  493. },
  494. {
  495. type: 'dropdown',
  496. hidden: ()=>!material.normalMap,
  497. property: [material, 'normalMapType'],
  498. children: ([
  499. ['TangentSpace', TangentSpaceNormalMap],
  500. ['ObjectSpace', ObjectSpaceNormalMap],
  501. ] as [string, NormalMapTypes][]).map(value => ({
  502. label: value[0],
  503. value: value[1],
  504. })),
  505. },
  506. makeSamplerUi(material, 'normalMap'),
  507. {
  508. type: 'input',
  509. property: [material, 'displacementScale'],
  510. hidden: ()=>!material.displacementMap,
  511. },
  512. {
  513. type: 'image',
  514. property: [material, 'displacementMap'],
  515. },
  516. makeSamplerUi(material, 'displacementMap'),
  517. ],
  518. }
  519. ),
  520. emission: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => (
  521. {
  522. type: 'folder',
  523. label: 'Emission',
  524. children: [
  525. {
  526. type: 'color',
  527. property: [material, 'emissive'],
  528. },
  529. {
  530. type: 'slider',
  531. bounds: [0, 100],
  532. property: [material, 'emissiveIntensity'],
  533. },
  534. {
  535. type: 'image',
  536. property: [material, 'emissiveMap'],
  537. },
  538. makeSamplerUi(material, 'emissiveMap'),
  539. ],
  540. }
  541. ),
  542. transmission: (material: PhysicalMaterial): UiObjectConfig => (
  543. {
  544. type: 'folder',
  545. label: 'Refraction',
  546. children: [
  547. // {
  548. // type: 'slider',
  549. // bounds: [0, 1],
  550. // property: [material, 'reflectivity'],
  551. // },
  552. {
  553. type: 'slider',
  554. bounds: [0, 4],
  555. property: [material, 'ior'],
  556. },
  557. {
  558. type: 'slider',
  559. bounds: [0, 1],
  560. property: [material, 'transmission'],
  561. },
  562. {
  563. type: 'slider',
  564. bounds: [0, 1],
  565. stepSize: 0.001,
  566. property: [material, 'thickness'],
  567. },
  568. {
  569. type: 'image',
  570. property: [material, 'transmissionMap'],
  571. },
  572. makeSamplerUi(material, 'transmissionMap'),
  573. {
  574. type: 'image',
  575. property: [material, 'thicknessMap'],
  576. },
  577. makeSamplerUi(material, 'thicknessMap'),
  578. {
  579. type: 'number',
  580. property: [material, 'attenuationDistance'],
  581. },
  582. {
  583. type: 'color',
  584. property: [material, 'attenuationColor'],
  585. },
  586. ],
  587. }
  588. ),
  589. clearcoat: (material: PhysicalMaterial): UiObjectConfig => (
  590. {
  591. type: 'folder',
  592. label: 'Clearcoat',
  593. children: [
  594. {
  595. type: 'slider',
  596. bounds: [0, 1],
  597. property: [material, 'clearcoat'],
  598. },
  599. {
  600. type: 'slider',
  601. bounds: [0, 1],
  602. hidden: ()=>material.clearcoat < 0.001,
  603. property: [material, 'clearcoatRoughness'],
  604. },
  605. {
  606. type: 'image',
  607. property: [material, 'clearcoatMap'],
  608. },
  609. makeSamplerUi(material, 'clearcoatMap'),
  610. {
  611. type: 'slider',
  612. bounds: [0, 1],
  613. property: [material, 'clearcoatRoughness'],
  614. },
  615. {
  616. type: 'image',
  617. property: [material, 'clearcoatRoughnessMap'],
  618. },
  619. makeSamplerUi(material, 'clearcoatRoughnessMap'),
  620. {
  621. type: 'image',
  622. property: [material, 'clearcoatNormalMap'],
  623. },
  624. {
  625. type: 'vec2',
  626. property: [material, 'clearcoatNormalScale'],
  627. hidden: ()=>!material.clearcoatNormalMap,
  628. },
  629. makeSamplerUi(material, 'clearcoatNormalMap'),
  630. ],
  631. }
  632. ),
  633. iridescence: (material: PhysicalMaterial): UiObjectConfig => (
  634. {
  635. type: 'folder',
  636. label: 'Iridescence',
  637. children: [
  638. {
  639. type: 'slider',
  640. bounds: [0, 3],
  641. label: 'Intensity',
  642. property: [material, 'iridescence'],
  643. },
  644. {
  645. type: 'slider',
  646. bounds: [0, 3],
  647. label: 'IOR',
  648. property: [material, 'iridescenceIOR'],
  649. },
  650. {
  651. type: 'slider',
  652. bounds: [0, 500],
  653. label: 'Thickness0',
  654. property: [material.iridescenceThicknessRange, '0'],
  655. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  656. },
  657. {
  658. type: 'slider',
  659. bounds: [0, 500],
  660. label: 'Thickness1',
  661. property: [material.iridescenceThicknessRange, '1'],
  662. onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
  663. },
  664. {
  665. type: 'image',
  666. property: [material, 'iridescenceMap'],
  667. },
  668. makeSamplerUi(material, 'iridescenceMap'),
  669. {
  670. type: 'image',
  671. property: [material, 'iridescenceThicknessMap'],
  672. },
  673. makeSamplerUi(material, 'iridescenceThicknessMap'),
  674. ],
  675. }
  676. ),
  677. sheen: (material: PhysicalMaterial): UiObjectConfig => (
  678. {
  679. type: 'folder',
  680. label: 'Sheen',
  681. children: [
  682. {
  683. type: 'slider',
  684. bounds: [0, 1],
  685. property: [material, 'sheen'],
  686. },
  687. {
  688. type: 'color',
  689. hidden: ()=>material.sheen < 0.001,
  690. property: [material, 'sheenColor'],
  691. },
  692. {
  693. type: 'image',
  694. property: [material, 'sheenColorMap'],
  695. },
  696. makeSamplerUi(material, 'sheenColorMap'),
  697. {
  698. type: 'slider',
  699. bounds: [0, 1],
  700. property: [material, 'sheenRoughness'],
  701. },
  702. {
  703. type: 'image',
  704. property: [material, 'sheenRoughnessMap'],
  705. },
  706. makeSamplerUi(material, 'sheenRoughnessMap'),
  707. ],
  708. }
  709. ),
  710. }