ThorAILabs commited on
Commit
3607024
·
verified ·
1 Parent(s): 1680cc8
Files changed (1) hide show
  1. index.html +214 -169
index.html CHANGED
@@ -1,179 +1,224 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <title>3D Scene Editor with Raytracing</title>
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <!-- TailWind CSS -->
8
- <script src="https://cdn.tailwindcss.com"></script>
9
- <!-- FontAwesome -->
10
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
 
 
 
11
  </head>
12
  <body class="bg-gray-900 text-white">
13
- <!-- Header -->
14
- <header class="p-4 flex items-center space-x-4">
15
- <i class="fas fa-cube text-3xl"></i>
16
- <h1 class="text-3xl font-bold">3D Scene Editor with Raytracing</h1>
17
- </header>
18
-
19
- <!-- Main Layout -->
20
- <div class="flex flex-col md:flex-row">
21
- <!-- Sidebar Controls -->
22
- <aside class="w-full md:w-1/4 p-4 space-y-4 bg-gray-800">
23
- <h2 class="text-xl font-semibold">Controls</h2>
24
- <button id="toggleRaytrace" class="w-full py-2 px-4 bg-blue-600 hover:bg-blue-700 rounded">
25
- <i class="fas fa-bolt"></i> Toggle Raytracing
26
- </button>
27
- <label for="sceneInput" class="block">
28
- <span class="text-sm font-medium">Load Scene JSON:</span>
29
- <input id="sceneInput" type="file" accept=".json" class="mt-1 block w-full p-2 text-gray-800 rounded"/>
30
- </label>
31
- <div id="parserOutput" class="text-sm text-green-400"></div>
32
- </aside>
33
-
34
- <!-- Canvas Container -->
35
- <main class="flex-1 relative">
36
- <canvas id="sceneCanvas" class="w-full h-screen"></canvas>
37
- </main>
38
- </div>
39
-
40
- <!-- Scripts -->
41
- <!-- Three.js Core -->
42
- <script src="https://unpkg.com/three@0.150.0/build/three.min.js"></script>
43
- <!-- OrbitControls -->
44
- <script src="https://unpkg.com/three@0.150.0/examples/js/controls/OrbitControls.js"></script>
45
- <!-- dat.GUI for interactive controls -->
46
- <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
47
- <!-- Main Application Script -->
48
- <script type="module">
49
- // Importing OBJLoader as an example of a parser library for 3D assets
50
- import { OBJLoader } from 'https://unpkg.com/three@0.150.0/examples/jsm/loaders/OBJLoader.js';
51
-
52
- let scene, camera, renderer, controls, gui;
53
- let raytraceMode = false;
54
- const canvas = document.getElementById('sceneCanvas');
55
-
56
- // Initialization function to set up scene, camera, renderer, and controls.
57
- function init() {
58
- // Create scene
59
- scene = new THREE.Scene();
60
- scene.background = new THREE.Color(0x222222);
61
-
62
- // Set up camera
63
- camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
64
- camera.position.set(0, 2, 5);
65
-
66
- // Renderer setup with antialiasing
67
- renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
68
- renderer.setSize(window.innerWidth, window.innerHeight);
69
- document.body.appendChild(renderer.domElement);
70
-
71
- // OrbitControls for interactive scene navigation
72
- controls = new THREE.OrbitControls(camera, renderer.domElement);
73
-
74
- // Lighting: Ambient and directional for solid shading
75
- const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
76
- scene.add(ambientLight);
77
- const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
78
- directionalLight.position.set(5, 10, 7.5);
79
- scene.add(directionalLight);
80
-
81
- // Add a sample cube
82
- const cubeGeometry = new THREE.BoxGeometry();
83
- const cubeMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
84
- const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
85
- cube.name = "Cube";
86
- scene.add(cube);
87
-
88
- // Add a sample plane as the floor
89
- const planeGeometry = new THREE.PlaneGeometry(10, 10);
90
- const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x808080 });
91
- const plane = new THREE.Mesh(planeGeometry, planeMaterial);
92
- plane.rotation.x = -Math.PI / 2;
93
- plane.name = "Plane";
94
- scene.add(plane);
95
-
96
- // Setup dat.GUI controls within a styled container
97
- gui = new dat.GUI({ autoPlace: false, width: 300 });
98
- const guiContainer = document.createElement('div');
99
- guiContainer.classList.add('absolute', 'top-4', 'right-4', 'bg-gray-800', 'p-4', 'rounded');
100
- guiContainer.appendChild(gui.domElement);
101
- document.body.appendChild(guiContainer);
102
-
103
- // dat.GUI folder for cube controls
104
- const cubeFolder = gui.addFolder('Cube Transform');
105
- cubeFolder.add(cube.position, 'x', -5, 5, 0.1).name('Position X');
106
- cubeFolder.add(cube.position, 'y', -5, 5, 0.1).name('Position Y');
107
- cubeFolder.add(cube.position, 'z', -5, 5, 0.1).name('Position Z');
108
- cubeFolder.open();
109
-
110
- animate();
111
- }
112
-
113
- // Animation loop for rendering the scene continuously.
114
- function animate() {
115
- requestAnimationFrame(animate);
116
- controls.update();
117
-
118
- if (!raytraceMode) {
119
- renderer.render(scene, camera);
120
- } else {
121
- // Here you would integrate a proper raytracing shader or postprocessing pass.
122
- // For demonstration, we simulate raytracing by applying a simple overlay effect.
123
- renderer.render(scene, camera);
124
- // Additional raytracing effects can be added here.
125
- }
126
- }
127
-
128
- // Adjust canvas size on window resize
129
- window.addEventListener('resize', () => {
130
- camera.aspect = window.innerWidth / window.innerHeight;
131
- camera.updateProjectionMatrix();
132
- renderer.setSize(window.innerWidth, window.innerHeight);
133
- });
134
-
135
- // Toggle raytracing mode and display a simple alert (simulation).
136
- document.getElementById('toggleRaytrace').addEventListener('click', () => {
137
- raytraceMode = !raytraceMode;
138
- alert('Raytracing mode ' + (raytraceMode ? 'enabled' : 'disabled') + '. (Simulation mode)');
139
- });
140
-
141
- // Basic scene parser: Load a JSON file and add objects to the scene.
142
- // Expected format:
143
- // {
144
- // "objects": [
145
- // { "type": "sphere", "radius": 1, "color": 16711680, "position": {"x": 0, "y": 1, "z": 0} }
146
- // ]
147
- // }
148
- document.getElementById('sceneInput').addEventListener('change', (event) => {
149
- const file = event.target.files[0];
150
- if (!file) return;
151
- const reader = new FileReader();
152
- reader.onload = (e) => {
153
- try {
154
- const sceneData = JSON.parse(e.target.result);
155
- document.getElementById('parserOutput').textContent = 'Scene loaded successfully!';
156
- if (Array.isArray(sceneData.objects)) {
157
- sceneData.objects.forEach(obj => {
158
- if (obj.type === 'sphere') {
159
- const sphereGeo = new THREE.SphereGeometry(obj.radius || 1, 32, 32);
160
- const sphereMat = new THREE.MeshStandardMaterial({ color: obj.color || 0xff0000 });
161
- const sphere = new THREE.Mesh(sphereGeo, sphereMat);
162
- sphere.position.set(obj.position?.x || 0, obj.position?.y || 0, obj.position?.z || 0);
163
- scene.add(sphere);
164
- }
165
- // Extend here with other object types and parsers as needed.
166
  });
167
- }
168
- } catch (error) {
169
- document.getElementById('parserOutput').textContent = 'Error parsing scene file!';
170
- }
171
- };
172
- reader.readAsText(file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
- // Initialize the 3D scene.
176
- init();
177
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  </body>
179
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <title>3D Scene Editor with Raytracing & Model Support</title>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/controls/OrbitControls.js"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/jsm/loaders/OBJLoader.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/jsm/loaders/STLLoader.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/jsm/exporters/STLExporter.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/jsm/exporters/OBJExporter.js"></script>
12
+ <script src="https://cdn.tailwindcss.com"></script>
13
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
14
  </head>
15
  <body class="bg-gray-900 text-white">
16
+ <div class="flex h-screen">
17
+ <!-- Sidebar -->
18
+ <div class="w-64 bg-gray-800 p-4 space-y-4">
19
+ <h2 class="text-xl font-bold mb-4">Scene Tools</h2>
20
+
21
+ <div class="space-y-2">
22
+ <select id="shapeType" class="w-full bg-gray-700 rounded p-2">
23
+ <option value="sphere">Sphere</option>
24
+ <option value="cube">Cube</option>
25
+ <option value="torus">Torus</option>
26
+ </select>
27
+
28
+ <input type="color" id="objectColor" class="w-full h-10">
29
+
30
+ <button onclick="addObject()" class="w-full bg-blue-600 hover:bg-blue-700 p-2 rounded">
31
+ <i class="fas fa-plus mr-2"></i>Add Object
32
+ </button>
33
+
34
+ <button onclick="raytraceScene()" class="w-full bg-purple-600 hover:bg-purple-700 p-2 rounded">
35
+ <i class="fas fa-magic mr-2"></i>Raytrace
36
+ </button>
37
+
38
+ <!-- File Import Section -->
39
+ <div class="border-t pt-4">
40
+ <input type="file" id="modelInput" accept=".stl,.obj" class="hidden"/>
41
+ <label for="modelInput" class="w-full bg-green-600 hover:bg-green-700 p-2 rounded block text-center cursor-pointer">
42
+ <i class="fas fa-file-import mr-2"></i>Import Model
43
+ </label>
44
+
45
+ <select id="exportFormat" class="w-full bg-gray-700 rounded p-2 mt-2">
46
+ <option value="stl">STL</option>
47
+ <option value="obj">OBJ</option>
48
+ </select>
49
+
50
+ <button onclick="exportScene()" class="w-full bg-orange-600 hover:bg-orange-700 p-2 rounded">
51
+ <i class="fas fa-file-export mr-2"></i>Export Scene
52
+ </button>
53
+ </div>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- Main View -->
58
+ <div class="flex-1 relative">
59
+ <canvas id="sceneCanvas" class="w-full h-full"></canvas>
60
+
61
+ <!-- Selected Object Controls -->
62
+ <div id="objectControls" class="absolute top-4 right-4 bg-gray-800 p-4 rounded-lg hidden">
63
+ <button onclick="deleteObject()" class="bg-red-600 hover:bg-red-700 p-2 rounded">
64
+ <i class="fas fa-trash mr-2"></i>Delete
65
+ </button>
66
+ </div>
67
+ </div>
68
+ </div>
69
+
70
+ <script>
71
+ let scene, camera, renderer, controls;
72
+ let selectedObject = null;
73
+
74
+ // Initialize Three.js Scene
75
+ function initScene() {
76
+ scene = new THREE.Scene();
77
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
78
+ renderer = new THREE.WebGLRenderer({ antialias: true });
79
+ renderer.setSize(window.innerWidth - 256, window.innerHeight);
80
+ renderer.setClearColor(0x1a1a1a);
81
+ document.getElementById('sceneCanvas').appendChild(renderer.domElement);
82
+
83
+ // Lighting setup
84
+ const ambientLight = new THREE.AmbientLight(0x404040);
85
+ scene.add(ambientLight);
86
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
87
+ directionalLight.position.set(5, 5, 5);
88
+ scene.add(directionalLight);
89
+
90
+ camera.position.z = 5;
91
+ controls = new THREE.OrbitControls(camera, renderer.domElement);
92
+
93
+ // Event listeners
94
+ renderer.domElement.addEventListener('click', onCanvasClick);
95
+ window.addEventListener('resize', onWindowResize);
96
+ }
97
+
98
+ // Model Import Handler
99
+ document.getElementById('modelInput').addEventListener('change', (e) => {
100
+ const file = e.target.files;
101
+ const reader = new FileReader();
102
+
103
+ reader.onload = (event) => {
104
+ const loader = file.name.endsWith('.stl') ?
105
+ new THREE.STLLoader() : new THREE.OBJLoader();
106
+
107
+ loader.load(event.target.result, (object) => {
108
+ object.traverse(child => {
109
+ if (child.isMesh) {
110
+ child.material = new THREE.MeshPhongMaterial({
111
+ color: Math.random() * 0xffffff,
112
+ shininess: 100
113
+ });
114
+ child.position.set(
115
+ (Math.random() - 0.5) * 5,
116
+ (Math.random() - 0.5) * 5,
117
+ (Math.random() - 0.5) * 5
118
+ );
119
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  });
121
+ scene.add(object);
122
+ });
123
+ };
124
+
125
+ reader.readAsDataURL(file);
126
+ });
127
+
128
+ // Scene Export Handler
129
+ function exportScene() {
130
+ const format = document.getElementById('exportFormat').value;
131
+ const exporter = format === 'stl' ?
132
+ new THREE.STLExporter() : new THREE.OBJExporter();
133
+
134
+ const result = exporter.parse(scene);
135
+ const blob = new Blob([result], {type: 'text/plain'});
136
+ const link = document.createElement('a');
137
+
138
+ link.href = URL.createObjectURL(blob);
139
+ link.download = `scene.${format}`;
140
+ link.click();
141
+ }
142
+
143
+ // Object Management
144
+ function addObject() {
145
+ const geometryType = document.getElementById('shapeType').value;
146
+ const color = document.getElementById('objectColor').value;
147
+
148
+ let geometry;
149
+ switch(geometryType) {
150
+ case 'sphere': geometry = new THREE.SphereGeometry(1, 32, 32); break;
151
+ case 'cube': geometry = new THREE.BoxGeometry(1, 1, 1); break;
152
+ case 'torus': geometry = new THREE.TorusGeometry(1, 0.4, 16, 100); break;
153
+ }
154
+
155
+ const material = new THREE.MeshPhongMaterial({
156
+ color: color,
157
+ shininess: 100
158
  });
159
+
160
+ const mesh = new THREE.Mesh(geometry, material);
161
+ mesh.position.set(
162
+ (Math.random() - 0.5) * 5,
163
+ (Math.random() - 0.5) * 5,
164
+ (Math.random() - 0.5) * 5
165
+ );
166
+ scene.add(mesh);
167
+ }
168
+
169
+ // Raytracing Functionality
170
+ function raytraceScene() {
171
+ const raycaster = new THREE.Raycaster();
172
+ const sceneBoundingBox = new THREE.Box3().setFromObject(scene);
173
+
174
+ // Implementation placeholder for actual raytracing
175
+ console.log("Raytracing initiated with scene bounds:", sceneBoundingBox);
176
+ }
177
+
178
+ // Event Handlers
179
+ function onCanvasClick(event) {
180
+ const raycaster = new THREE.Raycaster();
181
+ const mouse = new THREE.Vector2();
182
+
183
+ mouse.x = (event.clientX / renderer.domElement.width) * 2 - 1;
184
+ mouse.y = -(event.clientY / renderer.domElement.height) * 2 + 1;
185
+
186
+ raycaster.setFromCamera(mouse, camera);
187
+ const intersects = raycaster.intersectObjects(scene.children);
188
+
189
+ if(intersects.length > 0) {
190
+ selectedObject = intersects.object;
191
+ document.getElementById('objectControls').classList.remove('hidden');
192
+ } else {
193
+ selectedObject = null;
194
+ document.getElementById('objectControls').classList.add('hidden');
195
+ }
196
+ }
197
 
198
+ function deleteObject() {
199
+ if(selectedObject) {
200
+ scene.remove(selectedObject);
201
+ selectedObject = null;
202
+ document.getElementById('objectControls').classList.add('hidden');
203
+ }
204
+ }
205
+
206
+ function onWindowResize() {
207
+ camera.aspect = (window.innerWidth - 256) / window.innerHeight;
208
+ camera.updateProjectionMatrix();
209
+ renderer.setSize(window.innerWidth - 256, window.innerHeight);
210
+ }
211
+
212
+ // Animation Loop
213
+ function animate() {
214
+ requestAnimationFrame(animate);
215
+ controls.update();
216
+ renderer.render(scene, camera);
217
+ }
218
+
219
+ // Initialize Application
220
+ initScene();
221
+ animate();
222
+ </script>
223
  </body>
224
  </html>