UNPKG

threepipe

Version:

A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.

548 lines 18.7 kB
import { makeSamplerUi } from '../../ui/image-ui'; import { AdditiveBlending, AlwaysDepth, BackSide, DoubleSide, EqualDepth, FrontSide, GreaterDepth, GreaterEqualDepth, LessDepth, LessEqualDepth, MultiplyBlending, NeverDepth, NoBlending, NormalBlending, NotEqualDepth, ObjectSpaceNormalMap, SubtractiveBlending, TangentSpaceNormalMap, } from 'three'; import { downloadBlob, uploadFile } from 'ts-browser-helpers'; import { getEmptyMeta } from '../../utils'; import { generateUUID } from '../../three/utils'; export const iMaterialUI = { base: (material) => [ { 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) => ({ 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], ].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, 'dithering'], }, { type: 'dropdown', label: 'Blending', property: [material, 'blending'], children: [ ['None', NoBlending], ['Normal', NormalBlending], ['Additive', AdditiveBlending], ['Subtractive', SubtractiveBlending], ['Multiply', MultiplyBlending], ].map(value => ({ label: value[0], value: value[1], })), }, 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) => { 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) => { 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) => { material.userData.inverseAlphaMap = v ? v : undefined; material.setDirty(); }, } : {}, ], }), polygonOffset: (material) => ({ 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) => ({ 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) => ({ type: 'folder', label: 'Environment', children: [ { type: 'checkbox', label: 'Override Environment', // property: [this.userData, 'separateEnvMapIntensity'], getValue: () => material.userData.separateEnvMapIntensity === true, setValue: (v) => { 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) => { material.userData.envMapSlotKey = v; if (!v) delete material.userData.envMapSlotKey; material.setDirty(); }, }, ], }), misc: (material) => [ () => 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], ].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) => ({ 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) => ({ type: 'folder', // uuid: 'bump_normal', label: 'Bump/Normal', children: [ { type: 'slider', bounds: [-1, 1], 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], ].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) => ({ type: 'folder', label: 'Emission', children: [ { type: 'color', property: [material, 'emissive'], }, { type: 'slider', bounds: [0, 10], property: [material, 'emissiveIntensity'], }, { type: 'image', property: [material, 'emissiveMap'], }, makeSamplerUi(material, 'emissiveMap'), ], }), transmission: (material) => ({ 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) => ({ 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) => ({ 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) => ({ 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'), ], }), }; //# sourceMappingURL=IMaterialUi.js.map