let computing = false;
let previousStarMesh: BABYLON.Mesh;
let previousStarShape: Bit.Inputs.OCCT.TopoDSShapePointer;
let previousMeshInstances: BABYLON.InstancedMesh[] = [];
type Model = {
nrRays: number,
innerRadius: number,
outerRadius: number,
nrSections: number
}
const model: Model = {
nrRays: 5,
nrSections: 3,
innerRadius: 1,
outerRadius: 3,
}
const start = async () => {
bitbybit.draw.drawGridMesh(new Bit.Inputs.Draw.SceneDrawGridMeshDto())
createGUI();
const dirLight = new Bit.Inputs.BabylonScene.DirectionalLightDto();
dirLight.direction = [-20, -20, -20];
dirLight.shadowGeneratorMapSize = 2056;
dirLight.intensity = 4;
bitbybit.babylon.scene.drawDirectionalLight(dirLight);
createShape(model);
const skyBoxOptions = new Bit.Inputs.BabylonScene.SkyboxDto();
skyBoxOptions.skybox = Bit.Inputs.Base.skyboxEnum.default;
skyBoxOptions.blur = 5;
bitbybit.babylon.scene.enableSkybox(skyBoxOptions);
}
start();
async function createShape(m: Model) {
computing = true;
await disposePrevious();
const shapesToDelete = [];
const star1 = await bitbybit.occt.shapes.wire.createStarWire({
numRays: m.nrRays,
innerRadius: m.innerRadius,
outerRadius: m.outerRadius,
center: [0, 0, 0],
direction: [0, 1, 0],
half: false,
});
const star2 = await bitbybit.occt.shapes.wire.createStarWire({
numRays: m.nrRays,
innerRadius: m.innerRadius,
outerRadius: m.outerRadius,
center: [0, Math.random(), 0],
direction: [0, 1, 0],
half: false,
});
shapesToDelete.push(star1, star2);
const cornerPoints1 = await bitbybit.occt.shapes.edge.getCornerPointsOfEdgesForShape({ shape: star1 });
const cornerPoints2 = await bitbybit.occt.shapes.edge.getCornerPointsOfEdgesForShape({ shape: star2 });
const pts = [];
for (let i = 0; i < cornerPoints1.length; i++) {
if (i % 2 === 0) {
const pt = cornerPoints2[i];
pt[1] += Math.random() * 2;
pts.push(pt);
} else {
const pt = cornerPoints1[i];
pts.push(pt);
}
}
const flower = await bitbybit.occt.shapes.wire.createPolygonWire({
points: pts,
});
shapesToDelete.push(flower);
const flowerFillet = await bitbybit.occt.fillets.fillet3DWire({
shape: flower,
direction: [0, 10, 0],
radius: 360 / m.nrRays / 600,
});
shapesToDelete.push(flowerFillet);
const flowers = [];
for (let r = 1; r <= m.nrSections; r++) {
const scaled = await bitbybit.occt.transforms.scale3d({
shape: flowerFillet,
scale: [1 / r, r % 2 === 0 ? r / m.nrSections * 2 : r / m.nrSections * 1.5, 1 / r],
center: [0, 0, 0],
});
shapesToDelete.push(scaled);
const translated = await bitbybit.occt.transforms.translate({
shape: scaled,
translation: [0, r % 2 === 0 ? r / 4 : r / 3, 0]
});
flowers.push(translated);
shapesToDelete.push(translated);
}
const mirrored = await bitbybit.occt.transforms.mirrorAlongNormalShapes({
shapes: flowers,
normals: flowers.map(() => [0, -1, 0]),
origins: flowers.map(() => [0, 0, 0]),
});
mirrored.reverse().forEach(m => {
flowers.push(m);
shapesToDelete.push(m);
})
const loftOptions = new Bit.Inputs.OCCT.LoftAdvancedDto<Bit.Inputs.OCCT.TopoDSWirePointer>(flowers);
loftOptions.straight = true;
loftOptions.closed = true;
loftOptions.makeSolid = true;
previousStarShape = await bitbybit.occt.operations.loftAdvanced(loftOptions)
const options = new Bit.Inputs.Draw.DrawOcctShapeOptions();
options.precision = 0.01;
options.drawEdges = true;
options.edgeWidth = 0.5;
options.edgeColour = "#f0b89d";
const mat = new BABYLON.PBRMetallicRoughnessMaterial("mat");
mat.roughness = 0.1;
mat.baseColor = new BABYLON.Color3(1, 1, 1);
mat.zOffset = 1;
mat.metallic = 0.9;
options.faceMaterial = mat;
previousStarMesh = await bitbybit.draw.drawAnyAsync({ entity: previousStarShape, options });
await bitbybit.occt.deleteShapes({
shapes: shapesToDelete
})
// previousStarMesh.receiveShadows = true;
const meshes = previousStarMesh.getChildMeshes();
const coord = 60;
const step = 10;
for (let x = -coord; x < coord; x += step) {
for (let z = -coord; z < coord; z += step) {
const randomAngle = Math.random();
meshes.forEach((m: BABYLON.Mesh, index) => {
const inst = m.createInstance(`inst${index}-${x}-${z}`);
inst.rotateAround(new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1, 0), Math.PI * 2 * randomAngle);
inst.scaling = new BABYLON.Vector3(1 + randomAngle / 4, 1 + randomAngle, 1 + randomAngle / 4)
inst.position = new BABYLON.Vector3(x, 0, z);
previousMeshInstances.push(inst);
});
}
}
meshes.forEach(m => {
m.disableEdgesRendering();
m.isVisible = false;
});
previousStarMesh.isVisible = false;
computing = false;
}
async function disposePrevious() {
if (previousStarMesh) {
previousStarMesh.dispose();
}
if (previousStarShape) {
await bitbybit.occt.deleteShape({ shape: previousStarShape });
}
if (previousMeshInstances.length) {
previousMeshInstances.forEach(s => s.dispose());
previousMeshInstances = [];
}
}
async function createGUI() {
var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
var panel = new BABYLON.GUI.StackPanel();
panel.width = "800px";
panel.background = "#00000055";
panel.paddingLeftInPixels = 40;
panel.paddingRightInPixels = 40;
panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
panel.adaptHeightToChildren = true;
advancedTexture.addControl(panel);
var header1 = new BABYLON.GUI.TextBlock("GUI EXAMPLE");
header1.text = "GUI EXAMPLE";
header1.height = "80px";
header1.color = "#f0b89d";
header1.fontSize = "40px"
panel.addControl(header1);
const label1 = "Nr Rays:";
createSliderWithLabel(panel, label1, model.nrRays, 3, 10, 1,
(slider: BABYLON.GUI.Slider, header: BABYLON.GUI.TextBlock) => {
header.text = label1 + " " + slider.value;
model.nrRays = slider.value;
if (!computing) {
createShape(model);
}
}
);
const label2 = "Nr Sections:";
createSliderWithLabel(panel, label2, model.nrSections, 2, 20, 1,
(slider: BABYLON.GUI.Slider, header: BABYLON.GUI.TextBlock) => {
header.text = label2 + " " + slider.value;
model.nrSections = slider.value;
if (!computing) {
createShape(model);
}
}
);
const label3 = "Inner Radius:";
createSliderWithLabel(panel, label3, model.innerRadius, 0.4, 3, 0.1,
(slider: BABYLON.GUI.Slider, header: BABYLON.GUI.TextBlock) => {
if (slider.value > model.outerRadius) {
model.innerRadius = model.outerRadius - 0.1;
slider.value = model.innerRadius;
} else {
model.innerRadius = slider.value;
}
header.text = label3 + " " + slider.value.toFixed(2);
if (!computing) {
createShape(model);
}
}
);
const label4 = "Outer Radius:";
createSliderWithLabel(panel, label4, model.outerRadius, 0.4, 3, 0.1,
(slider: BABYLON.GUI.Slider, header: BABYLON.GUI.TextBlock) => {
if (slider.value < model.innerRadius) {
model.outerRadius = model.innerRadius + 0.1;
slider.value = model.outerRadius;
} else {
model.outerRadius = slider.value;
}
header.text = label4 + " " + slider.value.toFixed(2);
if (!computing) {
createShape(model);
}
}
);
var header2 = new BABYLON.GUI.TextBlock("bitbybit.dev");
header2.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;
header2.text = "bitbybit.dev";
header2.height = "120px";
header2.color = "#f0b89d";
header2.fontSize = "40px";
panel.addControl(header2);
}
function createSliderWithLabel(
panel: BABYLON.GUI.StackPanel,
name: string,
defaultVal: number,
min: number,
max: number,
step: number,
funcToRun: (slider: BABYLON.GUI.Slider, label: BABYLON.GUI.TextBlock) => void
) {
var header = new BABYLON.GUI.TextBlock(name);
header.paddingTopInPixels = 10;
header.text = name + " " + defaultVal;
header.height = "60px";
header.color = "white";
header.fontSize = "30px"
panel.addControl(header);
var slider = new BABYLON.GUI.Slider(name);
slider.thumbColor = "#f0b89d";
slider.isThumbCircle = true;
slider.borderColor = "#f0b89d"
slider.minimum = min;
slider.maximum = max;
slider.step = step;
slider.value = defaultVal;
slider.paddingLeftInPixels = 10;
slider.paddingRightInPixels = 10;
slider.isVertical = false;
slider.alpha = 1;
slider.height = "25px";
slider.onPointerUpObservable.add(() => {
funcToRun(slider, header);
});
panel.addControl(slider);
}