kitchen-simulator
Version:
It is a kitchen simulator (self-contained micro-frontend).
202 lines (198 loc) • 8.96 kB
JavaScript
import * as Three from 'three';
import { BoxGeometry, Group, Mesh, MeshBasicMaterial, MeshStandardMaterial, RepeatWrapping, TextureLoader, Vector2 } from 'three';
import { verticesDistance } from "../../utils/geometry";
import { isElevationView } from "../../utils/helper";
import * as SharedStyle from "../../shared-style";
import { LINE_THICKNESS, UNIT_CENTIMETER } from "../../constants";
import { convert } from "../../utils/convert-units-lite";
import ThreeBSP from "../../utils/threeCSG.es6";
var params = {
envMap: 'HDR',
roughness: 0.1,
metalness: 0.1,
exposure: 0.1
// debug: false
};
var halfPI = Math.PI / 2;
/**
* Apply a texture to a wall face
* @param material: The material of the face
* @param texture: The texture to load
* @param length: The lenght of the face
* @param height: The height of the face
*/
var applyTexture = function applyTexture(material, texture, length, height) {
var loader = new TextureLoader();
if (texture) {
material.map = loader.load(texture.uri["default"]);
material.map.colorSpace = Three.SRGBColorSpace, material.needsUpdate = true;
material.map.wrapS = RepeatWrapping;
material.map.wrapT = RepeatWrapping;
material.map.repeat.set(length * texture.lengthRepeatScale, height * texture.heightRepeatScale);
if (texture.normal) {
material.normalMap = loader.load(texture.normal.uri["default"]);
material.normalScale = new Vector2(texture.normal.normalScaleX, texture.normal.normalScaleY);
material.normalMap.wrapS = RepeatWrapping;
material.normalMap.wrapT = RepeatWrapping;
material.normalMap.repeat.set(length * texture.normal.lengthRepeatScale, height * texture.normal.heightRepeatScale);
}
}
};
export function buildWall(element, layer, scene, textures, mode) {
// Get the two vertices of the wall
var vetName0 = element.vertices.get(0);
var vetName1 = element.vertices.get(1);
// let invert = element.toJS().invert;
// As long as its two ending points is same. This is no longer a line.
if (vetName0 === vetName1) {
return Promise.resolve(null);
}
var wallColor;
layer.lines.forEach(function (data) {
wallColor = data.wallColor;
});
var vertex0 = layer.vertices.get(vetName0);
var vertex1 = layer.vertices.get(vetName1);
// Get height and thickness of the wall converting them into the current scene units
// let height = element.properties.getIn(['height', 'length']);
// let thickness = element.properties.getIn(['thickness', 'length']);
var height = convert(layer.ceilHeight).from(layer.unit).to(UNIT_CENTIMETER);
var thickness = 2.0;
var distance = verticesDistance(vertex0, vertex1);
var soulMaterial = new Three.MeshPhongMaterial({
color: new Three.Color(wallColor).convertLinearToSRGB()
}); //element.selected ? SharedStyle.MESH_SELECTED : 0xD3D3D3
var soulVertices = [];
soulVertices.push(new Three.Vector2(-distance / 2, height / 2));
soulVertices.push(new Three.Vector2(distance / 2, height / 2));
soulVertices.push(new Three.Vector2(distance / 2, -height / 2));
soulVertices.push(new Three.Vector2(-distance / 2, -height / 2));
var soulShape = new Three.Shape(soulVertices);
var soulMesh = new Mesh(new BoxGeometry(distance, height, thickness), soulMaterial);
if (element.userData.stateMode !== 'MODE_DRAWING_HOLE_3D') {
element.holes.forEach(function (holeID) {
var holeData = layer.holes.get(holeID);
if (holeData !== undefined) {
var holeWidth = holeData.properties.getIn(['width', 'length']);
var holeHeight = holeData.properties.getIn(['height', 'length']);
var holeAltitude = holeData.properties.getIn(['altitude', 'length']);
var offset = holeData.offset;
// if (vertex0.x > vertex1.x) offset = 1 - offset;
// if (invert) offset = 1 - offset;
var holeDistance = offset * distance;
var holeVertices = [];
holeVertices.push(new Three.Vector2(0, holeHeight));
holeVertices.push(new Three.Vector2(holeWidth, holeHeight));
holeVertices.push(new Three.Vector2(holeWidth, 0));
holeVertices.push(new Three.Vector2(0, 0));
for (var i = 0; i < holeVertices.length; i++) {
holeVertices[i].x += holeDistance - distance / 2 - holeWidth / 2;
holeVertices[i].y -= height / 2 - holeAltitude;
}
var shapeHole = new Three.Shape(holeVertices);
soulShape.holes.push(shapeHole);
var holeGeometry = new BoxGeometry(holeWidth, holeHeight, thickness);
var holeMesh = new Mesh(holeGeometry);
holeMesh.position.x += holeWidth / 2;
holeMesh.position.y += holeHeight / 2;
holeMesh.position.x += holeDistance - distance / 2 - holeWidth / 2;
holeMesh.position.y -= height / 2 - holeAltitude;
var wallBSP = new ThreeBSP(soulMesh);
var holeBSP = new ThreeBSP(holeMesh);
var wallWithHoleBSP = wallBSP.subtract(holeBSP);
soulMesh = wallWithHoleBSP.toMesh(soulMaterial);
}
});
}
var cAlpha = new Three.Vector2(vertex0.x - vertex1.x, vertex0.y - vertex1.y).angle();
var soulGeometry = new Three.ShapeGeometry(soulShape);
var soul = new Mesh(soulGeometry, soulMaterial);
soul.receiveShadow = true;
soul.castShadow = true;
soul.position.y += height / 2;
soul.rotation.y = cAlpha + Math.PI;
soul.name = 'soulFace';
soulMesh.position.y += height / 2;
soulMesh.rotation.y = cAlpha + Math.PI;
soulMesh.name = 'soul';
soulMesh.castShadow = true;
var frontMaterial = new MeshStandardMaterial({
color: new Three.Color(wallColor).convertLinearToSRGB(),
metalness: 0.1,
roughness: 0.9
// envMap: textureCube,
});
var backMaterial = new MeshStandardMaterial({
color: new Three.Color(wallColor).convertLinearToSRGB(),
metalness: 0.1,
roughness: 0.9
// envMap: textureCube,
});
applyTexture(frontMaterial, textures[element.properties.get('textureB')], distance, height);
applyTexture(backMaterial, textures[element.properties.get('textureB')], distance, height);
var frontFace = soul.clone();
frontFace.material = frontMaterial;
frontFace.name = 'frontFace';
soulMesh.material = frontMaterial;
var merged = new Group();
merged.add(frontFace, soulMesh);
// if this wall is front of camera, show/hide
if (!isElevationView(mode)) {
frontFace.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
var soulMesh = this.parent.getObjectByName('soul');
if (geometry.attributes.normal === undefined) return soulMesh.visible = false;
geometry.computeVertexNormals();
var normals = geometry.attributes.normal.array;
var pos = new Three.Vector4(0, 0, 0, 1);
pos = pos.applyMatrix4(this.matrixWorld);
pos = pos.applyMatrix4(camera.matrixWorldInverse);
var normal = new Three.Vector4(normals[0], normals[1], normals[2], 0);
normal = normal.applyMatrix4(this.matrixWorld);
normal = normal.applyMatrix4(camera.matrixWorldInverse);
if (soulMesh) {
if (pos.dot(normal) >= 0) soulMesh.visible = false;else soulMesh.visible = true;
}
};
}
return Promise.resolve(merged);
}
export function updatedWall(element, layer, scene, textures, mesh, oldElement, differences, selfDestroy, selfBuild) {
var noPerf = function noPerf() {
selfDestroy();
return selfBuild();
};
var soul = mesh.getObjectByName('soul');
var frontFace = mesh.getObjectByName('frontFace');
var backFace = mesh.getObjectByName('backFace');
if (differences[0] == 'selected') {
if (soul !== undefined) {
if (element.selected) {
soul.material = new MeshBasicMaterial({
color: new Three.Color(SharedStyle.MESH_SELECTED).convertLinearToSRGB()
});
} else {
var soulMaterial = frontFace ? frontFace.material : backFace.material;
soul.material = soulMaterial;
}
}
} else if (differences[0] == 'properties') {
if (differences[1] == 'thickness') {
var newThickness = LINE_THICKNESS / 2;
var oldThickness = LINE_THICKNESS / 2;
// let newThickness = element.getIn(['properties', 'thickness', 'length']);
// let oldThickness = oldElement.getIn(['properties', 'thickness', 'length']);
var halfNewThickness = newThickness / 2;
var texturedFaceDistance = halfNewThickness + 1;
var originalThickness = oldThickness / soul.scale.z;
var alpha = soul.rotation.y;
var xTemp = texturedFaceDistance * Math.cos(alpha - halfPI);
var zTemp = texturedFaceDistance * Math.sin(alpha - halfPI);
soul.scale.set(1, 1, newThickness / originalThickness);
frontFace.position.x = soul.position.x + xTemp;
frontFace.position.z = soul.position.z + zTemp;
backFace.position.x = soul.position.x - xTemp;
backFace.position.z = soul.position.z - zTemp;
} else return noPerf();
} else return noPerf();
return Promise.resolve(mesh);
}