| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- import {IMaterial} from '../IMaterial'
- import {UiObjectConfig} from 'uiconfig.js'
- import {makeSamplerUi} from '../../ui/image-ui'
- import {
- AdditiveBlending,
- AlwaysDepth,
- BackSide,
- Blending, CustomBlending,
- DepthModes,
- DoubleSide,
- EqualDepth,
- FrontSide,
- GreaterDepth,
- GreaterEqualDepth,
- LessDepth,
- LessEqualDepth,
- MultiplyBlending,
- NeverDepth,
- NoBlending,
- NormalBlending,
- NormalMapTypes,
- NotEqualDepth,
- ObjectSpaceNormalMap,
- OneFactor,
- OneMinusDstAlphaFactor,
- OneMinusDstColorFactor,
- OneMinusSrcAlphaFactor,
- OneMinusSrcColorFactor,
- Side,
- SrcAlphaFactor,
- SrcAlphaSaturateFactor,
- SrcColorFactor,
- SubtractiveBlending,
- TangentSpaceNormalMap,
- ZeroFactor,
- BlendingEquation,
- BlendingSrcFactor,
- MinEquation,
- ConstantAlphaFactor, ConstantColorFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor,
- ReverseSubtractEquation,
- SubtractEquation, AddEquation, MaxEquation, DstAlphaFactor, DstColorFactor,
- } from 'three'
- import {downloadBlob, uploadFile} from 'ts-browser-helpers'
- import {PhysicalMaterial} from './PhysicalMaterial'
- import {getEmptyMeta} from '../../utils'
- import {LegacyPhongMaterial} from './LegacyPhongMaterial'
- import {generateUUID} from '../../three/utils'
-
- declare module '../IMaterial' {
- interface IMaterial {
- __matExtUiConfigs?: Record<string, UiObjectConfig|undefined>
- }
- }
-
- export const iMaterialUI = {
- base: (material: IMaterial): UiObjectConfig[] => [
- {
- type: 'input',
- property: [material, 'name'],
- },
- // {
- // type: 'monitor',
- // property: [material, 'uuid'],
- // },
- {
- type: 'checkbox',
- property: [material, 'wireframe'],
- },
- {
- type: 'checkbox',
- property: [material, 'vertexColors'],
- },
- {
- type: 'color',
- property: [material, 'color'],
- },
- material.flatShading !== undefined ? {
- type: 'checkbox',
- property: [material, 'flatShading'],
- } : {},
- {
- type: 'image',
- property: [material, 'map'],
- },
- makeSamplerUi(material, 'map'),
- ],
- blending: (material: IMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Blending',
- children: [
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'opacity'],
- },
- {
- type: 'checkbox',
- property: [material, 'transparent'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'dropdown',
- property: [material, 'depthFunc'],
- children: ([
- ['Never', NeverDepth],
- ['Always', AlwaysDepth],
- ['Less', LessDepth],
- ['LessEqual', LessEqualDepth],
- ['Equal', EqualDepth],
- ['GreaterEqual', GreaterEqualDepth],
- ['Greater', GreaterDepth],
- ['NotEqual', NotEqualDepth],
- ] as [string, DepthModes][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'checkbox',
- property: [material, 'depthTest'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'checkbox',
- property: [material, 'depthWrite'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'checkbox',
- property: [material, 'colorWrite'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'slider',
- bounds: [0, 1],
- stepSize: 0.001,
- property: [material, 'alphaTest'],
- },
- {
- type: 'checkbox',
- property: [material, 'alphaHash'],
- },
- {
- type: 'checkbox',
- property: [material, 'dithering'],
- },
- {
- type: 'dropdown',
- label: 'Blending',
- property: [material, 'blending'],
- children: ([
- ['None', NoBlending],
- ['Normal', NormalBlending],
- ['Additive', AdditiveBlending],
- ['Subtractive', SubtractiveBlending],
- ['Multiply', MultiplyBlending],
- ['Custom', CustomBlending],
- ] as [string, Blending][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'dropdown',
- hidden: ()=>material.blending !== CustomBlending,
- property: [material, 'blendingEquation'],
- children: ([
- ['Add', AddEquation],
- ['Subtract', SubtractEquation],
- ['Reverse Subtract', ReverseSubtractEquation],
- ['Min', MinEquation],
- ['Max', MaxEquation],
- ] as [string, BlendingEquation][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'dropdown',
- property: [material, 'blendSrc'],
- hidden: ()=>material.blending !== CustomBlending,
- children: ([
- ['Zero', ZeroFactor],
- ['One', OneFactor],
- ['Src Color', SrcColorFactor],
- ['One Minus Src Color', OneMinusSrcColorFactor],
- ['Src Alpha', SrcAlphaFactor],
- ['One Minus Src Alpha', OneMinusSrcAlphaFactor],
- ['Dst Alpha', DstAlphaFactor],
- ['One Minus Dst Alpha', OneMinusDstAlphaFactor],
- ['Dst Color', DstColorFactor],
- ['One Minus Dst Color', OneMinusDstColorFactor],
- ['Src Alpha Saturate', SrcAlphaSaturateFactor],
- ['Constant Color', ConstantColorFactor],
- ['One Minus Constant Color', OneMinusConstantColorFactor],
- ['Constant Alpha', ConstantAlphaFactor],
- ['One Minus Constant Alpha', OneMinusConstantAlphaFactor],
- ] as [string, BlendingSrcFactor][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'dropdown',
- property: [material, 'blendDst'],
- hidden: ()=>material.blending !== CustomBlending,
- children: ([
- ['Zero', ZeroFactor],
- ['One', OneFactor],
- ['Src Color', SrcColorFactor],
- ['One Minus Src Color', OneMinusSrcColorFactor],
- ['Src Alpha', SrcAlphaFactor],
- ['One Minus Src Alpha', OneMinusSrcAlphaFactor],
- ['Dst Alpha', DstAlphaFactor],
- ['One Minus Dst Alpha', OneMinusDstAlphaFactor],
- ['Dst Color', DstColorFactor],
- ['One Minus Dst Color', OneMinusDstColorFactor],
- // ['Src Alpha Saturate', SrcAlphaSaturateFactor],
- ['Constant Color', ConstantColorFactor],
- ['One Minus Constant Color', OneMinusConstantColorFactor],
- ['Constant Alpha', ConstantAlphaFactor],
- ['One Minus Constant Alpha', OneMinusConstantAlphaFactor],
- ] as [string, BlendingSrcFactor][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'slider',
- bounds: [0, 1],
- hidden: ()=>material.blending !== CustomBlending,
- property: [material, 'blendSrcAlpha'],
- },
- {
- type: 'slider',
- bounds: [0, 1],
- hidden: ()=>material.blending !== CustomBlending,
- property: [material, 'blendDstAlpha'],
- },
- {
- type: 'color',
- hidden: ()=>material.blending !== CustomBlending ||
- material.blendSrc !== ConstantColorFactor &&
- material.blendSrc !== OneMinusConstantColorFactor &&
- material.blendDst !== ConstantColorFactor &&
- material.blendDst !== OneMinusConstantColorFactor,
- property: [material, 'blendColor'],
- },
- {
- type: 'slider',
- hidden: ()=>material.blending !== CustomBlending ||
- material.blendSrc !== ConstantAlphaFactor &&
- material.blendSrc !== OneMinusConstantAlphaFactor &&
- material.blendDst !== ConstantAlphaFactor &&
- material.blendDst !== OneMinusConstantAlphaFactor,
- bounds: [0, 1],
- property: [material, 'blendAlpha'],
- },
- material.alphaMap !== undefined ? {
- type: 'image',
- property: [material, 'alphaMap'],
- } : {},
- material.alphaMap !== undefined ? makeSamplerUi(material, 'alphaMap') : {},
- {
- type: 'checkbox',
- label: 'Render to Gbuffer',
- // hidden: ()=>!material.transparent && material.transmission < 0.001,
- getValue: ()=>material.userData.renderToGBuffer === true,
- setValue: (v: boolean)=>{
- if (!v && !material.userData.renderToGBuffer) return
- material.userData.renderToGBuffer = v
- material.setDirty()
- },
- },
- {
- type: 'checkbox',
- label: 'Render to Depth',
- hidden: ()=>material.userData.renderToDepth !== undefined,
- getValue: ()=>material.userData.renderToDepth === true,
- setValue: (v: boolean)=>{
- if (!v && !material.userData.renderToDepth) return
- material.userData.renderToDepth = v
- material.setDirty()
- },
- },
- material.isPhysicalMaterial ? {
- type: 'checkbox',
- label: 'Inverse AlphaMap',
- hidden: ()=>!material.transparent,
- getValue: ()=>material.userData.inverseAlphaMap === true,
- setValue: (v: boolean)=>{
- material.userData.inverseAlphaMap = v ? v : undefined
- material.setDirty()
- },
- } : {},
- ],
- }
- ),
- polygonOffset: (material: IMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Polygon Offset',
- children: [
- {
- type: 'checkbox',
- label: 'Polygon Offset',
- property: [material, 'polygonOffset'],
- },
- {
- type: 'slider',
- label: 'Polygon Offset Factor',
- bounds: [-10, 10],
- property: [material, 'polygonOffsetFactor'],
- },
- {
- type: 'slider',
- label: 'Polygon Offset Units',
- bounds: [-10, 10],
- property: [material, 'polygonOffsetUnits'],
- },
- ],
- }
- ),
- aoLightMap: (material: IMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'AO/Lightmap',
- children: [
- {
- type: 'slider',
- bounds: [0, 2],
- property: [material, 'aoMapIntensity'],
- },
- {
- type: 'image',
- property: [material, 'aoMap'],
- },
- makeSamplerUi(material, 'aoMap'),
- {
- type: 'slider',
- bounds: [0, 2],
- property: [material, 'lightMapIntensity'],
- },
- {
- type: 'image',
- property: [material, 'lightMap'],
- },
- makeSamplerUi(material, 'lightMap'),
- ],
- }
- ),
- environment: (material: IMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Environment',
- children: [
- {
- type: 'checkbox',
- label: 'Override Environment',
- // property: [material.userData, 'separateEnvMapIntensity'],
- getValue: ()=>material.userData.separateEnvMapIntensity === true,
- setValue: (v: boolean)=>{
- material.userData.separateEnvMapIntensity = v
- if (!v) delete material.userData.separateEnvMapIntensity
- },
- // onChange: material.setDirty,
- },
- {
- type: 'slider',
- bounds: [0, 20],
- hidden: ()=>!material.userData.separateEnvMapIntensity,
- label: 'Environment Intensity',
- property: [material, 'envMapIntensity'],
- },
- {
- type: 'dropdown',
- hidden: ()=>!material.userData.separateEnvMapIntensity && !material.userData.envMapSlotKey,
- label: 'Environment Map',
- children: ['', 'environment1', 'environment2'].map((i)=>({label: i || 'default', value: i})),
- getValue: ()=>material.userData.envMapSlotKey || '',
- setValue: (v: string)=>{
- material.userData.envMapSlotKey = v
- if (!v) delete material.userData.envMapSlotKey
- material.setDirty()
- },
- },
- ],
- }
- ),
- misc: (material: IMaterial): UiObjectConfig[] => [
- ()=>material.materialExtensions?.map(v=>{
- v.uuid = v.uuid || generateUUID()
- material.__matExtUiConfigs = material.__matExtUiConfigs || {}
- if (!material.__matExtUiConfigs[v.uuid]) material.__matExtUiConfigs[v.uuid] = v.getUiConfig?.(material, material.uiConfig?.uiRefresh)
- return material.__matExtUiConfigs[v.uuid]
- }).filter(v=>v),
- {
- type: 'dropdown',
- label: 'Side',
- property: [material, 'side'],
- children: ([
- ['Front', FrontSide],
- ['Back', BackSide],
- ['Double', DoubleSide],
- ] as [string, Side][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- {
- type: 'input',
- label: 'Mesh count',
- getValue: ()=>material.appliedMeshes.size || 0,
- disabled: true,
- },
- {
- type: 'button',
- label: `Download ${material.constructor.TypeSlug}`,
- value: ()=>{
- const blob = new Blob([JSON.stringify(material.toJSON(), null, 2)], {type: 'application/json'})
- downloadBlob(blob, `material.${material.constructor.TypeSlug}`)
- },
- },
- {
- type: 'button',
- label: `Select ${material.constructor.TypeSlug}`,
- value: async()=>uploadFile(false, false, material.constructor.TypeSlug).then(async(files)=>files?.[0]?.text()).then((text)=>{
- if (!text) return
- const json = JSON.parse(text)
- if (json.uuid) delete json.uuid // just copy the material properties
- const currentJson = material.toJSON()
- material.fromJSON(json, getEmptyMeta())
- return {
- undo: ()=>material.fromJSON(currentJson, getEmptyMeta()),
- redo: ()=>material.fromJSON(json, getEmptyMeta()),
- }
- }),
- },
- ],
- roughMetal: (material: PhysicalMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Rough/Metal',
- children: [
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'roughness'],
- },
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'metalness'],
- },
- {
- type: 'image',
- property: [material, 'roughnessMap'],
- },
- makeSamplerUi(material, 'roughnessMap'),
- {
- type: 'image',
- property: [material, 'metalnessMap'],
- },
- makeSamplerUi(material, 'metalnessMap'),
- ],
- }
- ),
- bumpNormal: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => (
- {
- type: 'folder',
- // uuid: 'bump_normal',
- label: 'Bump/Normal',
- children: [
- {
- type: 'slider',
- bounds: [-500, 500],
- stepSize: 0.001,
- property: [material, 'bumpScale'],
- hidden: ()=>!material.bumpMap,
- },
- {
- type: 'image',
- property: [material, 'bumpMap'],
- },
- makeSamplerUi(material, 'bumpMap'),
- {
- type: 'image',
- property: [material, 'normalMap'],
- },
- {
- type: 'vec2',
- property: [material, 'normalScale'],
- hidden: ()=>!material.normalMap,
- },
- {
- type: 'dropdown',
- hidden: ()=>!material.normalMap,
- property: [material, 'normalMapType'],
- children: ([
- ['TangentSpace', TangentSpaceNormalMap],
- ['ObjectSpace', ObjectSpaceNormalMap],
- ] as [string, NormalMapTypes][]).map(value => ({
- label: value[0],
- value: value[1],
- })),
- },
- makeSamplerUi(material, 'normalMap'),
- {
- type: 'input',
- property: [material, 'displacementScale'],
- hidden: ()=>!material.displacementMap,
- },
- {
- type: 'image',
- property: [material, 'displacementMap'],
- },
- makeSamplerUi(material, 'displacementMap'),
- ],
- }
- ),
- emission: (material: PhysicalMaterial|LegacyPhongMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Emission',
- children: [
- {
- type: 'color',
- property: [material, 'emissive'],
- },
- {
- type: 'slider',
- bounds: [0, 100],
- property: [material, 'emissiveIntensity'],
- },
- {
- type: 'image',
- property: [material, 'emissiveMap'],
- },
- makeSamplerUi(material, 'emissiveMap'),
- ],
- }
- ),
- transmission: (material: PhysicalMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Refraction',
- children: [
- // {
- // type: 'slider',
- // bounds: [0, 1],
- // property: [material, 'reflectivity'],
- // },
- {
- type: 'slider',
- bounds: [0, 4],
- property: [material, 'ior'],
- },
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'transmission'],
- },
- {
- type: 'slider',
- bounds: [0, 1],
- stepSize: 0.001,
- property: [material, 'thickness'],
- },
- {
- type: 'image',
- property: [material, 'transmissionMap'],
- },
- makeSamplerUi(material, 'transmissionMap'),
- {
- type: 'image',
- property: [material, 'thicknessMap'],
- },
- makeSamplerUi(material, 'thicknessMap'),
- {
- type: 'number',
- property: [material, 'attenuationDistance'],
- },
- {
- type: 'color',
- property: [material, 'attenuationColor'],
- },
- ],
- }
- ),
- clearcoat: (material: PhysicalMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Clearcoat',
- children: [
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'clearcoat'],
- },
- {
- type: 'slider',
- bounds: [0, 1],
- hidden: ()=>material.clearcoat < 0.001,
- property: [material, 'clearcoatRoughness'],
- },
- {
- type: 'image',
- property: [material, 'clearcoatMap'],
- },
- makeSamplerUi(material, 'clearcoatMap'),
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'clearcoatRoughness'],
- },
- {
- type: 'image',
- property: [material, 'clearcoatRoughnessMap'],
- },
- makeSamplerUi(material, 'clearcoatRoughnessMap'),
- {
- type: 'image',
- property: [material, 'clearcoatNormalMap'],
- },
- {
- type: 'vec2',
- property: [material, 'clearcoatNormalScale'],
- hidden: ()=>!material.clearcoatNormalMap,
- },
- makeSamplerUi(material, 'clearcoatNormalMap'),
- ],
- }
- ),
- iridescence: (material: PhysicalMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Iridescence',
- children: [
- {
- type: 'slider',
- bounds: [0, 3],
- label: 'Intensity',
- property: [material, 'iridescence'],
- },
- {
- type: 'slider',
- bounds: [0, 3],
- label: 'IOR',
- property: [material, 'iridescenceIOR'],
- },
- {
- type: 'slider',
- bounds: [0, 500],
- label: 'Thickness0',
- property: [material.iridescenceThicknessRange, '0'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'slider',
- bounds: [0, 500],
- label: 'Thickness1',
- property: [material.iridescenceThicknessRange, '1'],
- onChange: (ev)=>material.setDirty({uiChangeEvent: ev}),
- },
- {
- type: 'image',
- property: [material, 'iridescenceMap'],
- },
- makeSamplerUi(material, 'iridescenceMap'),
- {
- type: 'image',
- property: [material, 'iridescenceThicknessMap'],
- },
- makeSamplerUi(material, 'iridescenceThicknessMap'),
- ],
- }
- ),
- sheen: (material: PhysicalMaterial): UiObjectConfig => (
- {
- type: 'folder',
- label: 'Sheen',
- children: [
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'sheen'],
- },
- {
- type: 'color',
- hidden: ()=>material.sheen < 0.001,
- property: [material, 'sheenColor'],
- },
- {
- type: 'image',
- property: [material, 'sheenColorMap'],
- },
- makeSamplerUi(material, 'sheenColorMap'),
- {
- type: 'slider',
- bounds: [0, 1],
- property: [material, 'sheenRoughness'],
- },
- {
- type: 'image',
- property: [material, 'sheenRoughnessMap'],
- },
- makeSamplerUi(material, 'sheenRoughnessMap'),
- ],
- }
- ),
- }
|