From b3f21b3ec61aeddb5840f7d34e563a2b6d961a2b Mon Sep 17 00:00:00 2001 From: Kevin Levron Date: Mon, 19 Apr 2021 00:40:22 +0200 Subject: [PATCH] wip: materials --- src/materials/Material.ts | 6 +- src/materials/ShaderMaterial.js | 53 ----------- src/materials/ShaderMaterial.ts | 47 ++++++++++ src/materials/SubSurfaceMaterial.js | 55 ------------ src/materials/SubSurfaceMaterial.ts | 99 +++++++++++++++++++++ src/materials/SubsurfaceScatteringShader.ts | 28 +++--- 6 files changed, 162 insertions(+), 126 deletions(-) delete mode 100644 src/materials/ShaderMaterial.js create mode 100644 src/materials/ShaderMaterial.ts delete mode 100644 src/materials/SubSurfaceMaterial.js create mode 100644 src/materials/SubSurfaceMaterial.ts diff --git a/src/materials/Material.ts b/src/materials/Material.ts index 3af5d72..e119389 100644 --- a/src/materials/Material.ts +++ b/src/materials/Material.ts @@ -9,7 +9,6 @@ interface MaterialInterface { mesh?: MeshInterface material?: Material createMaterial?(): Material - addWatchers?(m: Material): void } export default defineComponent({ @@ -41,8 +40,7 @@ export default defineComponent({ if (this.createMaterial) { this.material = this.createMaterial() this.mesh.setMaterial(this.material) - this._addWatchers() - this.addWatchers?.(this.material) + this.addWatchers() } }, unmounted() { @@ -58,7 +56,7 @@ export default defineComponent({ setTexture(texture: Texture, key = 'map') { this.setProp(key, texture, true) }, - _addWatchers() { + addWatchers() { ['color', 'depthTest', 'depthWrite', 'fog', 'opacity', 'side', 'transparent'].forEach(p => { watch(() => this[p], (value) => { if (p === 'color') { diff --git a/src/materials/ShaderMaterial.js b/src/materials/ShaderMaterial.js deleted file mode 100644 index 4aea37b..0000000 --- a/src/materials/ShaderMaterial.js +++ /dev/null @@ -1,53 +0,0 @@ -import { defineComponent, watch } from 'vue'; -import { ShaderMaterial } from 'three'; -import { propsValues } from '../tools'; - -const defaultVertexShader = ` -varying vec2 vUv; -void main(){ - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); -}`; - -const defaultFragmentShader = ` -varying vec2 vUv; -void main() { - gl_FragColor = vec4(vUv.x, vUv.y, 0., 1.0); -}`; - -export default defineComponent({ - inject: ['three', 'mesh'], - props: { - uniforms: { type: Object, default: () => { return {}; } }, - vertexShader: { type: String, default: defaultVertexShader }, - fragmentShader: { type: String, default: defaultFragmentShader }, - }, - provide() { - return { - material: this, - }; - }, - created() { - this.createMaterial(); - ['vertexShader', 'fragmentShader'].forEach(p => { - watch(() => this[p], () => { - // recreate material if we change either shader - this.material.dispose(); - this.createMaterial(); - }); - }); - }, - unmounted() { - this.material.dispose(); - }, - methods: { - createMaterial() { - this.material = new ShaderMaterial(propsValues(this.$props)); - this.mesh.setMaterial(this.material); - }, - }, - render() { - return this.$slots.default ? this.$slots.default() : []; - }, - __hmrId: 'ShaderMaterial', -}); diff --git a/src/materials/ShaderMaterial.ts b/src/materials/ShaderMaterial.ts new file mode 100644 index 0000000..b87b98d --- /dev/null +++ b/src/materials/ShaderMaterial.ts @@ -0,0 +1,47 @@ +import { defineComponent, watch } from 'vue' +import { ShaderMaterial } from 'three' +import Material from './Material' + +const defaultVertexShader = ` + varying vec2 vUv; + void main(){ + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); + } +` + +const defaultFragmentShader = ` + varying vec2 vUv; + void main() { + gl_FragColor = vec4(vUv.x, vUv.y, 0., 1.0); + } +` + +export default defineComponent({ + extends: Material, + props: { + uniforms: { type: Object, default: () => ({}) }, + vertexShader: { type: String, default: defaultVertexShader }, + fragmentShader: { type: String, default: defaultFragmentShader }, + }, + methods: { + createMaterial() { + const material = new ShaderMaterial({ + uniforms: this.uniforms, + vertexShader: this.vertexShader, + fragmentShader: this.fragmentShader, + }) + + const watchProps = ['vertexShader', 'fragmentShader'] + watchProps.forEach(p => { + watch(() => this[p], (value) => { + this.setProp(p, value, true) + }) + }) + + return material + }, + addWatchers() {}, + }, + __hmrId: 'ShaderMaterial', +}) diff --git a/src/materials/SubSurfaceMaterial.js b/src/materials/SubSurfaceMaterial.js deleted file mode 100644 index 1fc08c6..0000000 --- a/src/materials/SubSurfaceMaterial.js +++ /dev/null @@ -1,55 +0,0 @@ -import { defineComponent } from 'vue'; -import { Color, ShaderMaterial as TShaderMaterial, UniformsUtils } from 'three'; -import SubsurfaceScatteringShader from './SubsurfaceScatteringShader.js'; - -export default defineComponent({ - inject: ['three', 'mesh'], - props: { - color: { type: String, default: '#ffffff' }, - thicknessColor: { type: String, default: '#ffffff' }, - thicknessDistortion: { type: Number, default: 0.4 }, - thicknessAmbient: { type: Number, default: 0.01 }, - thicknessAttenuation: { type: Number, default: 0.7 }, - thicknessPower: { type: Number, default: 2 }, - thicknessScale: { type: Number, default: 4 }, - transparent: { type: Boolean, default: false }, - opacity: { type: Number, default: 1 }, - vertexColors: { type: Boolean, default: false }, - }, - created() { - this.createMaterial(); - this.mesh.setMaterial(this.material); - }, - unmounted() { - this.material.dispose(); - }, - methods: { - createMaterial() { - const params = SubsurfaceScatteringShader; - const uniforms = UniformsUtils.clone(params.uniforms); - - Object.entries(this.$props).forEach(([key, value]) => { - let _key = key, _value = value; - if (['color', 'thicknessColor'].includes(key)) { - if (key === 'color') _key = 'diffuse'; - _value = new Color(value); - } - if (!['transparent', 'vertexColors'].includes(key)) { - uniforms[_key].value = _value; - } - }); - - this.material = new TShaderMaterial({ - ...params, - uniforms, - lights: true, - transparent: this.transparent, - vertexColors: this.vertexColors, - }); - }, - }, - render() { - return []; - }, - __hmrId: 'SubSurfaceMaterial', -}); diff --git a/src/materials/SubSurfaceMaterial.ts b/src/materials/SubSurfaceMaterial.ts new file mode 100644 index 0000000..3b30842 --- /dev/null +++ b/src/materials/SubSurfaceMaterial.ts @@ -0,0 +1,99 @@ +import { defineComponent } from 'vue' +import { Color, ShaderMaterial, UniformsUtils } from 'three' +import SubsurfaceScatteringShader from './SubsurfaceScatteringShader' +import Material from './Material' +// import { bindProps, propsValues } from '../tools' + +export default defineComponent({ + extends: Material, + props: { + thicknessColor: { type: String, default: '#ffffff' }, + thicknessDistortion: { type: Number, default: 0.4 }, + thicknessAmbient: { type: Number, default: 0.01 }, + thicknessAttenuation: { type: Number, default: 0.7 }, + thicknessPower: { type: Number, default: 2 }, + thicknessScale: { type: Number, default: 4 }, + }, + methods: { + createMaterial() { + const params = SubsurfaceScatteringShader + const uniforms = UniformsUtils.clone(params.uniforms) + + // Object.entries(this.$props).forEach(([key, value]) => { + // let _key = key, _value = value + // if (['color', 'thicknessColor'].includes(key)) { + // if (key === 'color') _key = 'diffuse' + // _value = new Color(value) + // } + // if (!['transparent', 'vertexColors'].includes(key)) { + // console.log(_key) + // uniforms[_key].value = _value + // } + // }) + + const material = new ShaderMaterial({ + ...params, + uniforms, + lights: true, + transparent: this.transparent, + vertexColors: this.vertexColors, + }) + + return material + }, + }, + __hmrId: 'SubSurfaceMaterial', +}) + + +// export default defineComponent({ +// inject: ['three', 'mesh'], +// props: { +// color: { type: String, default: '#ffffff' }, +// thicknessColor: { type: String, default: '#ffffff' }, +// thicknessDistortion: { type: Number, default: 0.4 }, +// thicknessAmbient: { type: Number, default: 0.01 }, +// thicknessAttenuation: { type: Number, default: 0.7 }, +// thicknessPower: { type: Number, default: 2 }, +// thicknessScale: { type: Number, default: 4 }, +// transparent: { type: Boolean, default: false }, +// opacity: { type: Number, default: 1 }, +// vertexColors: { type: Boolean, default: false }, +// }, +// created() { +// this.createMaterial() +// this.mesh.setMaterial(this.material) +// }, +// unmounted() { +// this.material.dispose() +// }, +// methods: { +// createMaterial() { +// const params = SubsurfaceScatteringShader +// const uniforms = UniformsUtils.clone(params.uniforms) + +// Object.entries(this.$props).forEach(([key, value]) => { +// let _key = key, _value = value +// if (['color', 'thicknessColor'].includes(key)) { +// if (key === 'color') _key = 'diffuse' +// _value = new Color(value) +// } +// if (!['transparent', 'vertexColors'].includes(key)) { +// uniforms[_key].value = _value +// } +// }) + +// this.material = new TShaderMaterial({ +// ...params, +// uniforms, +// lights: true, +// transparent: this.transparent, +// vertexColors: this.vertexColors, +// }) +// }, +// }, +// render() { +// return [] +// }, +// __hmrId: 'SubSurfaceMaterial', +// }) diff --git a/src/materials/SubsurfaceScatteringShader.ts b/src/materials/SubsurfaceScatteringShader.ts index d5a075c..168b06e 100644 --- a/src/materials/SubsurfaceScatteringShader.ts +++ b/src/materials/SubsurfaceScatteringShader.ts @@ -45,23 +45,23 @@ const SubsurfaceScatteringShader = { ${meshphongFragHead} - uniform float thicknessPower - uniform float thicknessScale - uniform float thicknessDistortion - uniform float thicknessAmbient - uniform float thicknessAttenuation - uniform vec3 thicknessColor + uniform float thicknessPower; + uniform float thicknessScale; + uniform float thicknessDistortion; + uniform float thicknessAmbient; + uniform float thicknessAttenuation; + uniform vec3 thicknessColor; void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in GeometricContext geometry, inout ReflectedLight reflectedLight) { #ifdef USE_COLOR - vec3 thickness = vColor * thicknessColor + vec3 thickness = vColor * thicknessColor; #else - vec3 thickness = thicknessColor + vec3 thickness = thicknessColor; #endif - vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion)) - float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale - vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness - reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color + vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion)); + float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale; + vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness; + reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color; } ` + meshphongFragBody.replace( '#include ', @@ -69,9 +69,9 @@ const SubsurfaceScatteringShader = { ShaderChunk.lights_fragment_begin, 'RE_Direct( directLight, geometry, material, reflectedLight );', ` - RE_Direct( directLight, geometry, material, reflectedLight ) + RE_Direct( directLight, geometry, material, reflectedLight ); #if defined( SUBSURFACE ) && defined( USE_UV ) - RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight) + RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight); #endif ` )