Neurons & axons
Neurons from mesh vertices
During World::new, the constructor walks the flat vertex array with a stride
of vertices_skip_step (default 2, so every second vertex), classifies each
position into a cortical region, and creates a
Neuron:
let mut i = 0;
while i < total_verts {
let off = i * 3;
let p = Vec3::new(flat[off], flat[off + 1], flat[off + 2]);
let region = classify_region(p, min, max);
let neuron_idx = neurons.len();
neurons.push(Neuron::new(p.x, p.y, p.z, region));
region_neurons[region.as_u32() as usize].push(neuron_idx);
region_counts.add(region, 1.0);
i += settings.vertices_skip_step.max(1);
}
The skip step keeps the neuron count manageable on dense meshes. Each region also gets a bucket of neuron indices, used later when injecting stimulus into a specific region.
Axon connections
Axons connect nearby neurons. The constructor does an O(N²) pass over neuron pairs, subject to two constraints:
- Each neuron may have at most
max_connections_per_neuronconnections (default6). - Two neurons are connected only if they are closer than
max_axon_dist(default8.0).
for j in 0..neuron_count {
for k in (j + 1)..neuron_count {
if neurons[j].connections.len() >= settings.max_connections_per_neuron
|| neurons[k].connections.len() >= settings.max_connections_per_neuron
{ continue; }
if n1_pos.distance(n2_pos) >= settings.max_axon_dist { continue; }
let axon = Axon::new(n1_pos, n2_pos, j, k, &mut rng);
// ... record connections on both neurons
}
}
This pairwise connection pass is O(N²) in the neuron count. It runs once at
construction, not per frame, so it is a one-time startup cost. The
vertices_skip_step and max_connections_per_neuron settings keep N and the
edge count bounded.
Bezier curves and sampling
Each axon is not a straight line: it is a cubic Bezier curve with four control points, sampled into vertices:
const SUBDIVISIONS_PER_AXON: usize = 8;
const SAMPLES_PER_AXON: usize = SUBDIVISIONS_PER_AXON + 1; // 9
So every axon produces 9 sampled vertices (8 segments). At construction the core bakes three flat render buffers from these samples:
axon_positions:SAMPLES_PER_AXON * 3floats per axon.axon_indices: line-segment pairs (SUBDIVISIONS_PER_AXON * 2per axon).axon_opacities: a random per-segment opacity in[0.005, 0.2], duplicated across each segment's two endpoints.
The control points themselves are stored in an AxonControlTable, which the
signal system uses to sample positions along the curve as a signal travels
(parameter t from 0 to 1). The same Bezier evaluation determines both the
static rendered axon and the moving signal position.
The Brain reads these buffers through the pointer getters
(axon_positions_ptr, axon_index_ptr, axon_opacity_ptr) and binds them to
the axon LineSegments geometry. They are uploaded once and never change.