Lines in a Projective Plane

../../_images/render1.png

In this example we will generate random lines (represented as planes) in a projective plane and visualize their intersections with a sphere and the projective plane in a Blender 3D scene. It’s a combination of geometric calculations and Blender scripting for You can see the full code at lines_in_a_projective_plane.py.

Setup

We start off by importing the necessary libraries.

# Import necessary libraries
import bpy
import numpy as np

import ddg
from ddg.blender.scene import clear

We are also going to clear the whole scene.

# Clear the existing objects in the Blender scene
clear()

Blender Collections

We create three Blender collections: rendering_coll for lights and cameras, gc_coll for great circles, and plane_coll for plane intersections.

# Create Blender collections for organizing objects
rendering_coll = ddg.blender.collection.collection("light and camera")
gc_coll = ddg.blender.collection.collection("great_circles")
plane_coll = ddg.blender.collection.collection("plane_intersections")

Geometric Calculations

Now we are going to generate random points on a unit sphere and calculate the corresponding planes using these points as normals. These planes are represented in the projective space.

# Generate N random normals and calculate corresponding planes
N = 4
seed = 59232
normals = [ddg.math.random.random_point_on_sphere(2, i * seed) for i in range(N)]
planes = [
    ddg.geometry.hyperplane_from_normal(normal, point=(0, 0, 0)) for normal in normals
]

Next we create a unit sphere (\(S^2\)) and a projective plane. The sphere is represented as a quadric, and the projective plane is represented as a hyperplane.

# Create a unit sphere (S2) and a projective plane
s2 = ddg.geometry.Quadric(np.diag([1, 1, 1, -1]))
bobj_s2 = ddg.blender.convert(s2, "s2")

projective_plane = ddg.geometry.hyperplane_from_normal((-1, 0, 0), point=(1.5, 0, 0))

Geometric Intersections

For each randomly generated plane, we calculate the intersection of the plane with the sphere (circ_on_sphere) and the intersection with the projective plane (meet_plane). These intersections are then visualized.

# Calculate intersections of the random planes with S2 and the projective plane
for i, plane in enumerate(planes):
    circ_on_sphere = ddg.geometry.meet(plane, s2)
    meet_plane = ddg.geometry.meet(plane, projective_plane)

    # Orthonormalize the intersection plane
    meet_plane = ddg.geometry.Subspace.orthonormalize(meet_plane)

    if circ_on_sphere.dimension != -1:
        # Create Blender objects for circles on the sphere
        bobj_circ_on_sphere = ddg.blender.convert(
            circ_on_sphere,
            f"spheric circle {i}",
            collection=gc_coll,
        )
        bobj_circ_on_sphere.data.bevel_depth = 0.005

    if meet_plane.dimension != -1:
        # Create Blender objects for plane intersections
        bobj_meet_plane = ddg.blender.convert(
            meet_plane,
            f"plane intersection {i}",
            collection=plane_coll,
        )
        bobj_meet_plane.data.bevel_depth = 0.005

Finally we can visualize it in Blender.

bobjprojective = ddg.blender.convert(projective_plane, "Projective plane")

Add Camera and Light

Awesome, so if we run this now, we see something in the Editor! However, for rendering we need a camera and a light. Let’s add those.

# Add a point light and a camera to the scene
light = ddg.blender.light.light(type_="POINT", collection=rendering_coll)
light.data.energy = 500
light.data.shadow_soft_size = 0
camera = ddg.blender.camera.camera(location=(-6, 0, 0), collection=rendering_coll)

# Position the camera to look at the projective plane
ddg.blender.camera.look_at_point(camera, (1.5, 0, 0))
bpy.context.scene.camera = camera

Add Materials

Finally let’s assign materials to the projective plane and the sphere. We assign the projective plane a color.

# Add a material to the projective plane
project_mat = ddg.blender.material.material(color=(0.8, 0.56, 0.535))
ddg.blender.material.set_material(bobjprojective, project_mat)

The sphere will get a color with transparency.

# Create a material for the sphere (S2) with transparency
s2material = bpy.data.materials.new("s2 material")
s2material.use_nodes = True
s2material.node_tree.nodes.remove(s2material.node_tree.nodes.get("Principled BSDF"))
transparent = s2material.node_tree.nodes.new("ShaderNodeBsdfTransparent")
transparent.inputs["Color"].default_value = (0.5, 0.5, 0.5, 1.0)
s2material.node_tree.links.new(
    transparent.outputs["BSDF"],
    s2material.node_tree.nodes["Material Output"].inputs["Surface"],
)
ddg.blender.material.set_material(bobj_s2, s2material)

That’s it! You should be able to just put that in your blender code editor and simply execute it.