New 'split' button for fast halfing of voxel size

This commit is contained in:
Lucas Dower 2021-07-10 22:52:23 +01:00
parent e3fbdf0486
commit d465004132
6 changed files with 90 additions and 18 deletions

View File

@ -24,17 +24,18 @@ A tool to convert .obj files into Minecraft Schematics
* ✔️ **Export to schematic**
0.3
* Export to litematic
* ✔️ ** Faster voxel splitting **
* Multithreading
* Quality of life
* Model centreing, scaling, voxel size preview, progress bar, limit warnings
0.4
* Export to litematic
* .mtl support for block choice
* Building guides
* Slice viewer
0.5
* Building guides
* Slice viewer
* .fbx support
* Block painting

View File

@ -26,6 +26,14 @@
<div class="input-group">
<label class="input-group-text ">Voxel size</label>
<input id="voxelInput" type="number" min="0.1" step="0.1" value="0.1" class="form-control border-0" disabled>
<button id="splitBtn" class="btn btn-primary border-0" type="button" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Half voxel size (faster)" disabled>
<img src="./resources/svg/split.svg" alt="">
</button>
<!--
<button id="joinBtn" class="btn btn-primary border-0" type="button" disabled>
<img src="./resources/svg/join.svg" alt="">
</button>
-->
<button id="voxelBtn" class="btn btn-primary border-0" type="button" disabled>
<img src="./resources/svg/voxel.svg" alt="">
Voxelise

7
resources/svg/split.svg Normal file
View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-split-2" width="22" height="22" viewBox="0 0 24 28" stroke-width="1.5" stroke="#ffffff" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M21 17h-5.397a5 5 0 0 1 -4.096 -2.133l-.514 -.734a5 5 0 0 0 -4.096 -2.133h-3.897" />
<path d="M21 7h-5.395a5 5 0 0 0 -4.098 2.135l-.51 .73a5 5 0 0 1 -4.097 2.135h-3.9" />
<path d="M18 10l3 -3l-3 -3" />
<path d="M18 20l3 -3l-3 -3" />
</svg>

After

Width:  |  Height:  |  Size: 541 B

View File

@ -53,6 +53,8 @@ $("#loadBtn").on("click", () => {
$('#voxelInput').prop('disabled', false);
$('#voxelBtn').prop('disabled', false);
$('#splitBtn').prop('disabled', true);
$('#exportBtn').prop('disabled', true);
showToastWithText(`Successfully load ${file.name}`, 'success');
});
@ -76,7 +78,7 @@ $("#voxelBtn").on("click", () => {
voxelManager.voxeliseMesh(loadedMesh);
renderer.clear();
renderer.registerVoxelMesh(voxelManager);
renderer.registerVoxelMesh(voxelManager, true);
/*
const mesh = voxelManager.buildMesh();
@ -101,9 +103,10 @@ $("#voxelBtn").on("click", () => {
}
*/
$('#exportBtn').prop('disabled', false);
$('#splitBtn').prop('disabled', false);
const height = (voxelManager.maxY - voxelManager.minY) / voxelSize;
console.log(height);
//console.log(height);
if (height >= 256) {
showToastWithText("Schematic won't fit in world", 'warning');
} else if (height >= 193) {
@ -116,8 +119,28 @@ $("#voxelBtn").on("click", () => {
});
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
$("#splitBtn").on("click", () => {
const voxelSize = $("#voxelInput").prop('value');
$("#voxelInput").prop('value', voxelSize / 2);
voxelManager.splitVoxels();
renderer.clear();
renderer.setVoxelSize(voxelSize / 2);
renderer.registerVoxelMesh(voxelManager, true);
renderer.compileRegister();
});
// EXPORT SCHEMATIC
document.querySelector("#exportBtn").addEventListener('click', async function() {
$("#exportBtn").on("click", async () => {
const {filePath} = await dialog.showSaveDialog({
title: "Save schematic",

View File

@ -289,11 +289,17 @@ class Renderer {
}
}
registerVoxelMesh(voxelManager) {
registerVoxelMesh(voxelManager, useMeshing) {
if (useMeshing) {
const mesh = voxelManager.buildMesh();
for (const box of mesh) {
this.registerBox(box.centre, box.size, false);
}
} else {
for (const voxel of voxelManager.voxels) {
this.registerVoxel(voxel, false);
}
}
}
registerTriangle(triangle, debug) {

View File

@ -1,12 +1,13 @@
const { AABB, CubeAABB } = require("./aabb.js");
const { Vector3 } = require("./vector.js");
const { HashSet } = require('./hash_map.js');
const { HashSet, HashMap } = require('./hash_map.js');
class VoxelManager {
constructor(voxelSize) {
this._voxelSize = voxelSize;
this.voxels = [];
this.triangleAABBs = [];
this.failedAABBs = [];
this.minX = Infinity; // JavaScript crack
@ -22,7 +23,7 @@ class VoxelManager {
this._voxelSize = voxelSize;
}
clear() {
_clearVoxels() {
this.voxels = [];
this.failedAABBs = [];
@ -32,9 +33,15 @@ class VoxelManager {
this.maxX = -Infinity;
this.maxY = -Infinity;
this.maxZ = -Infinity;
this.voxelsHash = new HashSet(2048);
}
clear() {
this.triangleAABBs = [];
this._clearVoxels();
}
_getTriangleCubeAABB(triangle) {
let gridSnappedCentre = Vector3.divScalar(triangle.aabb.centre, this._voxelSize);
gridSnappedCentre = Vector3.round(gridSnappedCentre);
@ -197,11 +204,32 @@ class VoxelManager {
return this.mesh;
}
splitVoxels() {
this._voxelSize /= 2;
this._clearVoxels();
const newTriangleAABBs = [];
for (const {triangle, AABBs} of this.triangleAABBs) {
const triangleAABBs = [];
for (const AABB of AABBs) {
for (const sub of AABB.subdivide()) {
if (triangle.intersectAABB(sub)) {
this.addVoxel(sub.centre);
triangleAABBs.push(sub);
}
}
}
newTriangleAABBs.push({triangle: triangle, AABBs: triangleAABBs});
}
this.triangleAABBs = newTriangleAABBs;
}
voxeliseTriangle(triangle) {
const cubeAABB = this._getTriangleCubeAABB(triangle);
//renderer.setStroke(new Vector3(1.0, 1.0, 1.0));
//let voxels = [];
const triangleAABBs = [];
let queue = [cubeAABB];
while (queue.length > 0) {
@ -212,16 +240,15 @@ class VoxelManager {
queue.push(...aabb.subdivide());
} else {
// We've reached the voxel level, stop
//renderer.registerBox(aabb.centre, aabb.size);
//this.voxels.push(aabb.centre);
this.addVoxel(aabb.centre);
triangleAABBs.push(aabb);
}
} else {
this.failedAABBs.push(aabb);
}
}
//return voxels;
this.triangleAABBs.push({triangle: triangle, AABBs: triangleAABBs});
}
voxeliseMesh(mesh) {