Skip to content

Commit 66b2fa5

Browse files
committed
Update 4.8.0
1 parent daf33b5 commit 66b2fa5

File tree

19 files changed

+1079
-366
lines changed

19 files changed

+1079
-366
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
### **Voxel-based 3D Modeling Application**
66
**Model . Render . Export**<br>
7-
This application is suitable for rapid prototyping, speed modeling, creating small assets in large numbers, loading and saving MagicaVoxel VOX format, or simply playing around and learning 3D modeling.
87

98
[https://nimadez.github.io/voxel-builder/](https://nimadez.github.io/voxel-builder/)
109

@@ -30,7 +29,7 @@ This application is suitable for rapid prototyping, speed modeling, creating sma
3029
- Interactive modeling toolsets
3130
- Symmetric drawing and painting
3231
- Voxel transforms and manipulation
33-
- Color groups and visibility options
32+
- Color groups and layering options
3433

3534
**Rendering**
3635
- Three.js Sandbox
@@ -129,7 +128,7 @@ Also, the FPS depends on many factors, such as the material (CEL is faster) and
129128
## FAQ
130129

131130
#### Why isn't there a layering feature and a layer list?
132-
> There is, you can have 16,777,216 layers (groups or color groups), because the layering system in this app is determined by colors, even a change in the brightness of a color creates a new group that can contain hundreds of voxels.<br>
131+
> You can have 16,777,216 layers (color groups), the layering system in this app is determined by colors, even a change in the brightness of a color creates a new group that can contain hundreds of voxels.<br>
133132
> So groups are automatically created, merged, or deleted based on color. You can even hide, delete, select, paint, transform, or duplicate color groups.
134133
135134
#### Why can't I freely transform 3D objects like in other 3D software?
@@ -142,10 +141,10 @@ Also, the FPS depends on many factors, such as the material (CEL is faster) and
142141
> GLB has a special use in this application, you can save and retrieve voxel data using baked meshes, exporting raw voxels to GLB leads to interference and errors when loading it using the "Load Bakes" option.
143142
144143
#### What are the methods for saving and loading voxel data?
145-
> -- **Save to JSON** *(primary, human-readable, fastest)*<br>
146-
> -- **Export baked meshes to GLB** *(and 'Load Bakes', supports Blender and other 3D apps, slower)*<br>
144+
> -- **Save to JSON** *(includes scene configs, human-readable, fastest)*<br>
145+
> -- **Export baked meshes to GLB** *(uses 'Load Bakes', supports Blender and other 3D software, slower)*<br>
147146
> -- **Save snapshots to ZIP archive** *(easy to share, browser storage limits, speed is variable)*<br>
148-
> -- **Save to VOX format** *(supported by many 3D apps and engines, very fast)*
147+
> -- **Save to VOX format** *(supports MagicaVoxel, very fast)*
149148
150149
#### How to merge vertices after export to GLB?
151150
> 1- Open exported GLB file in Blender<br>
@@ -167,9 +166,12 @@ git log -2 (copy the hash of the previous commit)
167166
git reset --hard $HASH
168167
```
169168

169+
#### Will WebGPU be supported?
170+
> It was supported to some extent before, but was removed due to unnecessary complexity. But once it matures enough to be enabled by default in browsers, this upgrade will be possible with a few simple changes.
171+
170172
## History
171173
```
172-
↑ Advancing to the Renaissance Bubble
174+
↑ Advancing in the Renaissance Bubble
173175
↑ A fundamental overhaul of the core
174176
↑ Core initialization!
175177
↑ Rendering was left to Three and three-gpu-pathtracer

media/screenshot.png

-6.72 KB
Loading

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "voxel-builder",
3-
"version": "4.7.9",
3+
"version": "4.8.0",
44
"description": "Voxel-based 3D modeling application",
55
"main": "electron.js",
66
"scripts": {
@@ -12,9 +12,9 @@
1212
"devDependencies": {
1313
"electron": "^38.0.0",
1414
"babylonjs": "8.50.0",
15-
"three": "0.182.0",
15+
"three": "0.183.0",
1616
"three-mesh-bvh": "0.9.7",
17-
"three-gpu-pathtracer": "0.0.23",
17+
"three-gpu-pathtracer": "0.0.24",
1818
"@tweenjs/tween.js": "25.0.0",
1919
"reinvented-color-wheel": "0.4.0",
2020
"jszip": "3.10.1"

server.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,13 @@ const PORT = 8011;
1212

1313
let filePath = undefined;
1414
const mimeTypes = {
15-
'txt': 'text/plain',
1615
'html': 'text/html',
17-
'xml': 'application/xml',
1816
'js': 'text/javascript',
19-
'py': 'text/x-python',
20-
'css': 'text/css',
2117
'json': 'application/json',
2218
'png': 'image/png',
2319
'jpg': 'image/jpg',
24-
'jpeg': 'image/jpeg',
2520
'svg': 'image/svg+xml',
26-
'gif': 'image/gif',
27-
'ico': 'image/x-icon',
2821
'ttf': 'font/ttf',
29-
'woff': 'font/woff',
3022
'woff2': 'font/woff2'
3123
};
3224

src/index.html

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@
304304
<li class="category">ABOUT</li>
305305
<li class="about">
306306
<div><span style="color: orange">V</span>OXEL BUILDER</div>
307-
&#8627; 4.7.9 BETA
307+
&#8627; 4.8.0 BETA
308308
<br>&#8627; <a href="https://github.com/nimadez/voxel-builder/" target="_blank">GitHub</a>
309309
<br>&#8627; <a href="https://github.com/nimadez/voxel-builder/releases" target="_blank">Changelog</a>
310310
<br>DEVELOPER
@@ -353,6 +353,7 @@
353353
<li title="Less battery drain (&#60;100 ms startup)"><input type="checkbox" id="pref_minimal"> <label for="pref_minimal">Minimal UIX</label></li>
354354
<li title="Enabled in self-hosted desktop mode"><input type="checkbox" id="pref_user_startup"> <label for="pref_user_startup">User Startup</label></li>
355355
<li class="spacer"></li>
356+
<li title="Rendering is also affected" class="row_input"><label>Max FPS</label> <input type="number" id="pref_fps_max" class="ignorekeys" value="60" min="30" max="120" step="1"></li>
356357
<li class="row_input"><label>Start Box</label> <input type="number" id="pref_startbox_size" class="ignorekeys" value="20" min="1" max="40" step="1"></li>
357358
<li class="row_input"><label>Palette</label> <input type="number" id="pref_palette_size" class="ignorekeys" value="1" min="1" max="20" step="1"></li>
358359
<li class="row_input" title="Maximum 100 Storages"><label>Snapshot</label> <input type="number" id="pref_snapshot_num" class="ignorekeys" value="6" min="1" max="100" step="1"></li>
@@ -365,7 +366,7 @@
365366
<li class="row_input"><label>UI Opacity</label> <input type="range" id="pref_ui_opacity" class="ignorekeys" value="0.8" min="0.6" max="0.9" step="0.05"></li>
366367
<li class="category">SCENE</li>
367368
<li class="row_color"><label for="pref_background_check">BG</label> <input type="color" id="pref_background_color" value="#151515"> <input type="checkbox" id="pref_background_check" style="width: 57px;"></li>
368-
<li class="row_color" title="General shade color is widely distributed throughout the app."><label>Shade</label><input type="color" id="pref_render_shade" value="#90A0B3"><button style="width: 52px; height: 20px;" title="Reset" onclick="this.previousElementSibling.value = '#90A0B3'; this.previousElementSibling.dispatchEvent(new Event('input', { bubbles: true }));">R</button></li>
369+
<li class="row_color" title="General shade color is widely distributed throughout the app"><label>Shade</label><input type="color" id="pref_render_shade" value="#90A0B3"><button style="width: 52px; height: 20px;" title="Reset" onclick="this.previousElementSibling.value = '#90A0B3'; this.previousElementSibling.dispatchEvent(new Event('input', { bubbles: true }));">R</button></li>
369370
<li><input type="checkbox" id="pref_scene_pointcloud"> <label for="pref_scene_pointcloud">Point Cloud</label></li>
370371
<li class="category">RENDER</li>
371372
<li class="row">
@@ -513,7 +514,7 @@
513514

514515
<ul class="menu panel" id="menu-voxelize">
515516
<li class="category">MODELS</li>
516-
<li class="row"><label style="margin-right: 10px">Scale</label><input type="number" class="ignorekeys" id="input-voxelizer-scale" value="50" min="1"></li>
517+
<li class="row"><label style="margin-right: 10px">Scale</label><input type="number" class="ignorekeys" id="input-voxelizer-scale" value="50" min="1" step="1"></li>
517518
<li class="spacer"></li>
518519
<li><button onclick="document.getElementById('openfile_voxelizer').click()">Upload Model</button></li>
519520
<li><label class="help">? GLB | OBJ | STL | PLY</label></li>
@@ -538,9 +539,9 @@
538539
<ul class="menu panel" id="menu-create">
539540
<li class="category">BOX</li>
540541
<li>
541-
<div class="row">&nbsp;<label style="margin-right: 4px">X</label>&nbsp;<input id="create_grid_x" type="number" class="ignorekeys" value="20" min="1"></div>
542-
<div class="row">&nbsp;<label style="margin-right: 4px">Y</label>&nbsp;<input id="create_grid_y" type="number" class="ignorekeys" value="20" min="1"></div>
543-
<div class="row">&nbsp;<label class="Z">Z</label>&nbsp;<input id="create_grid_z" type="number" class="ignorekeys" value="20" min="1"></div>
542+
<div class="row">&nbsp;<label style="margin-right: 4px">X</label>&nbsp;<input id="create_grid_x" type="number" class="ignorekeys" value="20" min="1" step="1"></div>
543+
<div class="row">&nbsp;<label style="margin-right: 4px">Y</label>&nbsp;<input id="create_grid_y" type="number" class="ignorekeys" value="20" min="1" step="1"></div>
544+
<div class="row">&nbsp;<label class="Z">Z</label>&nbsp;<input id="create_grid_z" type="number" class="ignorekeys" value="20" min="1" step="1"></div>
544545
<div class="spacer"></div>
545546
<input type="checkbox" id="create_grid_fill" checked> <label for="create_grid_fill">Fill Box</label><br>
546547
<div class="spacer"></div>
@@ -552,18 +553,18 @@
552553
</li>
553554
<li class="category">SPHERE</li>
554555
<li>
555-
<div class="row">&nbsp;<label style="margin-right: 6px">Outer</label>&nbsp;<input id="create_sphere_outer" type="number" class="ignorekeys" value="20" min="3"></div>
556-
<div class="row">&nbsp;<label style="margin-right: 8px">Inner</label>&nbsp;<input id="create_sphere_inner" type="number" class="ignorekeys" value="10" min="0"></div>
556+
<div class="row">&nbsp;<label style="margin-right: 6px">Outer</label>&nbsp;<input id="create_sphere_outer" type="number" class="ignorekeys" value="20" min="3" step="1"></div>
557+
<div class="row">&nbsp;<label style="margin-right: 8px">Inner</label>&nbsp;<input id="create_sphere_inner" type="number" class="ignorekeys" value="10" min="0" step="1"></div>
557558
<div class="spacer"></div>
558559
<div title="Adds inner voxels and paints them using the selected color"><input type="checkbox" id="create_sphere_inner_color" checked> <label for="create_sphere_inner_color">Colored Inner</label></div>
559560
<div class="spacer"></div>
560561
<button id="btn_action_create_sphere">Sphere</button>
561562
</li>
562563
<li class="category">TERRAIN</li>
563564
<li>
564-
<div class="row">&nbsp;<label style="margin-right: 4px">X</label>&nbsp;<input id="create_terrain_x" type="number" class="ignorekeys" value="100" min="3"></div>
565-
<div class="row">&nbsp;<label style="margin-right: 4px">Y</label>&nbsp;<input id="create_terrain_y" type="number" class="ignorekeys" value="5" min="1"></div>
566-
<div class="row">&nbsp;<label class="Z">Z</label>&nbsp;<input id="create_terrain_z" type="number" class="ignorekeys" value="100" min="3"></div>
565+
<div class="row">&nbsp;<label style="margin-right: 4px">X</label>&nbsp;<input id="create_terrain_x" type="number" class="ignorekeys" value="100" min="3" step="1"></div>
566+
<div class="row">&nbsp;<label style="margin-right: 4px">Y</label>&nbsp;<input id="create_terrain_y" type="number" class="ignorekeys" value="5" min="1" step="1"></div>
567+
<div class="row">&nbsp;<label class="Z">Z</label>&nbsp;<input id="create_terrain_z" type="number" class="ignorekeys" value="100" min="3" step="1"></div>
567568
<div class="spacer"></div>
568569
<input type="checkbox" id="create_terrain_grad" checked> <label for="create_terrain_grad">Height Gradient</label><br>
569570
<div class="spacer"></div>
@@ -919,8 +920,10 @@
919920

920921
float amb = 1.0;
921922
float dif = max(dot(N, L), 0.0);
923+
if (dot(N, L) < 0.0)
924+
dif = 0.5 * min(dot(N, -L), 1.0);
922925

923-
float NdotV = max(dot(N, V), 0.0);
926+
float NdotV = max(dot(N, V), 1.0);
924927
float ao = pow(NdotV, 0.5);
925928
float curvature = abs(NdotV);
926929
ao = mix(ao, 0.5, curvature * 0.5);
@@ -982,7 +985,7 @@
982985
vec3 sb = sobel(textureSampler, vUV);
983986
float mx = max(max(sb.r, sb.g), sb.b);
984987
float aa = smoothstep(1.0, 0.0, mx);
985-
float edge = step(mx, 0.5);
988+
float edge = step(mx, 1.0);
986989

987990
vec3 col = texture2D(textureSampler, vUV).rgb;
988991
col = mix(col, col * edge * aa, 1.0);

src/libs/addons/GLTFExporter.js

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,12 +1852,12 @@ class GLTFWriter {
18521852
! ( array instanceof Uint8Array ) ) {
18531853

18541854
console.warn( 'GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.' );
1855-
modifiedAttribute = new BufferAttribute( new Uint16Array( array ), attribute.itemSize, attribute.normalized );
1855+
modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute( attribute, Uint16Array );
18561856

18571857
} else if ( ( array instanceof Uint32Array || array instanceof Int32Array ) && ! attributeName.startsWith( '_' ) ) {
18581858

18591859
console.warn( `GLTFExporter: Attribute "${ attributeName }" converted to type FLOAT.` );
1860-
modifiedAttribute = GLTFExporter.Utils.toFloat32BufferAttribute( attribute );
1860+
modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute( attribute, Float32Array );
18611861

18621862
}
18631863

@@ -2355,6 +2355,13 @@ class GLTFWriter {
23552355

23562356
if ( ! json.nodes ) json.nodes = [];
23572357

2358+
// Handle pivot by creating a container node
2359+
if ( object.pivot !== null ) {
2360+
2361+
return await this._processNodeWithPivotAsync( object );
2362+
2363+
}
2364+
23582365
const nodeDef = {};
23592366

23602367
if ( options.trs ) {
@@ -2451,6 +2458,126 @@ class GLTFWriter {
24512458

24522459
}
24532460

2461+
/**
2462+
* Process Object3D node with pivot using container approach
2463+
* @param {THREE.Object3D} object Object3D with pivot
2464+
* @return {Promise<number>} Index of the container node
2465+
*/
2466+
async _processNodeWithPivotAsync( object ) {
2467+
2468+
const json = this.json;
2469+
const options = this.options;
2470+
const nodeMap = this.nodeMap;
2471+
2472+
const pivot = object.pivot;
2473+
2474+
// Container node: holds position + pivot offset, rotation, scale
2475+
// Animations will target this node
2476+
const containerDef = {};
2477+
2478+
const rotation = object.quaternion.toArray();
2479+
const position = [
2480+
object.position.x + pivot.x,
2481+
object.position.y + pivot.y,
2482+
object.position.z + pivot.z
2483+
];
2484+
const scale = object.scale.toArray();
2485+
2486+
if ( ! equalArray( rotation, [ 0, 0, 0, 1 ] ) ) {
2487+
2488+
containerDef.rotation = rotation;
2489+
2490+
}
2491+
2492+
if ( ! equalArray( position, [ 0, 0, 0 ] ) ) {
2493+
2494+
containerDef.translation = position;
2495+
2496+
}
2497+
2498+
if ( ! equalArray( scale, [ 1, 1, 1 ] ) ) {
2499+
2500+
containerDef.scale = scale;
2501+
2502+
}
2503+
2504+
// Store pivot in extras for round-trip reconstruction
2505+
containerDef.extras = { pivot: pivot.toArray() };
2506+
2507+
if ( object.name !== '' ) containerDef.name = String( object.name );
2508+
2509+
this.serializeUserData( object, containerDef );
2510+
2511+
const containerIndex = json.nodes.push( containerDef ) - 1;
2512+
2513+
// Map original object to container so animations target it
2514+
nodeMap.set( object, containerIndex );
2515+
2516+
// Child node: holds mesh with -pivot offset
2517+
const childDef = {};
2518+
2519+
const childPosition = [ - pivot.x, - pivot.y, - pivot.z ];
2520+
2521+
if ( ! equalArray( childPosition, [ 0, 0, 0 ] ) ) {
2522+
2523+
childDef.translation = childPosition;
2524+
2525+
}
2526+
2527+
if ( object.isMesh || object.isLine || object.isPoints ) {
2528+
2529+
const meshIndex = await this.processMeshAsync( object );
2530+
2531+
if ( meshIndex !== null ) childDef.mesh = meshIndex;
2532+
2533+
} else if ( object.isCamera ) {
2534+
2535+
childDef.camera = this.processCamera( object );
2536+
2537+
}
2538+
2539+
if ( object.isSkinnedMesh ) this.skins.push( object );
2540+
2541+
const childIndex = json.nodes.push( childDef ) - 1;
2542+
2543+
// Build children array for container
2544+
const containerChildren = [ childIndex ];
2545+
2546+
// Process object's children as children of the child node
2547+
if ( object.children.length > 0 ) {
2548+
2549+
const grandchildren = [];
2550+
2551+
for ( let i = 0, l = object.children.length; i < l; i ++ ) {
2552+
2553+
const child = object.children[ i ];
2554+
2555+
if ( child.visible || options.onlyVisible === false ) {
2556+
2557+
const childNodeIndex = await this.processNodeAsync( child );
2558+
2559+
if ( childNodeIndex !== null ) grandchildren.push( childNodeIndex );
2560+
2561+
}
2562+
2563+
}
2564+
2565+
if ( grandchildren.length > 0 ) childDef.children = grandchildren;
2566+
2567+
}
2568+
2569+
containerDef.children = containerChildren;
2570+
2571+
await this._invokeAllAsync( function ( ext ) {
2572+
2573+
ext.writeNode && ext.writeNode( object, containerDef );
2574+
2575+
} );
2576+
2577+
return containerIndex;
2578+
2579+
}
2580+
24542581
/**
24552582
* Process Scene
24562583
* @param {Scene} scene Scene to process
@@ -3538,9 +3665,9 @@ GLTFExporter.Utils = {
35383665

35393666
},
35403667

3541-
toFloat32BufferAttribute: function ( srcAttribute ) {
3668+
toTypedBufferAttribute: function ( srcAttribute, TypedArray ) {
35423669

3543-
const dstAttribute = new BufferAttribute( new Float32Array( srcAttribute.count * srcAttribute.itemSize ), srcAttribute.itemSize, false );
3670+
const dstAttribute = new BufferAttribute( new TypedArray( srcAttribute.count * srcAttribute.itemSize ), srcAttribute.itemSize, false );
35443671

35453672
if ( ! srcAttribute.normalized && ! srcAttribute.isInterleavedBufferAttribute ) {
35463673

0 commit comments

Comments
 (0)