Making A Frame
Using Frame Maker
var frame = frameMaker("frame", options, scene);
| option | value | default value |
|---|---|---|
| path | (Vector3[]) array of Vector3 points forming outer edge of the frame, z must be 0, REQUIRED | |
| profile | (Vector3[]) array of Vector3 points forming the frame profile, z must be 0, REQUIRED |
The profile, or cross section, of the frame has to be a consecutive sequence of points in the XoY plane that give the corners of the profile. The left-most point or points follow the path and form the outer edge of the frame. The following profile is a square with a rebated corner.
import { Vector3 } from "@babylonjs/core/Maths/math.vector";var profilePoints = [ new Vector3(-15, 15, 0), new Vector3(-15, -15, 0), new Vector3(15, -15, 0), new Vector3(15, 10, 0), new Vector3(10, 10, 0), new Vector3(10, 15, 0)];The path defines the outer edge of the frame and is also given as points in the XoY plane. The following example produces a rectangular frame.
import { Vector3 } from "@babylonjs/core/Maths/math.vector";path = [ new Vector3(-150, -100, 0), new Vector3(150, -100, 0), new Vector3(150, 100, 0), new Vector3(-150, 100, 0)];The direction of the path (clockwise or counter-clockwise) determines the orientation of the profile around the frame. If you need to flip the profile, reverse the path array before passing it to frameMaker.
path.reverse();Playground Examples
Window With Rebate Triangular Frame with L Shape Profile Oval FrameCode
import { Vector3 } from "@babylonjs/core/Maths/math.vector";import { Mesh } from "@babylonjs/core/Meshes/mesh";import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";var frameMaker = function (name, options, scene) { var path = options.path; var profile = options.profile; var originX = Number.MAX_VALUE; for (let m = 0; m < profile.length; m++) { originX = Math.min(originX, profile[m].x); } var innerData = []; var outerData = []; var angle = 0; var extrusion = 0; var width = 0; var cornerProfile = []; var nbPoints = path.length; var line = Vector3.Zero(); var nextLine = Vector3.Zero(); path[1].subtractToRef(path[0], line); path[2].subtractToRef(path[1], nextLine); for (let p = 0; p < nbPoints; p++) { angle = Math.PI - Math.acos(Vector3.Dot(line, nextLine) / (line.length() * nextLine.length())); direction = Vector3.Cross(line, nextLine).normalize().z; lineNormal = new Vector3(line.y, -1 * line.x, 0).normalize(); line.normalize(); extrusionLength = line.length(); cornerProfile[(p + 1) % nbPoints] = []; //local profile for (m = 0; m < profile.length; m++) { width = profile[m].x - originX; cornerProfile[(p + 1) % nbPoints].push(path[(p + 1) % nbPoints].subtract(lineNormal.scale(width)).subtract(line.scale(direction * width / Math.tan(angle / 2)))); } line = nextLine.clone(); path[(p + 3) % nbPoints].subtractToRef(path[(p + 2) % nbPoints], nextLine); } var frame = []; var extrusionPaths = []; for (let p = 0; p < nbPoints; p++) { extrusionPaths = []; for (let m = 0; m < profile.length; m++) { extrusionPaths[m] = []; extrusionPaths[m].push(new Vector3(cornerProfile[p][m].x, cornerProfile[p][m].y, profile[m].y)); extrusionPaths[m].push(new Vector3(cornerProfile[(p + 1) % nbPoints][m].x, cornerProfile[(p + 1) % nbPoints][m].y, profile[m].y)); } frame[p] = MeshBuilder.CreateRibbon("frameLeft", { pathArray: extrusionPaths, sideOrientation: Mesh.DOUBLESIDE, updatable: true, closeArray: true }, scene); } return Mesh.MergeMeshes(frame, true).convertToFlatShadedMesh();};