js/Mobilizing/renderer/3D/three/scene/Material.js
import * as THREE from "three";
import Color from "../types/Color";
/**
* A material will give color and some effect to the surface of the 3D object.
* Mobilizing.js 3D renderer is based on the one of Three.js https://threejs.org/docs/index.html#api/en/materials/Material and its variations
*/
export default class Material {
/**
* @example
* //this is how to use a parameters object in order to instanciate a Mobilizing.js object
* var mobilizingObject = new Mobilizing.Class({paramName1: value, paramName2: value});
*
* @param {Object} params The parameters object
* @param {String | THREE.Material} [params.type="basic"] the type of the matrial, one of "basic", "projectionmapping", "phong", "line", "sprite", or directly a Three.js Material.
* @param {Color} [params.color=Color.white.clone()]
* @param {String} [params.shading="flat"]
* @param {Object} [params.customParams={}] the parameters to use for custom type.
*/
constructor({
type = "default",
color = Color.white.clone(),
shading = "flat", //|| "smooth"
customParams = {}
} = {}) {
this.type = type;
this.color = color;
this.shading = shading;
this.customParams = customParams;
this.texture = undefined;
//console.log(this.type);
if (this.type instanceof THREE.Material) {
console.log("THREE.Material input");
this._material = this.type;
}
else {
switch (this.type) {
case "basic":
this._material = new THREE.MeshBasicMaterial({
color: this.color,
wireframe: false
/*,overdraw: true*/
});
break;
case "points":
this._material = new THREE.PointsMaterial({ color: this.color });
break;
case "custom":
this._material = new THREE.ShaderMaterial(this.customParams);
break;
case "projectionmapping":
// eslint-disable-next-line no-case-declarations
const shader = THREE.ShaderLib.cube;
// eslint-disable-next-line no-case-declarations
const uniforms = THREE.UniformsUtils.clone(shader.uniforms);
shader.vertexShader = shader.vertexShader.replace("vWorldPosition = transformDirection( position, modelMatrix );",
"vWorldPosition = (modelMatrix * vec4( position, 0.0 )).xyz;");
shader.fragmentShader = shader.fragmentShader.replace("gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",
"vec3 viewDir = vWorldPosition-viewPosition; gl_FragColor = textureCube( tCube, normalize(viewDir));");
shader.fragmentShader = shader.fragmentShader.replace("uniform samplerCube tCube;",
"uniform samplerCube tCube; uniform vec3 viewPosition;");
uniforms.viewPosition = { type: 'v3', value: new THREE.Vector3(0, 0, 0) };
this._material = new THREE.ShaderMaterial({
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms
});
break;
case "lambert": //vertex lit
this._material = new THREE.MeshLambertMaterial({
color: 0xffffff,
wireframe: false
});
break;
case "default":
case "phong":
this._material = new THREE.MeshPhongMaterial({ color: this.color });
break;
case "line":
this._material = new THREE.LineBasicMaterial({ color: this.color });
break;
case "sprite":
this._material = new THREE.SpriteMaterial({ color: this.color });
break;
default:
this._material = new THREE.MeshBasicMaterial({ color: this.color, wireframe: false });
}
}
this.setShading(this.shading);
this._material.side = THREE.DoubleSide;
}
/**
* @returns the Three.js native object used in this class
*/
getNativeObject() {
return this._material;
}
/**
* set this material texture
* @param {Texture} texture
*/
setTexture(texture) {
this.texture = texture;
if (this.texture.getNativeObject) {
const nativeTexture = this.texture.getNativeObject();
if (nativeTexture) {
this._material.map = nativeTexture;
//this._material.needsUpdate = true;
}
}
else {
this._material.map = texture;
}
/* else if (texture.cube) {
if (this.type === "projectionmapping") {
this._material.uniforms.tCube.value = texture.cube; // textureCube has been init before
}
else {
this._material.envMap = texture.cube;
}
} */
}
/**
* Gets the current texture
* @return {Texture}
*/
getTexture() {
return this.texture;
}
/**
* @param {String} name the name of the uniform to set
* @param {Object} value the value of the uniform to set
*/
setUniform(name, value) {
this._material.uniforms[name].value = value;
}
/**
* @param {Boolean} trans
*/
setTransparent(trans) {
this._material.transparent = trans;
}
/**
* @return {Boolean}
*/
getTransparent() {
return this._material.transparent;
}
/**
* @param {Color} color
*/
setColor(color) {
this.color = color;
this._material.color = this.color;
}
/**
* @return {Color}
*/
getColor() {
return this.color;
}
/**
* @param {Boolean} wireframe
*/
setWireframe(wireframe) {
this._material.wireframe = wireframe;
}
/**
* @return {Boolean}
*/
getWireframe() {
return this._material.wireframe;
}
/**
* @param {float} op between 0 and 1
*/
setOpacity(op) {
this._material.opacity = op;
}
/**
* @return {float}
*/
getOpacity() {
return this._material.opacity;
}
/**
* @param {Boolean} sided
*/
setDoubleSided(sided) {
this._material.side = sided ? THREE.DoubleSide : THREE.FrontSide;
}
/**
* @return {Boolean}
*/
getDoubleSided() {
return (this._material.side === THREE.DoubleSide);
}
/**
* @param {Number} val between 0 and 1
*/
setAlphaTest(val) {
this._material.alphaTest = val;
}
/**
* @return {Number}
*/
getAlphaTest() {
return this._material.alphaTest;
}
/**
* Sets the depth write.
* @param {boolean} bool - The depthWrite value
*/
setDepthWrite(bool) {
this._material.depthWrite = bool;
}
/**
* Sets the depth test.
* @param {boolean} bool - The depthTest value
*/
setDepthTest(bool) {
this._material.depthTest = bool;
}
/**
* @param {Number} val
*/
setLineWidth(val) {
this._material.linewidth = val;
}
/**
* @return {Number}
*/
getLineWidth() {
return this._material.linewidth;
}
/**
* @param {Number} val
*/
setPointSize(val) {
if (this._material.isPointsMaterial) {
this._material.size = val;
}
}
/**
* @return {Number}
*/
getPointSize() {
if (this._material.isPointsMaterial) {
return this._material.size;
}
return undefined;
}
/**
* @param {Number} color
*/
setShininess(val) {
this._material.shininess = val;
}
/**
* @return {Number}
*/
getShininess() {
return this._material.shininess;
}
/**
* @param {Color} color
*/
setEmissiveColor(color) {
this._material.emissive = color;
}
/**
* @return {Color}
*/
getEmissiveColor() {
return this._material.emissive;
}
/**
* @param {String} shading one of "smooth", "flat"
*/
setShading(shading) {
this.shading = shading;
this._material.flatShading = ((this.shading === "flat") ? true : false);
this._material.needsUpdate = true;
}
/**
* @param {Color} color
*/
setSpecularColor(color) {
this._material.specular = color;
}
/**
* @return {Color}
*/
getSpecularColor() {
return this._material.specular;
}
//cf http://blog.cjgammon.com/threejs-custom-shader-material
//cf https://threejs.org/docs/index.html#api/en/materials/ShaderMaterial
/**
* @param {String} name
* @param {Object} value (depending on the property)
*/
setProperty(name, val) {
this._material.uniforms[name].value = val;
}
/**
* @param {String} name
* @return {Object} value (depending on the property)
*/
getProperty(name) {
return this._material.uniforms[name].value;
}
/**
* @param {String} name
*/
setBlending(blending) {
this._material.blending = blending;
}
/**
* erase this material (calling dispose and clearing texture map)
*/
erase() {
if (this._material) {
if (this._material.map) {
this._material.map.dispose();
}
this._material.dispose();
}
}
}