()
| 2439 | } |
| 2440 | |
| 2441 | buildLayers() { |
| 2442 | const inputGeometry = new THREE.BoxGeometry( |
| 2443 | this.options.inputNodeSize, |
| 2444 | this.options.inputNodeSize, |
| 2445 | this.options.inputNodeSize, |
| 2446 | ); |
| 2447 | const hiddenGeometry = new THREE.SphereGeometry(this.options.hiddenNodeRadius, 16, 16); |
| 2448 | // Test with MeshBasicMaterial for hidden/output neurons (no lighting influence) |
| 2449 | const hiddenBaseMaterial = new THREE.MeshBasicMaterial(); |
| 2450 | hiddenBaseMaterial.toneMapped = false; |
| 2451 | |
| 2452 | const layerCount = this.mlp.architecture.length; |
| 2453 | const totalWidth = (layerCount - 1) * this.options.layerSpacing; |
| 2454 | const startX = -totalWidth / 2; |
| 2455 | |
| 2456 | this.clearOutputLabels(); |
| 2457 | this.mlp.architecture.forEach((neuronCount, layerIndex) => { |
| 2458 | const layerX = startX + layerIndex * this.options.layerSpacing; |
| 2459 | const positions = this.computeLayerPositions(layerIndex, neuronCount, layerX); |
| 2460 | const isOutputLayer = layerIndex === layerCount - 1; |
| 2461 | |
| 2462 | if (layerIndex === 0) { |
| 2463 | const material = new THREE.MeshLambertMaterial(); |
| 2464 | material.emissive.setRGB(0.08, 0.08, 0.08); |
| 2465 | const mesh = new THREE.InstancedMesh(inputGeometry, material, neuronCount); |
| 2466 | mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); |
| 2467 | const colorAttribute = new THREE.InstancedBufferAttribute(new Float32Array(neuronCount * 3), 3); |
| 2468 | colorAttribute.setUsage(THREE.DynamicDrawUsage); |
| 2469 | mesh.instanceColor = colorAttribute; |
| 2470 | |
| 2471 | positions.forEach((position, instanceIndex) => { |
| 2472 | this.tempObject.position.copy(position); |
| 2473 | this.tempObject.updateMatrix(); |
| 2474 | mesh.setMatrixAt(instanceIndex, this.tempObject.matrix); |
| 2475 | mesh.setColorAt(instanceIndex, this.tempColor.setRGB(0.15, 0.15, 0.15)); |
| 2476 | }); |
| 2477 | |
| 2478 | mesh.instanceMatrix.needsUpdate = true; |
| 2479 | mesh.instanceColor.needsUpdate = true; |
| 2480 | this.scene.add(mesh); |
| 2481 | this.layerMeshes.push({ mesh, positions, type: "input", layerIndex }); |
| 2482 | } else { |
| 2483 | const material = hiddenBaseMaterial.clone(); |
| 2484 | // Clone geometry per mesh so each InstancedMesh can have its own instanceColor attribute |
| 2485 | const geometry = hiddenGeometry.clone(); |
| 2486 | const mesh = new THREE.InstancedMesh(geometry, material, neuronCount); |
| 2487 | mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); |
| 2488 | const colorAttribute = new THREE.InstancedBufferAttribute(new Float32Array(neuronCount * 3), 3); |
| 2489 | colorAttribute.setUsage(THREE.DynamicDrawUsage); |
| 2490 | mesh.instanceColor = colorAttribute; |
| 2491 | |
| 2492 | positions.forEach((position, instanceIndex) => { |
| 2493 | this.tempObject.position.copy(position); |
| 2494 | this.tempObject.updateMatrix(); |
| 2495 | mesh.setMatrixAt(instanceIndex, this.tempObject.matrix); |
| 2496 | mesh.setColorAt(instanceIndex, this.tempColor.setRGB(0.15, 0.15, 0.15)); |
| 2497 | }); |
| 2498 |
no test coverage detected