1
0
mirror of https://github.com/troisjs/trois.git synced 2024-11-24 04:12:02 +08:00

wip: materials

This commit is contained in:
Kevin Levron 2021-04-19 00:10:00 +02:00
parent b37c1b465f
commit 457d871269
17 changed files with 249 additions and 232 deletions

View File

@ -1,20 +0,0 @@
import { defineComponent } from 'vue';
import { MeshBasicMaterial } from 'three';
import { bindProps, propsValues } from '../tools';
import Material, { wireframeProps } from './Material';
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
this.material = new MeshBasicMaterial(propsValues(this.$props));
},
addWatchers() {
bindProps(this, Object.keys(wireframeProps), this.material);
},
},
__hmrId: 'BasicMaterial',
});

View File

@ -0,0 +1,19 @@
import { defineComponent } from 'vue'
import { MeshBasicMaterial } from 'three'
import { bindProps, propsValues } from '../tools'
import Material, { wireframeProps } from './Material'
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
const material = new MeshBasicMaterial(propsValues(this.$props))
bindProps(this, Object.keys(wireframeProps), material)
return material
},
},
__hmrId: 'BasicMaterial',
})

View File

@ -1,20 +0,0 @@
import { defineComponent } from 'vue';
import { MeshLambertMaterial } from 'three';
import { bindProps, propsValues } from '../tools';
import Material, { wireframeProps } from './Material';
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
this.material = new MeshLambertMaterial(propsValues(this.$props));
},
addWatchers() {
bindProps(this, Object.keys(wireframeProps), this.material);
},
},
__hmrId: 'LambertMaterial',
});

View File

@ -0,0 +1,19 @@
import { defineComponent } from 'vue'
import { MeshLambertMaterial } from 'three'
import { bindProps, propsValues } from '../tools'
import Material, { wireframeProps } from './Material'
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
const material = new MeshLambertMaterial(propsValues(this.$props))
bindProps(this, Object.keys(wireframeProps), material)
return material
},
},
__hmrId: 'LambertMaterial',
})

View File

@ -1,25 +0,0 @@
import { defineComponent } from 'vue';
import { MeshMatcapMaterial, TextureLoader } from 'three';
import { propsValues, getMatcapUrl } from '../tools';
import Material from './Material';
export default defineComponent({
extends: Material,
props: {
src: String,
name: String,
flatShading: Boolean,
},
methods: {
createMaterial() {
const src = this.name ? getMatcapUrl(this.name) : this.src;
const opts = propsValues(this.$props, ['src', 'name']);
opts.matcap = new TextureLoader().load(src);
this.material = new MeshMatcapMaterial(opts);
},
addWatchers() {
// TODO
},
},
__hmrId: 'MatcapMaterial',
});

View File

@ -0,0 +1,22 @@
import { defineComponent } from 'vue'
import { MeshMatcapMaterial, TextureLoader } from 'three'
import { propsValues, getMatcapUrl } from '../tools'
import Material from './Material'
export default defineComponent({
extends: Material,
props: {
src: String,
name: { type: String, default: '0404E8_0404B5_0404CB_3333FC' },
flatShading: Boolean,
},
methods: {
createMaterial() {
const src = this.src ? this.src : getMatcapUrl(this.name)
const opts = propsValues(this.$props, ['src', 'name'])
opts.matcap = new TextureLoader().load(src)
return new MeshMatcapMaterial(opts)
},
},
__hmrId: 'MatcapMaterial',
})

View File

@ -1,63 +0,0 @@
import { defineComponent, watch } from 'vue';
import { FrontSide } from 'three';
export default defineComponent({
inject: ['three', 'mesh'],
props: {
color: { type: [String, Number], default: '#ffffff' },
depthTest: { type: Boolean, default: true },
depthWrite: { type: Boolean, default: true },
fog: { type: Boolean, default: true },
opacity: { type: Number, default: 1 },
side: { type: Number, default: FrontSide },
transparent: Boolean,
vertexColors: Boolean,
},
provide() {
return {
material: this,
};
},
created() {
this.createMaterial();
this.mesh.setMaterial(this.material);
this._addWatchers();
if (this.addWatchers) this.addWatchers();
},
unmounted() {
this.material.dispose();
},
methods: {
setProp(key, value, needsUpdate = false) {
this.material[key] = value;
this.material.needsUpdate = needsUpdate;
},
setTexture(texture, key = 'map') {
this.setProp(key, texture, true);
},
_addWatchers() {
['color', 'depthTest', 'depthWrite', 'fog', 'opacity', 'side', 'transparent'].forEach(p => {
watch(() => this[p], () => {
if (p === 'color') {
this.material.color.set(this.color);
} else {
this.material[p] = this[p];
}
});
});
},
},
render() {
return this.$slots.default ? this.$slots.default() : [];
},
__hmrId: 'Material',
});
export const wireframeProps = {
wireframe: { type: Boolean, default: false },
// not needed for WebGL
// wireframeLinecap: { type: String, default: 'round' },
// wireframeLinejoin: { type: String, default: 'round' },
wireframeLinewidth: { type: Number, default: 1 }, // not really useful
};

85
src/materials/Material.ts Normal file
View File

@ -0,0 +1,85 @@
import { defineComponent, watch } from 'vue'
import { FrontSide, Material, Texture } from 'three'
interface MeshInterface {
setMaterial(material: Material): void
}
interface MaterialInterface {
mesh?: MeshInterface
material?: Material
createMaterial?(): Material
addWatchers?(m: Material): void
}
export default defineComponent({
inject: ['three', 'mesh'],
props: {
color: { type: [String, Number], default: '#ffffff' },
depthTest: { type: Boolean, default: true },
depthWrite: { type: Boolean, default: true },
fog: { type: Boolean, default: true },
opacity: { type: Number, default: 1 },
side: { type: Number, default: FrontSide },
transparent: Boolean,
vertexColors: Boolean,
},
setup(): MaterialInterface {
return {}
},
provide() {
return {
material: this,
}
},
created() {
if (!this.mesh) {
console.error('Missing parent Mesh')
return
}
if (this.createMaterial) {
this.material = this.createMaterial()
this.mesh.setMaterial(this.material)
this._addWatchers()
this.addWatchers?.(this.material)
}
},
unmounted() {
this.material?.dispose()
},
methods: {
setProp(key: string, value: any, needsUpdate = false) {
if (this.material) {
this.material[key] = value
this.material.needsUpdate = needsUpdate
}
},
setTexture(texture: Texture, key = 'map') {
this.setProp(key, texture, true)
},
_addWatchers() {
['color', 'depthTest', 'depthWrite', 'fog', 'opacity', 'side', 'transparent'].forEach(p => {
watch(() => this[p], (value) => {
if (p === 'color') {
this.material.color.set(value)
} else {
this.material[p] = value
}
})
})
},
},
render() {
return this.$slots.default ? this.$slots.default() : []
},
__hmrId: 'Material',
})
export const wireframeProps = {
wireframe: { type: Boolean, default: false },
// not needed for WebGL
// wireframeLinecap: { type: String, default: 'round' },
// wireframeLinejoin: { type: String, default: 'round' },
wireframeLinewidth: { type: Number, default: 1 }, // not really useful
}

View File

@ -1,7 +1,7 @@
import { defineComponent, watch } from 'vue'; import { defineComponent, watch } from 'vue'
import { MeshPhongMaterial } from 'three'; import { MeshPhongMaterial } from 'three'
import { bindProps, propsValues } from '../tools'; import { bindProps, propsValues } from '../tools'
import Material, { wireframeProps } from './Material'; import Material, { wireframeProps } from './Material'
export default defineComponent({ export default defineComponent({
extends: Material, extends: Material,
@ -16,21 +16,23 @@ export default defineComponent({
}, },
methods: { methods: {
createMaterial() { createMaterial() {
this.material = new MeshPhongMaterial(propsValues(this.$props)); const material = new MeshPhongMaterial(propsValues(this.$props))
},
addWatchers() {
// TODO : handle flatShading ? // TODO : handle flatShading ?
['emissive', 'emissiveIntensity', 'reflectivity', 'shininess', 'specular'].forEach(p => { const watchProps = ['emissive', 'emissiveIntensity', 'reflectivity', 'shininess', 'specular']
watchProps.forEach(p => {
watch(() => this[p], (value) => { watch(() => this[p], (value) => {
if (p === 'emissive' || p === 'specular') { if (p === 'emissive' || p === 'specular') {
this.material[p].set(value); material[p].set(value)
} else { } else {
this.material[p] = value; material[p] = value
} }
}); })
}); })
bindProps(this, Object.keys(wireframeProps), this.material); bindProps(this, Object.keys(wireframeProps), material)
return material
}, },
}, },
__hmrId: 'PhongMaterial', __hmrId: 'PhongMaterial',
}); })

View File

@ -1,20 +0,0 @@
import { defineComponent } from 'vue';
import { MeshPhysicalMaterial } from 'three';
import { propsValues } from '../tools';
import StandardMaterial from './StandardMaterial';
export default defineComponent({
extends: StandardMaterial,
props: {
flatShading: Boolean,
},
methods: {
createMaterial() {
this.material = new MeshPhysicalMaterial(propsValues(this.$props));
},
addWatchers() {
// TODO
},
},
__hmrId: 'PhysicalMaterial',
});

View File

@ -0,0 +1,17 @@
import { defineComponent } from 'vue'
import { MeshPhysicalMaterial } from 'three'
import { propsValues } from '../tools'
import StandardMaterial from './StandardMaterial'
export default defineComponent({
extends: StandardMaterial,
props: {
flatShading: Boolean,
},
methods: {
createMaterial() {
return new MeshPhysicalMaterial(propsValues(this.$props))
},
},
__hmrId: 'PhysicalMaterial',
})

View File

@ -1,7 +1,7 @@
import { defineComponent, watch } from 'vue'; import { defineComponent, watch } from 'vue'
import { MeshStandardMaterial } from 'three'; import { MeshStandardMaterial } from 'three'
import { bindProp, bindProps, propsValues } from '../tools'; import { bindProp, bindProps, propsValues } from '../tools'
import Material, { wireframeProps } from './Material'; import Material, { wireframeProps } from './Material'
const props = { const props = {
aoMapIntensity: { type: Number, default: 1 }, aoMapIntensity: { type: Number, default: 1 },
@ -13,11 +13,11 @@ const props = {
envMapIntensity: { type: Number, default: 1 }, envMapIntensity: { type: Number, default: 1 },
lightMapIntensity: { type: Number, default: 1 }, lightMapIntensity: { type: Number, default: 1 },
metalness: { type: Number, default: 0 }, metalness: { type: Number, default: 0 },
normalScale: { type: Object, default: { x: 1, y: 1 } }, normalScale: { type: Object, default: () => ({ x: 1, y: 1 }) },
roughness: { type: Number, default: 1 }, roughness: { type: Number, default: 1 },
refractionRatio: { type: Number, default: 0.98 }, refractionRatio: { type: Number, default: 0.98 },
flatShading: Boolean, flatShading: Boolean,
}; }
export default defineComponent({ export default defineComponent({
extends: Material, extends: Material,
@ -27,23 +27,25 @@ export default defineComponent({
}, },
methods: { methods: {
createMaterial() { createMaterial() {
this.material = new MeshStandardMaterial(propsValues(this.$props, ['normalScale'])); const material = new MeshStandardMaterial(propsValues(this.$props, ['normalScale']))
},
addWatchers() {
// TODO : use setProp, handle flatShading ? // TODO : use setProp, handle flatShading ?
Object.keys(props).forEach(p => { Object.keys(props).forEach(p => {
if (p === 'normalScale') return; if (p === 'normalScale') return
watch(() => this[p], (value) => { watch(() => this[p], (value) => {
if (p === 'emissive') { if (p === 'emissive') {
this.material[p].set(value); material[p].set(value)
} else { } else {
this.material[p] = value; material[p] = value
} }
}); })
}); })
bindProp(this, 'normalScale', this.material);
bindProps(this, Object.keys(wireframeProps), this.material); bindProp(this, 'normalScale', material)
bindProps(this, Object.keys(wireframeProps), material)
return material
}, },
}, },
__hmrId: 'StandardMaterial', __hmrId: 'StandardMaterial',
}); })

View File

@ -11,14 +11,14 @@ import {
ShaderChunk, ShaderChunk,
ShaderLib, ShaderLib,
UniformsUtils, UniformsUtils,
} from 'three'; } from 'three'
function replaceAll(string, find, replace) { function replaceAll(string: string, find: string, replace: string) {
return string.split(find).join(replace); return string.split(find).join(replace)
} }
const meshphongFragHead = ShaderChunk.meshphong_frag.slice(0, ShaderChunk.meshphong_frag.indexOf('void main() {')); const meshphongFragHead = ShaderChunk.meshphong_frag.slice(0, ShaderChunk.meshphong_frag.indexOf('void main() {'))
const meshphongFragBody = ShaderChunk.meshphong_frag.slice(ShaderChunk.meshphong_frag.indexOf('void main() {')); const meshphongFragBody = ShaderChunk.meshphong_frag.slice(ShaderChunk.meshphong_frag.indexOf('void main() {'))
const SubsurfaceScatteringShader = { const SubsurfaceScatteringShader = {
@ -45,23 +45,23 @@ const SubsurfaceScatteringShader = {
${meshphongFragHead} ${meshphongFragHead}
uniform float thicknessPower; uniform float thicknessPower
uniform float thicknessScale; uniform float thicknessScale
uniform float thicknessDistortion; uniform float thicknessDistortion
uniform float thicknessAmbient; uniform float thicknessAmbient
uniform float thicknessAttenuation; uniform float thicknessAttenuation
uniform vec3 thicknessColor; uniform vec3 thicknessColor
void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in GeometricContext geometry, inout ReflectedLight reflectedLight) { void RE_Direct_Scattering(const in IncidentLight directLight, const in vec2 uv, const in GeometricContext geometry, inout ReflectedLight reflectedLight) {
#ifdef USE_COLOR #ifdef USE_COLOR
vec3 thickness = vColor * thicknessColor; vec3 thickness = vColor * thicknessColor
#else #else
vec3 thickness = thicknessColor; vec3 thickness = thicknessColor
#endif #endif
vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion)); vec3 scatteringHalf = normalize(directLight.direction + (geometry.normal * thicknessDistortion))
float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale; float scatteringDot = pow(saturate(dot(geometry.viewDir, -scatteringHalf)), thicknessPower) * thicknessScale
vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness; vec3 scatteringIllu = (scatteringDot + thicknessAmbient) * thickness
reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color; reflectedLight.directDiffuse += scatteringIllu * thicknessAttenuation * directLight.color
} }
` + meshphongFragBody.replace( ` + meshphongFragBody.replace(
'#include <lights_fragment_begin>', '#include <lights_fragment_begin>',
@ -69,13 +69,13 @@ const SubsurfaceScatteringShader = {
ShaderChunk.lights_fragment_begin, ShaderChunk.lights_fragment_begin,
'RE_Direct( directLight, geometry, material, reflectedLight );', 'RE_Direct( directLight, geometry, material, reflectedLight );',
` `
RE_Direct( directLight, geometry, material, reflectedLight ); RE_Direct( directLight, geometry, material, reflectedLight )
#if defined( SUBSURFACE ) && defined( USE_UV ) #if defined( SUBSURFACE ) && defined( USE_UV )
RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight); RE_Direct_Scattering(directLight, vUv, geometry, reflectedLight)
#endif #endif
` `
) )
), ),
}; }
export default SubsurfaceScatteringShader; export default SubsurfaceScatteringShader

View File

@ -1,20 +0,0 @@
import { defineComponent } from 'vue';
import { MeshToonMaterial } from 'three';
import { bindProps, propsValues } from '../tools';
import Material, { wireframeProps } from './Material';
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
this.material = new MeshToonMaterial(propsValues(this.$props));
},
addWatchers() {
bindProps(this, Object.keys(wireframeProps), this.material);
},
},
__hmrId: 'ToonMaterial',
});

View File

@ -0,0 +1,19 @@
import { defineComponent } from 'vue'
import { MeshToonMaterial } from 'three'
import { bindProps, propsValues } from '../tools'
import Material, { wireframeProps } from './Material'
export default defineComponent({
extends: Material,
props: {
...wireframeProps,
},
methods: {
createMaterial() {
const material = new MeshToonMaterial(propsValues(this.$props))
bindProps(this, Object.keys(wireframeProps), material)
return material
},
},
__hmrId: 'ToonMaterial',
})

View File

@ -1,12 +0,0 @@
export { default as BasicMaterial } from './BasicMaterial.js';
export { default as LambertMaterial } from './LambertMaterial.js';
export { default as MatcapMaterial } from './MatcapMaterial.js';
export { default as PhongMaterial } from './PhongMaterial.js';
export { default as PhysicalMaterial } from './PhysicalMaterial.js';
export { default as ShaderMaterial } from './ShaderMaterial.js';
export { default as StandardMaterial } from './StandardMaterial.js';
export { default as SubSurfaceMaterial } from './SubSurfaceMaterial.js';
export { default as ToonMaterial } from './ToonMaterial.js';
export { default as Texture } from './Texture.js';
export { default as CubeTexture } from './CubeTexture.js';

12
src/materials/index.ts Normal file
View File

@ -0,0 +1,12 @@
export { default as BasicMaterial } from './BasicMaterial'
export { default as LambertMaterial } from './LambertMaterial'
export { default as MatcapMaterial } from './MatcapMaterial'
export { default as PhongMaterial } from './PhongMaterial'
export { default as PhysicalMaterial } from './PhysicalMaterial'
export { default as ShaderMaterial } from './ShaderMaterial'
export { default as StandardMaterial } from './StandardMaterial'
export { default as SubSurfaceMaterial } from './SubSurfaceMaterial'
export { default as ToonMaterial } from './ToonMaterial'
export { default as Texture } from './Texture'
export { default as CubeTexture } from './CubeTexture'