MySafeCode commited on
Commit
9ba4a16
·
verified ·
1 Parent(s): 40de165

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +100 -47
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Fixed VOX Color Viewer</title>
7
  <style>
8
  body {
9
  margin: 0;
@@ -24,7 +24,7 @@
24
  background: rgba(0,0,0,0.8);
25
  padding: 15px;
26
  border-radius: 8px;
27
- max-width: 380px;
28
  }
29
  #controls h3 {
30
  margin-top: 0;
@@ -35,7 +35,7 @@
35
  }
36
  label {
37
  display: inline-block;
38
- width: 140px;
39
  font-size: 12px;
40
  }
41
  input[type="file"] {
@@ -121,7 +121,7 @@
121
  <div id="container"></div>
122
 
123
  <div id="controls">
124
- <h3>VOX & GLB Viewer</h3>
125
 
126
  <div class="control-group">
127
  <button class="btn" onclick="document.getElementById('glbFileInput').click()">Load GLB/GLTF</button>
@@ -155,6 +155,12 @@
155
  <span id="ballSegmentsValue">8</span>
156
  </div>
157
 
 
 
 
 
 
 
158
  <div class="rotation-controls">
159
  <div class="control-group">
160
  <label>Rotation Center:</label>
@@ -188,14 +194,14 @@
188
  </div>
189
 
190
  <div id="loading">Loading...</div>
191
- <div id="info">Click and drag to rotate • Scroll to zoom • Switch between balls and boxes for VOX!</div>
192
 
193
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
194
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
195
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
196
 
197
  <script>
198
- // Fixed VOX parser with correct color handling
199
  class VOXParser {
200
  static parse(buffer) {
201
  const view = new DataView(buffer);
@@ -250,7 +256,7 @@
250
  return chunks;
251
  }
252
 
253
- static createInstancedGeometry(voxData, renderMode = 'box', voxelSize = 0.8, ballSegments = 8) {
254
  if (!voxData.voxels || !voxData.size) return null;
255
 
256
  const voxels = voxData.voxels;
@@ -264,50 +270,80 @@
264
  baseGeometry = new THREE.BoxGeometry(voxelSize, voxelSize, voxelSize);
265
  }
266
 
267
- // Create instanced mesh for performance - use a material that supports vertex colors
268
- const instancedMesh = new THREE.InstancedMesh(
269
- baseGeometry,
270
- new THREE.MeshPhongMaterial({
271
- vertexColors: true,
 
 
 
 
 
 
 
 
272
  shininess: 30
273
- }),
274
- voxels.length
275
- );
 
276
 
277
- // Set up instance data
278
- const dummy = new THREE.Object3D();
279
- const color = new THREE.Color();
280
 
281
  // Calculate offsets to center the model
282
  const offsetX = voxData.size.x / 2;
283
  const offsetY = voxData.size.y / 2;
284
  const offsetZ = voxData.size.z / 2;
285
 
 
286
  for (let i = 0; i < voxels.length; i++) {
287
  const voxel = voxels[i];
 
288
 
289
- // Position
290
- dummy.position.set(
291
- voxel.x - offsetX,
292
- voxel.y - offsetY,
293
- voxel.z - offsetZ
294
- );
295
- dummy.updateMatrix();
296
- instancedMesh.setMatrixAt(i, dummy.matrix);
297
-
298
- // Color - fix the color index mapping
299
- const colorIndex = voxel.colorIndex - 1; // VOX color indices start at 1
300
  if (colorIndex >= 0 && colorIndex < palette.length) {
301
- const colorData = palette[colorIndex];
302
- color.setRGB(colorData.r / 255, colorData.g / 255, colorData.b / 255);
303
- instancedMesh.setColorAt(i, color);
 
 
 
 
 
 
 
 
304
  }
305
  }
306
 
307
- instancedMesh.castShadow = true;
308
- instancedMesh.receiveShadow = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
 
310
- return instancedMesh;
311
  }
312
 
313
  static generateDefaultPalette() {
@@ -349,10 +385,10 @@
349
  const defaultCameraLookAt = new THREE.Vector3(0, 0, 0);
350
 
351
  // Lighting setup - make it brighter for better color visibility
352
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
353
  scene.add(ambientLight);
354
 
355
- const directionalLight = new THREE.DirectionalLight(0xffffff, 0.9);
356
  directionalLight.position.set(10, 10, 5);
357
  directionalLight.castShadow = true;
358
  directionalLight.shadow.mapSize.width = 2048;
@@ -365,6 +401,7 @@
365
  let currentFileType = 'none'; // 'none', 'glb', 'vox'
366
  let autoRotateEnabled = true;
367
  let currentRenderMode = 'box';
 
368
  let modelCenter = new THREE.Vector3(0, 0, 0); // Store model center for rotation
369
 
370
  // File input handlers
@@ -419,15 +456,16 @@
419
  voxData.size.z / 2 - voxData.size.z / 2
420
  );
421
 
422
- const instancedMesh = VOXParser.createInstancedGeometry(
423
  voxData,
424
  currentRenderMode,
425
  parseFloat(document.getElementById('voxelSize').value),
426
- parseInt(document.getElementById('ballSegments').value)
 
427
  );
428
 
429
- if (instancedMesh) {
430
- loadModel(instancedMesh, 'vox');
431
  showVOXControls(true);
432
  updateModelInfo(`VOX: ${file.name} (${voxData.voxels.length} voxels)`, 'vox');
433
  }
@@ -477,10 +515,12 @@
477
  const voxControls = document.getElementById('voxControls');
478
  const voxelSizeControl = document.getElementById('voxelSizeControl');
479
  const ballSegmentsControl = document.getElementById('ballSegmentsControl');
 
480
 
481
  voxControls.style.display = show ? 'block' : 'none';
482
  voxelSizeControl.style.display = show ? 'block' : 'none';
483
  ballSegmentsControl.style.display = show && currentRenderMode === 'ball' ? 'block' : 'none';
 
484
  }
485
 
486
  function setRenderMode(mode) {
@@ -496,15 +536,16 @@
496
 
497
  // Rebuild geometry if we have VOX data
498
  if (currentVOXData && currentFileType === 'vox') {
499
- const instancedMesh = VOXParser.createInstancedGeometry(
500
  currentVOXData,
501
  mode,
502
  parseFloat(document.getElementById('voxelSize').value),
503
- parseInt(document.getElementById('ballSegments').value)
 
504
  );
505
 
506
- if (instancedMesh) {
507
- loadModel(instancedMesh, 'vox');
508
  }
509
  }
510
  }
@@ -527,6 +568,16 @@
527
  }
528
  }
529
 
 
 
 
 
 
 
 
 
 
 
530
  function centerRotationOnModel() {
531
  if (!currentModel) return;
532
 
@@ -605,6 +656,7 @@
605
 
606
  document.getElementById('voxelSize').addEventListener('input', updateVoxelSize);
607
  document.getElementById('ballSegments').addEventListener('input', updateBallSegments);
 
608
 
609
  // Animation loop
610
  function animate() {
@@ -622,16 +674,17 @@
622
  // Handle window resize
623
  window.addEventListener('resize', () => {
624
  camera.aspect = window.innerWidth / window.innerHeight;
625
- camera.updateProjectionMatrix;
626
  renderer.setSize(window.innerWidth, window.innerHeight);
627
  });
628
 
629
  // Initialize
630
  updateVoxelSize();
631
  updateBallSegments();
 
632
  updateModelInfo('Ready to load models', 'none');
633
 
634
  animate();
635
  </script>
636
  </body>
637
- </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>VOX Color Fix - Amplified Viewer</title>
7
  <style>
8
  body {
9
  margin: 0;
 
24
  background: rgba(0,0,0,0.8);
25
  padding: 15px;
26
  border-radius: 8px;
27
+ max-width: 400px;
28
  }
29
  #controls h3 {
30
  margin-top: 0;
 
35
  }
36
  label {
37
  display: inline-block;
38
+ width: 160px;
39
  font-size: 12px;
40
  }
41
  input[type="file"] {
 
121
  <div id="container"></div>
122
 
123
  <div id="controls">
124
+ <h3>VOX Color Amplifier</h3>
125
 
126
  <div class="control-group">
127
  <button class="btn" onclick="document.getElementById('glbFileInput').click()">Load GLB/GLTF</button>
 
155
  <span id="ballSegmentsValue">8</span>
156
  </div>
157
 
158
+ <div class="control-group" id="colorAmplifyControl" style="display: none;">
159
+ <label>Color Amplify:</label>
160
+ <input type="range" id="colorAmplify" min="0.1" max="50" step="0.1" value="1.0">
161
+ <span id="colorAmplifyValue">1.0</span>x
162
+ </div>
163
+
164
  <div class="rotation-controls">
165
  <div class="control-group">
166
  <label>Rotation Center:</label>
 
194
  </div>
195
 
196
  <div id="loading">Loading...</div>
197
+ <div id="info">Click and drag to rotate • Scroll to zoom • Use color amplifier for VOX files!</div>
198
 
199
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
200
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
201
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
202
 
203
  <script>
204
+ // Fixed VOX parser with proper color handling and amplification
205
  class VOXParser {
206
  static parse(buffer) {
207
  const view = new DataView(buffer);
 
256
  return chunks;
257
  }
258
 
259
+ static createInstancedGeometry(voxData, renderMode = 'box', voxelSize = 0.8, ballSegments = 8, colorAmplify = 1.0) {
260
  if (!voxData.voxels || !voxData.size) return null;
261
 
262
  const voxels = voxData.voxels;
 
270
  baseGeometry = new THREE.BoxGeometry(voxelSize, voxelSize, voxelSize);
271
  }
272
 
273
+ // Create materials for different colors instead of using vertex colors
274
+ const materials = [];
275
+ const colorMap = new Map();
276
+
277
+ // Create materials for each unique color in the palette
278
+ for (let i = 0; i < palette.length; i++) {
279
+ const color = palette[i];
280
+ const material = new THREE.MeshPhongMaterial({
281
+ color: new THREE.Color(
282
+ Math.min(1.0, (color.r / 255) * colorAmplify),
283
+ Math.min(1.0, (color.g / 255) * colorAmplify),
284
+ Math.min(1.0, (color.b / 255) * colorAmplify)
285
+ ),
286
  shininess: 30
287
+ });
288
+ materials.push(material);
289
+ colorMap.set(i, materials.length - 1);
290
+ }
291
 
292
+ // Create groups of meshes by material for better performance
293
+ const meshGroups = new Map();
 
294
 
295
  // Calculate offsets to center the model
296
  const offsetX = voxData.size.x / 2;
297
  const offsetY = voxData.size.y / 2;
298
  const offsetZ = voxData.size.z / 2;
299
 
300
+ // Group voxels by color
301
  for (let i = 0; i < voxels.length; i++) {
302
  const voxel = voxels[i];
303
+ const colorIndex = voxel.colorIndex - 1; // VOX colors start at 1
304
 
 
 
 
 
 
 
 
 
 
 
 
305
  if (colorIndex >= 0 && colorIndex < palette.length) {
306
+ const materialIndex = colorIndex;
307
+
308
+ if (!meshGroups.has(materialIndex)) {
309
+ meshGroups.set(materialIndex, []);
310
+ }
311
+
312
+ meshGroups.get(materialIndex).push({
313
+ x: voxel.x - offsetX,
314
+ y: voxel.y - offsetY,
315
+ z: voxel.z - offsetZ
316
+ });
317
  }
318
  }
319
 
320
+ // Create a group to hold all the voxel meshes
321
+ const voxelGroup = new THREE.Group();
322
+
323
+ // Create instanced meshes for each color group
324
+ for (const [materialIndex, positions] of meshGroups) {
325
+ if (positions.length === 0) continue;
326
+
327
+ const instancedMesh = new THREE.InstancedMesh(
328
+ baseGeometry,
329
+ materials[materialIndex],
330
+ positions.length
331
+ );
332
+
333
+ const dummy = new THREE.Object3D();
334
+ for (let i = 0; i < positions.length; i++) {
335
+ const pos = positions[i];
336
+ dummy.position.set(pos.x, pos.y, pos.z);
337
+ dummy.updateMatrix();
338
+ instancedMesh.setMatrixAt(i, dummy.matrix);
339
+ }
340
+
341
+ instancedMesh.castShadow = true;
342
+ instancedMesh.receiveShadow = true;
343
+ voxelGroup.add(instancedMesh);
344
+ }
345
 
346
+ return voxelGroup;
347
  }
348
 
349
  static generateDefaultPalette() {
 
385
  const defaultCameraLookAt = new THREE.Vector3(0, 0, 0);
386
 
387
  // Lighting setup - make it brighter for better color visibility
388
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
389
  scene.add(ambientLight);
390
 
391
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
392
  directionalLight.position.set(10, 10, 5);
393
  directionalLight.castShadow = true;
394
  directionalLight.shadow.mapSize.width = 2048;
 
401
  let currentFileType = 'none'; // 'none', 'glb', 'vox'
402
  let autoRotateEnabled = true;
403
  let currentRenderMode = 'box';
404
+ let currentColorAmplify = 1.0;
405
  let modelCenter = new THREE.Vector3(0, 0, 0); // Store model center for rotation
406
 
407
  // File input handlers
 
456
  voxData.size.z / 2 - voxData.size.z / 2
457
  );
458
 
459
+ const voxelGroup = VOXParser.createInstancedGeometry(
460
  voxData,
461
  currentRenderMode,
462
  parseFloat(document.getElementById('voxelSize').value),
463
+ parseInt(document.getElementById('ballSegments').value),
464
+ currentColorAmplify
465
  );
466
 
467
+ if (voxelGroup) {
468
+ loadModel(voxelGroup, 'vox');
469
  showVOXControls(true);
470
  updateModelInfo(`VOX: ${file.name} (${voxData.voxels.length} voxels)`, 'vox');
471
  }
 
515
  const voxControls = document.getElementById('voxControls');
516
  const voxelSizeControl = document.getElementById('voxelSizeControl');
517
  const ballSegmentsControl = document.getElementById('ballSegmentsControl');
518
+ const colorAmplifyControl = document.getElementById('colorAmplifyControl');
519
 
520
  voxControls.style.display = show ? 'block' : 'none';
521
  voxelSizeControl.style.display = show ? 'block' : 'none';
522
  ballSegmentsControl.style.display = show && currentRenderMode === 'ball' ? 'block' : 'none';
523
+ colorAmplifyControl.style.display = show ? 'block' : 'none';
524
  }
525
 
526
  function setRenderMode(mode) {
 
536
 
537
  // Rebuild geometry if we have VOX data
538
  if (currentVOXData && currentFileType === 'vox') {
539
+ const voxelGroup = VOXParser.createInstancedGeometry(
540
  currentVOXData,
541
  mode,
542
  parseFloat(document.getElementById('voxelSize').value),
543
+ parseInt(document.getElementById('ballSegments').value),
544
+ currentColorAmplify
545
  );
546
 
547
+ if (voxelGroup) {
548
+ loadModel(voxelGroup, 'vox');
549
  }
550
  }
551
  }
 
568
  }
569
  }
570
 
571
+ function updateColorAmplify() {
572
+ const value = parseFloat(document.getElementById('colorAmplify').value);
573
+ document.getElementById('colorAmplifyValue').textContent = value.toFixed(1);
574
+ currentColorAmplify = value;
575
+
576
+ if (currentVOXData && currentFileType === 'vox') {
577
+ setRenderMode(currentRenderMode);
578
+ }
579
+ }
580
+
581
  function centerRotationOnModel() {
582
  if (!currentModel) return;
583
 
 
656
 
657
  document.getElementById('voxelSize').addEventListener('input', updateVoxelSize);
658
  document.getElementById('ballSegments').addEventListener('input', updateBallSegments);
659
+ document.getElementById('colorAmplify').addEventListener('input', updateColorAmplify);
660
 
661
  // Animation loop
662
  function animate() {
 
674
  // Handle window resize
675
  window.addEventListener('resize', () => {
676
  camera.aspect = window.innerWidth / window.innerHeight;
677
+ camera.updateProjectionMatrix();
678
  renderer.setSize(window.innerWidth, window.innerHeight);
679
  });
680
 
681
  // Initialize
682
  updateVoxelSize();
683
  updateBallSegments();
684
+ updateColorAmplify();
685
  updateModelInfo('Ready to load models', 'none');
686
 
687
  animate();
688
  </script>
689
  </body>
690
+ </html>