forked from mirror/ObjToSchematic
New 'split' button for fast halfing of voxel size
This commit is contained in:
parent
e3fbdf0486
commit
d465004132
@ -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
|
||||
|
||||
|
@ -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
7
resources/svg/split.svg
Normal 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 |
@ -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",
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user