Initializing 3D Canvas...

Gaussian Curvature

2 min read1 page

In Differential Geometry, we classify the shape of a surface based on how it bends.Gaussian Curvature (K) is an intrinsic property, meaning it doesn't change even if you bend the surface (without stretching it).

Curvature Types:

1. Positive (Sphere): Bends inward on all sides. Cannot be flattened without tearing/stretching. 2. Zero (Cylinder): Bends in only one direction. Can be unrolled into a flat plane perfectly. 3. Negative (Saddle/Hyperbolic): Bends UP along one axis and DOWN along another (like a Pringles chip).
python
1# Gaussian Curvature Theory
2def understand_curvature(K):
3 """K = k1 * k2 (the two principal curvatures)"""
4
5 if K > 0:
6 return "Positive (Synclastic): Like a Sphere. Bends same way in all directions."
7 elif K < 0:
8 return "Negative (Anticlastic): Like a Saddle. Bends up in one direction, down in another."
9 else:
10 return "Zero (Developable): Like a Cylinder or flat plane. Unrolls flat without tearing."
Curvature (Positive/Zero/Negative)
0.00
1 min read1 page

In a continuous math formula, curvature is measured at an infinitely small point. But in a discrete Triangle Mesh, curvature can only be approximated by looking at a vertex and its immediate neighbors.

Discrete Differential Geometry:

1. Select the Vertex we want to analyze. 2. Find the 1-Ring Neighborhood (Vertex Star): All triangles that share this vertex. 3. The geometry of this specific ring of triangles determines the curvature at the central vertex.
python
1# Finding the 1-Ring Neighborhood
2def get_vertex_star(mesh, vertex_id):
3 """Returns all faces and vertices immediately connected to a vertex."""
4
5 # We query the topology graph
6 connected_faces = mesh.topology.get_faces_at_vertex(vertex_id)
7 connected_vertices = mesh.topology.get_neighbors(vertex_id)
8
9 return connected_faces, connected_vertices
Highlight 1-Ring
0.00
2 min read1 page

Because curvature is a measure of how bending changes over an area, we need to know exactly how much surface area "belongs" to our central vertex.

Area Weighting:

1. Every triangle in the 1-Ring neighborhood has an area. 2. By taking exactly 1/3 of each triangle's area, we carve out a polygon around the center vertex. 3. This is known as the Barycentric Area (or simplified Voronoi Area). 4. This value will be used later to "normalize" the final curvature calculation.
python
1# Voronoi Area of a Vertex
2def calculate_mixed_voronoi_area(vertex_id, star_faces):
3 """Calculates the surface area 'belonging' to a single vertex."""
4
5 total_area = 0.0
6
7 for face in star_faces:
8 # A simple approximation (Barycentric area) is 1/3 of each triangle's area
9 tri_area = calculate_triangle_area(face)
10
11 # In Meyer's true algorithm, we use the Mixed Voronoi Area
12 # which accounts for obtuse (wide) triangles, but 1/3 is often good enough!
13 total_area += (tri_area / 3.0)
14
15 return total_area
Area (Triangles/Thirds/Voronoi)
0.00
2 min read1 page

How do we know if a vertex is flat, peaked, or saddle-shaped just by looking at its triangles? We use the Angle Deficit.

The 360 Rule:

1. Look at all the triangles attached to the central vertex. 2. Measure the internal angle of each triangle at that center point. 3. Add them all up. 4. If the sum is exactly 360° (2π), the vertex is completely flat (Zero Curvature). 5. If the sum is less than 360°, it forms a cone/peak (Positive Curvature). 6. If the sum is greater than 360°, it is wavy/ruffled like a saddle (Negative Curvature).
python
1# Calculating Angle Deficit
2def calculate_angle_deficit(vertex_id, star_faces):
3 """How much a vertex behaves like a cone vs a saddle."""
4
5 # Start with 2*PI (a completely flat, 360 degree circle)
6 angle_sum = 2.0 * math.pi
7
8 for face in star_faces:
9 # Find the angle of this specific triangle at the central vertex
10 theta = calculate_triangle_angle(face, center=vertex_id)
11
12 # Subtract it from our total
13 angle_sum -= theta
14
15 # The remainder is the 'Angle Deficit'
16 return angle_sum
Angles (<360 / =360 / >360)
0.00
2 min read1 page

We have the Angle Deficit (the raw bending amount) and the Voronoi Area (the size of the neighborhood). To get the final Gaussian Curvature (K), we simply divide the Deficit by the Area.

Mesh Independence:

1. Why divide by Area? Because of Mesh Resolution! 2. On a high-resolution sphere, a single vertex is surrounded by tiny triangles. Its Angle Deficit is very small. 3. On a low-resolution sphere (like a D20 die), the triangles are huge, and the Angle Deficit at a corner is massive. 4. By dividing the Deficit by the Area, both spheres output the exact same Gaussian Curvature! It becomes a property of the shape, not the polygons.
python
1# Calculating Discrete Gaussian Curvature
2def get_gaussian_curvature(vertex_id, mesh):
3 """Combines Angle Deficit with Voronoi Area."""
4
5 star_faces = mesh.topology.get_faces(vertex_id)
6
7 # 1. Get the raw angular deficit
8 angle_deficit = calculate_angle_deficit(vertex_id, star_faces)
9
10 # 2. Get the surface area belonging to this vertex
11 voronoi_area = calculate_mixed_voronoi_area(vertex_id, star_faces)
12
13 # 3. Normalize!
14 # Without this, a densely tessellated sphere would seem to have
15 # less curvature per-vertex than a low-poly sphere.
16 K = angle_deficit / voronoi_area
17
18 return K
Sphere Resolution
0.00
2 min read1 page

Once we calculate Gaussian Curvature K for every single vertex on a mesh, we have an array of numbers. To make this data useful to humans, we map those numbers to Vertex Colors.

Color Mapping:

1. Find the Minimum and Maximum curvature values across the entire mesh. 2. Normalize every vertex's K value to a 0.0 - 1.0 percentage. 3. Map that percentage to a color gradient. Usually:
- Red: High Positive (Peaks)
- Green/Grey: Zero (Flat)
- Blue: High Negative (Saddles/Valleys)
python
1# Vertex Color Mapping
2def apply_curvature_colors(mesh, k_array):
3 """Maps numerical curvature to an RGB gradient."""
4
5 # K can be anything from -100 to +100 depending on scale.
6 # We need to map this to a 0.0 to 1.0 color gradient.
7
8 k_min = min(k_array)
9 k_max = max(k_array)
10
11 for vertex_id, K in enumerate(k_array):
12 # Normalize K to a 0-1 range based on the mesh extremes
13 normalized_k = (K - k_min) / (k_max - k_min)
14
15 # Look up color in a gradient map (e.g. Blue -> Green -> Red)
16 color = sample_gradient(normalized_k)
17
18 mesh.vertices[vertex_id].color = color
Color Mode (Solid/Curvature)
0.00
2 min read1 page

In advanced 3D modeling tools (like Rhino or Alias), Curvature Analysis is used constantly. Car designers use it to ensure the sheet metal is perfectly smooth without any hidden wobbles. 3D Printers use it to identify sharp peaks that might melt or break off.

Visual Diagnostics:

1. Observe the complex organic shape. 2. Activate the Curvature Analysis. 3. The Red areas represent sharp peaks or edges (Positive Curvature). 4. The Blue areas represent tight folds or saddles (Negative Curvature). 5. A perfectly smooth, flat surface would appear Grey.
python
1# Complete Curvature Pipeline
2def analyze_surface_curvature(mesh):
3 """Full discrete differential geometry analysis."""
4
5 curvature_data = []
6
7 for vertex in mesh.vertices:
8 # 1. Topological Analysis (1-Ring)
9 star = get_vertex_star(mesh, vertex.id)
10
11 # 2. Geometric Analysis
12 deficit = calculate_angle_deficit(vertex.id, star)
13 area = calculate_mixed_voronoi_area(vertex.id, star)
14
15 # 3. Normalization
16 K = deficit / area
17 curvature_data.append(K)
18
19 # 4. Rendering
20 apply_curvature_colors(mesh, curvature_data)
21
22 return mesh
Auto-Rotate
1.00
Show Curvature Map
1.00