Add reusable procedural helper library
This commit is contained in:
parent
eb650ad7b5
commit
aa4d49da1a
18 changed files with 378 additions and 242 deletions
|
|
@ -22,6 +22,21 @@ except ModuleNotFoundError:
|
|||
load_repo_geometry_script()
|
||||
|
||||
from geometry_script import * # noqa: F403 - Geometry Script exposes node functions as DSL globals.
|
||||
from vibegeometry import (
|
||||
CylinderFrame,
|
||||
add_box,
|
||||
add_curve_polyline,
|
||||
add_cylinder_between,
|
||||
add_material,
|
||||
add_mesh_parts,
|
||||
add_multi_polyline_curve,
|
||||
aim_camera,
|
||||
append_box_parts,
|
||||
append_cylindrical_ring_band,
|
||||
clear_scene,
|
||||
fbm_2d,
|
||||
smoothstep,
|
||||
)
|
||||
|
||||
|
||||
TAU = pymath.tau
|
||||
|
|
@ -31,6 +46,12 @@ CUT_END = pymath.radians(132.0)
|
|||
FULL_START = -pymath.pi
|
||||
FULL_END = pymath.pi
|
||||
INNER_RADIUS = 5.0
|
||||
FRAME = CylinderFrame(INNER_RADIUS)
|
||||
radial = FRAME.radial
|
||||
tangent = FRAME.tangent
|
||||
cyl_point = FRAME.cyl_point
|
||||
surface_point = FRAME.surface_point
|
||||
mat = add_material
|
||||
|
||||
|
||||
@tree("VG Bloom Light Spine")
|
||||
|
|
@ -55,42 +76,6 @@ def vg_bloom_light_spine(
|
|||
return {"Geometry": curve_to_mesh(curve=positioned, profile_curve=profile, fill_caps=True)}
|
||||
|
||||
|
||||
def mat(name, color, emission=False, strength=0.0, alpha=1.0):
|
||||
import bpy
|
||||
|
||||
material = bpy.data.materials.new(name)
|
||||
material.diffuse_color = (color[0], color[1], color[2], alpha)
|
||||
material.use_nodes = True
|
||||
bsdf = material.node_tree.nodes.get("Principled BSDF")
|
||||
if bsdf:
|
||||
if emission:
|
||||
bsdf.inputs["Emission Color"].default_value = (color[0], color[1], color[2], 1.0)
|
||||
bsdf.inputs["Emission Strength"].default_value = strength
|
||||
bsdf.inputs["Base Color"].default_value = (color[0], color[1], color[2], alpha)
|
||||
bsdf.inputs["Roughness"].default_value = 0.62
|
||||
bsdf.inputs["Alpha"].default_value = alpha
|
||||
if alpha < 1.0:
|
||||
material.blend_method = "BLEND"
|
||||
material.use_screen_refraction = True
|
||||
material.show_transparent_back = True
|
||||
return material
|
||||
|
||||
|
||||
def clear_scene():
|
||||
import bpy
|
||||
|
||||
bpy.ops.object.select_all(action="SELECT")
|
||||
bpy.ops.object.delete()
|
||||
|
||||
|
||||
def radial(angle: float):
|
||||
return (0.0, pymath.cos(angle), pymath.sin(angle))
|
||||
|
||||
|
||||
def tangent(angle: float):
|
||||
return (0.0, -pymath.sin(angle), pymath.cos(angle))
|
||||
|
||||
|
||||
def add_shell_segment(name, radius, half_length, thickness, material, angle_steps=144, x_steps=8, start_angle=FULL_START, end_angle=FULL_END):
|
||||
import bpy
|
||||
|
||||
|
|
@ -100,7 +85,7 @@ def add_shell_segment(name, radius, half_length, thickness, material, angle_step
|
|||
x = -half_length + (2.0 * half_length * ix / x_steps)
|
||||
for ia in range(angle_steps + 1):
|
||||
a = start_angle + (end_angle - start_angle) * ia / angle_steps
|
||||
verts.append((x, radius * pymath.cos(a), radius * pymath.sin(a)))
|
||||
verts.append(cyl_point(x, a, radius))
|
||||
for ix in range(x_steps):
|
||||
for ia in range(angle_steps):
|
||||
row = angle_steps + 1
|
||||
|
|
@ -118,11 +103,6 @@ def add_shell_segment(name, radius, half_length, thickness, material, angle_step
|
|||
return obj
|
||||
|
||||
|
||||
def surface_point(x, angle, radius=INNER_RADIUS, lift=-0.04):
|
||||
r = radius + lift
|
||||
return (x, r * pymath.cos(angle), r * pymath.sin(angle))
|
||||
|
||||
|
||||
def add_surface_patch(name, x0, x1, a0, a1, radius, material, lift=-0.045, angle_steps=8, x_steps=3):
|
||||
import bpy
|
||||
|
||||
|
|
@ -177,68 +157,6 @@ def add_surface_block_field(name, x_values, angles, material, size, radial_lift=
|
|||
)
|
||||
|
||||
|
||||
def append_box_parts(verts, faces, loc, axes, size):
|
||||
from mathutils import Vector
|
||||
|
||||
origin = Vector(loc)
|
||||
ax = [Vector(axis).normalized() for axis in axes]
|
||||
sx, sy, sz = (value * 0.5 for value in size)
|
||||
base = len(verts)
|
||||
for dx, dy, dz in [
|
||||
(-sx, -sy, -sz),
|
||||
(sx, -sy, -sz),
|
||||
(sx, sy, -sz),
|
||||
(-sx, sy, -sz),
|
||||
(-sx, -sy, sz),
|
||||
(sx, -sy, sz),
|
||||
(sx, sy, sz),
|
||||
(-sx, sy, sz),
|
||||
]:
|
||||
v = origin + ax[0] * dx + ax[1] * dy + ax[2] * dz
|
||||
verts.append((v.x, v.y, v.z))
|
||||
faces.extend(
|
||||
[
|
||||
(base + 0, base + 1, base + 2, base + 3),
|
||||
(base + 4, base + 7, base + 6, base + 5),
|
||||
(base + 0, base + 4, base + 5, base + 1),
|
||||
(base + 1, base + 5, base + 6, base + 2),
|
||||
(base + 2, base + 6, base + 7, base + 3),
|
||||
(base + 3, base + 7, base + 4, base + 0),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def add_mesh_parts(name, verts, faces, material):
|
||||
import bpy
|
||||
|
||||
mesh = bpy.data.meshes.new(name + "Mesh")
|
||||
mesh.from_pydata(verts, [], faces)
|
||||
mesh.update()
|
||||
obj = bpy.data.objects.new(name, mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
obj.data.materials.append(material)
|
||||
return obj
|
||||
|
||||
|
||||
def add_multi_polyline_curve(name, lines, bevel, material, resolution=2):
|
||||
import bpy
|
||||
|
||||
curve = bpy.data.curves.new(name + "Curve", "CURVE")
|
||||
curve.dimensions = "3D"
|
||||
curve.resolution_u = resolution
|
||||
curve.bevel_depth = bevel
|
||||
curve.bevel_resolution = 2
|
||||
for line in lines:
|
||||
spline = curve.splines.new("POLY")
|
||||
spline.points.add(len(line) - 1)
|
||||
for point, co in zip(spline.points, line):
|
||||
point.co = (co[0], co[1], co[2], 1.0)
|
||||
obj = bpy.data.objects.new(name, curve)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
obj.data.materials.append(material)
|
||||
return obj
|
||||
|
||||
|
||||
def add_surface_stilt(name, x, angle, inner_lift, outer_lift, material, radius=0.009):
|
||||
start = surface_point(x, angle, INNER_RADIUS, lift=inner_lift)
|
||||
end = surface_point(x, angle, INNER_RADIUS, lift=outer_lift)
|
||||
|
|
@ -317,17 +235,6 @@ def add_favela_fractal_cluster(prefix, x_values, angles, mats):
|
|||
add_multi_polyline_curve(prefix + "_brace_and_catwalks", brace_lines, 0.005, mats["brace"], resolution=2)
|
||||
|
||||
|
||||
def append_endcap_ring_band(verts, faces, x, inner_radius, outer_radius, segments=96):
|
||||
base = len(verts)
|
||||
for i in range(segments):
|
||||
a = FULL_START + TAU * i / segments
|
||||
verts.append(cyl_point(x, a, inner_radius))
|
||||
verts.append(cyl_point(x, a, outer_radius))
|
||||
for i in range(segments):
|
||||
j = (i + 1) % segments
|
||||
faces.append((base + i * 2, base + j * 2, base + j * 2 + 1, base + i * 2 + 1))
|
||||
|
||||
|
||||
def add_hubward_endcap_terraced_slums(prefix, x, mats):
|
||||
# Bloom lore frame: on an endcap, "up" is inward toward the axial Spire.
|
||||
# These terraces are not polar graph paper. Fractal noise makes the shelf
|
||||
|
|
@ -345,7 +252,7 @@ def add_hubward_endcap_terraced_slums(prefix, x, mats):
|
|||
outer_r = rings[tier + 1]
|
||||
tier_t = tier / (len(rings) - 2)
|
||||
face_x = x + 0.035 + tier * 0.018
|
||||
append_endcap_ring_band(shelf_verts, shelf_faces, face_x, inner_r, outer_r, segments=160)
|
||||
append_cylindrical_ring_band(shelf_verts, shelf_faces, face_x, inner_r, outer_r, segments=160)
|
||||
count = int(30 + tier * 8 + 18 * fbm_2d(tier * 0.71, 4.0, seed=12))
|
||||
angular_step = TAU / count
|
||||
run = 0
|
||||
|
|
@ -414,7 +321,7 @@ def add_hubward_endcap_terraced_slums(prefix, x, mats):
|
|||
def add_hubward_office_complex(prefix, x, mats):
|
||||
office_verts, office_faces = [], []
|
||||
for i, radius in enumerate((0.42, 0.68, 0.92)):
|
||||
append_endcap_ring_band(office_verts, office_faces, x + 0.18 + i * 0.06, radius, radius + 0.16, segments=96)
|
||||
append_cylindrical_ring_band(office_verts, office_faces, x + 0.18 + i * 0.06, radius, radius + 0.16, segments=96)
|
||||
add_mesh_parts(prefix + "_ring_office_mesh", office_verts, office_faces, mats["hub"])
|
||||
for i, angle in enumerate([pymath.radians(a) for a in range(-150, 181, 30)]):
|
||||
add_cylinder_between(
|
||||
|
|
@ -511,48 +418,6 @@ def add_frame_transfer_artery(name, x, angle, start_radius, end_radius, material
|
|||
return add_curve_polyline(name, samples, bevel, material)
|
||||
|
||||
|
||||
def cyl_point(x, angle, radius):
|
||||
return (x, radius * pymath.cos(angle), radius * pymath.sin(angle))
|
||||
|
||||
|
||||
def smoothstep(t):
|
||||
return t * t * (3.0 - 2.0 * t)
|
||||
|
||||
|
||||
def hash01(ix, iy=0, seed=0):
|
||||
n = ix * 374761393 + iy * 668265263 + seed * 1442695041
|
||||
n = (n ^ (n >> 13)) * 1274126177
|
||||
n = n ^ (n >> 16)
|
||||
return (n & 0xFFFFFFFF) / 0xFFFFFFFF
|
||||
|
||||
|
||||
def value_noise_2d(x, y, seed=0):
|
||||
ix = pymath.floor(x)
|
||||
iy = pymath.floor(y)
|
||||
fx = smoothstep(x - ix)
|
||||
fy = smoothstep(y - iy)
|
||||
a = hash01(ix, iy, seed)
|
||||
b = hash01(ix + 1, iy, seed)
|
||||
c = hash01(ix, iy + 1, seed)
|
||||
d = hash01(ix + 1, iy + 1, seed)
|
||||
ab = a + (b - a) * fx
|
||||
cd = c + (d - c) * fx
|
||||
return ab + (cd - ab) * fy
|
||||
|
||||
|
||||
def fbm_2d(x, y, seed=0, octaves=4):
|
||||
value = 0.0
|
||||
amplitude = 0.5
|
||||
frequency = 1.0
|
||||
total = 0.0
|
||||
for octave in range(octaves):
|
||||
value += value_noise_2d(x * frequency, y * frequency, seed + octave * 19) * amplitude
|
||||
total += amplitude
|
||||
amplitude *= 0.5
|
||||
frequency *= 2.03
|
||||
return value / total if total else 0.0
|
||||
|
||||
|
||||
def add_spiral_spoke_loop(name, x, angle, start_radius, end_radius, material, bevel=0.04, cargo=False):
|
||||
"""Shared cylinder frame: x is axial, angle is shell azimuth, radius is spin radius."""
|
||||
samples = []
|
||||
|
|
@ -615,60 +480,6 @@ def add_endcap_terrace_blocks(prefix, x, radii, angles, material, height=0.18):
|
|||
)
|
||||
|
||||
|
||||
def add_cylinder_between(name, start, end, radius, material, vertices=16):
|
||||
import bpy
|
||||
from mathutils import Vector
|
||||
|
||||
start_v = Vector(start)
|
||||
end_v = Vector(end)
|
||||
mid = (start_v + end_v) / 2.0
|
||||
direction = end_v - start_v
|
||||
length = direction.length
|
||||
bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=length, location=mid)
|
||||
obj = bpy.context.object
|
||||
obj.name = name
|
||||
obj.data.name = name + "Mesh"
|
||||
obj.rotation_euler = direction.to_track_quat("Z", "Y").to_euler()
|
||||
obj.data.materials.append(material)
|
||||
return obj
|
||||
|
||||
|
||||
def add_curve_polyline(name, points, bevel, material, resolution=2):
|
||||
import bpy
|
||||
|
||||
curve = bpy.data.curves.new(name + "Curve", "CURVE")
|
||||
curve.dimensions = "3D"
|
||||
curve.resolution_u = resolution
|
||||
curve.bevel_depth = bevel
|
||||
curve.bevel_resolution = 4
|
||||
spline = curve.splines.new("POLY")
|
||||
spline.points.add(len(points) - 1)
|
||||
for point, co in zip(spline.points, points):
|
||||
point.co = (co[0], co[1], co[2], 1.0)
|
||||
obj = bpy.data.objects.new(name, curve)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
obj.data.materials.append(material)
|
||||
return obj
|
||||
|
||||
|
||||
def add_box(name, loc, axes, size, material):
|
||||
import bpy
|
||||
from mathutils import Matrix, Vector
|
||||
|
||||
bpy.ops.mesh.primitive_cube_add(size=1.0, location=loc)
|
||||
obj = bpy.context.object
|
||||
obj.name = name
|
||||
obj.dimensions = size
|
||||
matrix = Matrix.Identity(4)
|
||||
matrix.col[0].xyz = Vector(axes[0]).normalized()
|
||||
matrix.col[1].xyz = Vector(axes[1]).normalized()
|
||||
matrix.col[2].xyz = Vector(axes[2]).normalized()
|
||||
obj.rotation_euler = matrix.to_euler()
|
||||
obj.data.materials.append(material)
|
||||
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
|
||||
return obj
|
||||
|
||||
|
||||
def add_label(name, text, loc, size, material):
|
||||
import bpy
|
||||
|
||||
|
|
@ -696,13 +507,6 @@ def add_gn_light_spine(material):
|
|||
return obj
|
||||
|
||||
|
||||
def aim_camera(obj, target):
|
||||
from mathutils import Vector
|
||||
|
||||
direction = Vector(target) - obj.location
|
||||
obj.rotation_euler = direction.to_track_quat("-Z", "Y").to_euler()
|
||||
|
||||
|
||||
def build_scene():
|
||||
import bpy
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue