threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

IMaterialUi.ts 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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,
  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. Side,
  25. SubtractiveBlending,
  26. TangentSpaceNormalMap,
  27. } from 'three'
  28. import {downloadBlob} from 'ts-browser-helpers'
  29. import {PhysicalMaterial} from './PhysicalMaterial'
  30. export const iMaterialUI = {
  31. base: (material: IMaterial): UiObjectConfig[] => [
  32. {
  33. type: 'input',
  34. property: [material, 'name'],
  35. },
  36. // {
  37. // type: 'monitor',
  38. // property: [material, 'uuid'],
  39. // },
  40. {
  41. type: 'checkbox',
  42. property: [material, 'wireframe'],
  43. },
  44. {
  45. type: 'checkbox',
  46. property: [material, 'vertexColors'],
  47. },
  48. {
  49. type: 'color',
  50. property: [material, 'color'],
  51. },
  52. material.flatShading !== undefined ? {
  53. type: 'checkbox',
  54. property: [material, 'flatShading'],
  55. } : {},
  56. {
  57. type: 'image',
  58. property: [material, 'map'],
  59. },
  60. makeSamplerUi(material, 'map'),
  61. ],
  62. blending: (material: IMaterial): UiObjectConfig => (
  63. {
  64. type: 'folder',
  65. label: 'Blending',
  66. children: [
  67. {
  68. type: 'slider',
  69. bounds: [0, 1],
  70. property: [material, 'opacity'],
  71. },
  72. {
  73. type: 'checkbox',
  74. property: [material, 'transparent'],
  75. onChange: material.setDirty,
  76. },
  77. {
  78. type: 'dropdown',
  79. property: [material, 'depthFunc'],
  80. children: ([
  81. ['Never', NeverDepth],
  82. ['Always', AlwaysDepth],
  83. ['Less', LessDepth],
  84. ['LessEqual', LessEqualDepth],
  85. ['Equal', EqualDepth],
  86. ['GreaterEqual', GreaterEqualDepth],
  87. ['Greater', GreaterDepth],
  88. ['NotEqual', NotEqualDepth],
  89. ] as [string, DepthModes][]).map(value => ({
  90. label: value[0],
  91. value: value[1],
  92. })),
  93. },
  94. {
  95. type: 'checkbox',
  96. property: [material, 'depthTest'],
  97. onChange: material.setDirty,
  98. },
  99. {
  100. type: 'checkbox',
  101. property: [material, 'depthWrite'],
  102. onChange: material.setDirty,
  103. },
  104. {
  105. type: 'slider',
  106. bounds: [0, 1],
  107. property: [material, 'alphaTest'],
  108. },
  109. {
  110. type: 'checkbox',
  111. property: [material, 'dithering'],
  112. },
  113. {
  114. type: 'dropdown',
  115. label: 'Blending',
  116. property: [material, 'blending'],
  117. children: ([
  118. ['None', NoBlending],
  119. ['Normal', NormalBlending],
  120. ['Additive', AdditiveBlending],
  121. ['Subtractive', SubtractiveBlending],
  122. ['Multiply', MultiplyBlending],
  123. ] as [string, Blending][]).map(value => ({
  124. label: value[0],
  125. value: value[1],
  126. })),
  127. },
  128. {
  129. type: 'image',
  130. property: [material, 'alphaMap'],
  131. },
  132. makeSamplerUi(material, 'alphaMap'),
  133. {
  134. type: 'checkbox',
  135. label: 'Render to Gbuffer',
  136. // hidden: ()=>!material.transparent && material.transmission < 0.001,
  137. getValue: ()=>material.userData.renderToGBuffer === true,
  138. setValue: (v: boolean)=>{
  139. material.userData.renderToGBuffer = v ? v : undefined
  140. material.setDirty()
  141. },
  142. },
  143. material.isPhysicalMaterial ? {
  144. type: 'checkbox',
  145. label: 'Inverse AlphaMap',
  146. hidden: ()=>!material.transparent,
  147. getValue: ()=>material.userData.inverseAlphaMap === true,
  148. setValue: (v: boolean)=>{
  149. material.userData.inverseAlphaMap = v ? v : undefined
  150. material.setDirty()
  151. },
  152. } : {},
  153. ],
  154. }
  155. ),
  156. polygonOffset: (material: IMaterial): UiObjectConfig => (
  157. {
  158. type: 'folder',
  159. label: 'Polygon Offset',
  160. children: [
  161. {
  162. type: 'checkbox',
  163. label: 'Polygon Offset',
  164. property: [material, 'polygonOffset'],
  165. },
  166. {
  167. type: 'slider',
  168. label: 'Polygon Offset Factor',
  169. bounds: [-10, 10],
  170. property: [material, 'polygonOffsetFactor'],
  171. },
  172. {
  173. type: 'slider',
  174. label: 'Polygon Offset Units',
  175. bounds: [-10, 10],
  176. property: [material, 'polygonOffsetUnits'],
  177. },
  178. ],
  179. }
  180. ),
  181. aoLightMap: (material: IMaterial): UiObjectConfig => (
  182. {
  183. type: 'folder',
  184. label: 'AO/Lightmap',
  185. children: [
  186. {
  187. type: 'slider',
  188. bounds: [0, 2],
  189. property: [material, 'aoMapIntensity'],
  190. },
  191. {
  192. type: 'image',
  193. property: [material, 'aoMap'],
  194. },
  195. makeSamplerUi(material, 'aoMap'),
  196. {
  197. type: 'slider',
  198. bounds: [0, 2],
  199. property: [material, 'lightMapIntensity'],
  200. },
  201. {
  202. type: 'image',
  203. property: [material, 'lightMap'],
  204. },
  205. makeSamplerUi(material, 'lightMap'),
  206. ],
  207. }
  208. ),
  209. misc: (material: IMaterial): UiObjectConfig[] => [
  210. {
  211. type: 'dropdown',
  212. label: 'Side',
  213. property: [material, 'side'],
  214. children: ([
  215. ['Front', FrontSide],
  216. ['Back', BackSide],
  217. ['Double', DoubleSide],
  218. ] as [string, Side][]).map(value => ({
  219. label: value[0],
  220. value: value[1],
  221. })),
  222. },
  223. {
  224. type: 'input',
  225. label: 'Mesh count',
  226. getValue: ()=>material.appliedMeshes.size || 0,
  227. disabled: true,
  228. },
  229. {
  230. type: 'button',
  231. label: `Download ${material.constructor.TypeSlug}}`,
  232. value: ()=>{
  233. const blob = new Blob([JSON.stringify(material.toJSON(), null, 2)], {type: 'application/json'})
  234. downloadBlob(blob, `unlit-material.${material.constructor.TypeSlug}`)
  235. },
  236. },
  237. ()=>material.materialExtensions?.map(v=>v.getUiConfig?.(material, material.uiConfig?.uiRefresh)).filter(v=>v),
  238. ],
  239. roughMetal: (material: PhysicalMaterial): UiObjectConfig => (
  240. {
  241. type: 'folder',
  242. label: 'Rough/Metal',
  243. children: [
  244. {
  245. type: 'slider',
  246. bounds: [0, 1],
  247. property: [material, 'roughness'],
  248. },
  249. {
  250. type: 'slider',
  251. bounds: [0, 1],
  252. property: [material, 'metalness'],
  253. },
  254. {
  255. type: 'image',
  256. property: [material, 'roughnessMap'],
  257. },
  258. makeSamplerUi(material, 'roughnessMap'),
  259. {
  260. type: 'image',
  261. property: [material, 'metalnessMap'],
  262. },
  263. makeSamplerUi(material, 'metalnessMap'),
  264. ],
  265. }
  266. ),
  267. bumpNormal: (material: PhysicalMaterial): UiObjectConfig => (
  268. {
  269. type: 'folder',
  270. label: 'Bump/Normal',
  271. children: [
  272. {
  273. type: 'slider',
  274. bounds: [0, 0.2],
  275. stepSize: 0.001,
  276. property: [material, 'bumpScale'],
  277. hidden: ()=>!material.bumpMap,
  278. },
  279. {
  280. type: 'image',
  281. property: [material, 'bumpMap'],
  282. },
  283. makeSamplerUi(material, 'bumpMap'),
  284. {
  285. type: 'image',
  286. property: [material, 'normalMap'],
  287. },
  288. {
  289. type: 'vec2',
  290. property: [material, 'normalScale'],
  291. hidden: ()=>!material.normalMap,
  292. },
  293. {
  294. type: 'dropdown',
  295. hidden: ()=>!material.normalMap,
  296. property: [material, 'normalMapType'],
  297. children: ([
  298. ['TangentSpace', TangentSpaceNormalMap],
  299. ['ObjectSpace', ObjectSpaceNormalMap],
  300. ] as [string, NormalMapTypes][]).map(value => ({
  301. label: value[0],
  302. value: value[1],
  303. })),
  304. },
  305. makeSamplerUi(material, 'normalMap'),
  306. {
  307. type: 'input',
  308. property: [material, 'displacementScale'],
  309. hidden: ()=>!material.displacementMap,
  310. },
  311. {
  312. type: 'image',
  313. property: [material, 'displacementMap'],
  314. },
  315. makeSamplerUi(material, 'displacementMap'),
  316. ],
  317. }
  318. ),
  319. emission: (material: PhysicalMaterial): UiObjectConfig => (
  320. {
  321. type: 'folder',
  322. label: 'Emission',
  323. children: [
  324. {
  325. type: 'color',
  326. property: [material, 'emissive'],
  327. },
  328. {
  329. type: 'slider',
  330. bounds: [0, 10],
  331. property: [material, 'emissiveIntensity'],
  332. },
  333. {
  334. type: 'image',
  335. property: [material, 'emissiveMap'],
  336. },
  337. makeSamplerUi(material, 'emissiveMap'),
  338. ],
  339. }
  340. ),
  341. transmission: (material: PhysicalMaterial): UiObjectConfig => (
  342. {
  343. type: 'folder',
  344. label: 'Refraction',
  345. children: [
  346. {
  347. type: 'slider',
  348. bounds: [0, 1],
  349. property: [material, 'reflectivity'],
  350. },
  351. {
  352. type: 'slider',
  353. bounds: [0, 1],
  354. property: [material, 'transmission'],
  355. limitedUi: true,
  356. },
  357. {
  358. type: 'slider',
  359. bounds: [0, 1],
  360. stepSize: 0.001,
  361. property: [material, 'thickness'],
  362. },
  363. {
  364. type: 'image',
  365. property: [material, 'transmissionMap'],
  366. },
  367. makeSamplerUi(material, 'transmissionMap'),
  368. {
  369. type: 'image',
  370. property: [material, 'thicknessMap'],
  371. },
  372. makeSamplerUi(material, 'thicknessMap'),
  373. ],
  374. }
  375. ),
  376. clearcoat: (material: PhysicalMaterial): UiObjectConfig => (
  377. {
  378. type: 'folder',
  379. label: 'Clearcoat',
  380. children: [
  381. {
  382. type: 'slider',
  383. bounds: [0, 1],
  384. property: [material, 'clearcoat'],
  385. },
  386. {
  387. type: 'slider',
  388. bounds: [0, 1],
  389. hidden: ()=>material.clearcoat < 0.001,
  390. property: [material, 'clearcoatRoughness'],
  391. },
  392. {
  393. type: 'image',
  394. property: [material, 'clearcoatMap'],
  395. },
  396. makeSamplerUi(material, 'clearcoatMap'),
  397. {
  398. type: 'slider',
  399. bounds: [0, 1],
  400. property: [material, 'clearcoatRoughness'],
  401. },
  402. {
  403. type: 'image',
  404. property: [material, 'clearcoatRoughnessMap'],
  405. },
  406. makeSamplerUi(material, 'clearcoatRoughnessMap'),
  407. {
  408. type: 'image',
  409. property: [material, 'clearcoatNormalMap'],
  410. },
  411. {
  412. type: 'vec2',
  413. property: [material, 'clearcoatNormalScale'],
  414. hidden: ()=>!material.clearcoatNormalMap,
  415. },
  416. makeSamplerUi(material, 'clearcoatNormalMap'),
  417. ],
  418. }
  419. ),
  420. sheen: (material: PhysicalMaterial): UiObjectConfig => (
  421. {
  422. type: 'folder',
  423. label: 'Sheen',
  424. children: [
  425. {
  426. type: 'slider',
  427. bounds: [0, 1],
  428. property: [material, 'sheen'],
  429. },
  430. {
  431. type: 'color',
  432. hidden: ()=>material.sheen < 0.001,
  433. property: [material, 'sheenColor'],
  434. },
  435. {
  436. type: 'image',
  437. property: [material, 'sheenColorMap'],
  438. },
  439. makeSamplerUi(material, 'sheenColorMap'),
  440. {
  441. type: 'slider',
  442. bounds: [0, 1],
  443. property: [material, 'sheenRoughness'],
  444. },
  445. {
  446. type: 'image',
  447. property: [material, 'sheenRoughnessMap'],
  448. },
  449. makeSamplerUi(material, 'sheenRoughnessMap'),
  450. ],
  451. }
  452. ),
  453. }