save startup blend for animation tab & whatnot
This commit is contained in:
2026-04-08 12:10:18 -06:00
parent 57a652524a
commit 692e200ffe
180 changed files with 12336 additions and 3431 deletions
@@ -31,6 +31,7 @@ if "bpy" in locals():
importlib.reload(add_mesh_menger_sponge)
importlib.reload(add_mesh_vertex)
importlib.reload(add_empty_as_parent)
importlib.reload(add_mesh_equilateral_grid)
importlib.reload(add_mesh_beam_builder)
importlib.reload(Blocks)
importlib.reload(Wallfactory)
@@ -59,6 +60,7 @@ else:
from . import Wallfactory
from . import add_mesh_triangles
from . import preferences
from . import add_mesh_equilateral_grid
from .add_mesh_rocks import __init__
from .add_mesh_rocks import rockgen
@@ -154,6 +156,7 @@ class VIEW3D_MT_mesh_extras_add(Menu):
oper.change = False
oper = layout.operator("mesh.primitive_teapot_add", text="Teapot+")
oper = layout.operator("mesh.menger_sponge_add", text="Menger Sponge")
oper = layout.operator("mesh.add_equilateral_grid", text="Equilateral Grid")
class VIEW3D_MT_mesh_torus_add(Menu):
@@ -209,7 +212,7 @@ def menu_func(self, context):
if prefs.show_single_vert:
layout.menu("VIEW3D_MT_mesh_vert_add", text="Single Vert", icon='DECORATE')
if prefs.show_torus_objects:
layout.menu("VIEW3D_MT_mesh_torus_add", text="Torus Objects", icon='MESH_TORUS')
@@ -218,7 +221,7 @@ def menu_func(self, context):
if prefs.show_gears:
layout.menu("VIEW3D_MT_mesh_gears_add", text="Gears", icon='PREFERENCES')
if prefs.show_pipe_joints:
layout.menu("VIEW3D_MT_mesh_pipe_joints_add", text="Pipe Joints", icon='IPO_CONSTANT')
@@ -409,6 +412,7 @@ classes = [
add_mesh_menger_sponge.AddMengerSponge,
add_mesh_vertex.AddVert,
add_mesh_vertex.AddEmptyVert,
add_mesh_equilateral_grid.MESH_OT_add_equilateral_grid,
add_mesh_vertex.AddSymmetricalEmpty,
add_mesh_vertex.AddSymmetricalVert,
add_empty_as_parent.P2E,
@@ -0,0 +1,270 @@
# SPDX-FileCopyrightText: 2026 Blender Foundation
#
# SPDX-License-Identifier: GPL-3.0-or-later
# Author: Luis-Lerga
import bpy
import bmesh
from math import sqrt
from bpy_extras import object_utils
class MESH_OT_add_equilateral_grid(bpy.types.Operator):
"""Add an equilateral triangular grid with hexagonal pattern"""
bl_idname = "mesh.add_equilateral_grid"
bl_label = "Add Equilateral Grid"
bl_options = {'REGISTER', 'UNDO'}
# Dimensions
width: bpy.props.FloatProperty(
name="Width",
description="Horizontal width of the rectangle",
default=10.0,
min=0.1,
max=100.0,
step=100,
precision=2,
unit='LENGTH'
)
height: bpy.props.FloatProperty(
name="Height",
description="Vertical height of the rectangle",
default=10.0,
min=0.1,
max=100.0,
step=100,
precision=2,
unit='LENGTH'
)
density: bpy.props.IntProperty(
name="Density",
description="Number of horizontal segments",
default=20,
min=4,
max=200,
step=1
)
# UVs
use_uv: bpy.props.BoolProperty(
name="Generate UVs",
description="Generate UV coordinates for the mesh",
default=True
)
# Alignment
align: bpy.props.EnumProperty(
name="Align",
description="Mesh alignment orientation",
items=[
('WORLD', "World", "Align to world origin"),
('VIEW', "View", "Align to current view"),
('CURSOR', "3D Cursor", "Align to 3D cursor position"),
],
default='WORLD'
)
# Transformations
location: bpy.props.FloatVectorProperty(
name="Location",
description="Object location",
subtype='TRANSLATION',
default=(0.0, 0.0, 0.0),
unit='LENGTH'
)
rotation: bpy.props.FloatVectorProperty(
name="Rotation",
description="Object rotation (Euler XYZ)",
subtype='EULER',
default=(0.0, 0.0, 0.0),
unit='ROTATION'
)
def execute(self, context):
# Create geometry & mesh.
verts, faces = self.create_geometry(context)
mesh = bpy.data.meshes.new("Equilateral Grid")
mesh.from_pydata(verts, [], faces)
mesh.update()
# Clean-up.
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(mesh)
bm.free()
# Generate UVs.
if self.use_uv:
self.generate_uvs(mesh)
# Create an object.
obj = object_utils.object_data_add(context, mesh, operator=self)
if context.preferences.edit.use_enter_edit_mode:
bpy.ops.object.mode_set(mode = 'EDIT')
return {'FINISHED'}
def create_geometry(self, context):
"""Generate geometry with equilateral triangles and perfect rectangular borders"""
L = self.width / self.density
tri_height = L * sqrt(3) / 2
# Calculate EVEN number of triangle rows for straight top/bottom borders
target_rows = self.height / tri_height
rows = int(round(target_rows / 2.0)) * 2 # Always even
rows = max(2, rows)
# Actual adjusted dimensions
actual_width = self.density * L
actual_height = rows * tri_height
# === Generate vertices WITHOUT protruding vertices ===
verts = []
row_offsets = [] # Track starting index of each row
for row in range(rows + 1): # rows+1 vertex rows
y = -actual_height / 2 + row * tri_height
row_offsets.append(len(verts))
if row % 2 == 0:
# Even rows: density+1 vertices spanning full width
num_verts = self.density + 1
offset = 0.0
else:
# Odd rows: density vertices (NO protruding vertex)
num_verts = self.density
offset = L * 0.5
for col in range(num_verts):
x = -actual_width / 2 + col * L + offset
verts.append((x, y, 0.0))
# === Generate interior faces (equilateral triangles) ===
faces = []
for row in range(rows):
if row % 2 == 0:
# Even row → next row is odd (fewer vertices)
for col in range(self.density):
i00 = row_offsets[row] + col
i01 = i00 + 1
i10 = row_offsets[row + 1] + col
i11 = i10 + 1 if col < self.density - 1 else None
faces.append((i00, i10, i01))
if i11 is not None:
faces.append((i01, i10, i11))
else:
# Odd row → next row is even (more vertices)
for col in range(self.density):
i00 = row_offsets[row] + col
i01 = i00 + 1 if col < self.density - 1 else None
i10 = row_offsets[row + 1] + col
i11 = i10 + 1
if i01 is not None:
faces.append((i00, i11, i01))
faces.append((i00, i10, i11))
# === Fill LEFT/RIGHT borders for odd rows ===
for row in range(1, rows, 2): # Only odd rows (1, 3, 5...)
y = -actual_height / 2 + row * tri_height
# Add LEFT border vertex at exact x = -width/2
left_idx = len(verts)
verts.append((-actual_width / 2, y, 0.0))
# Add RIGHT border vertex at exact x = +width/2
right_idx = len(verts)
verts.append((actual_width / 2, y, 0.0))
# Connect LEFT border vertex
base_idx = row_offsets[row]
above_idx = row_offsets[row - 1] # Even row above
below_idx = row_offsets[row + 1] # Even row below
# Upper triangle: left border → first interior → vertex above first interior
faces.append((left_idx, base_idx, above_idx))
# Lower triangle: left border → vertex below first interior → first interior
faces.append((left_idx, below_idx, base_idx))
# Connect RIGHT border vertex
last_interior = base_idx + self.density - 1
above_last = above_idx + self.density # Last vertex of even row above
below_last = below_idx + self.density # Last vertex of even row below
# Upper triangle: right border → last interior → vertex above last interior
faces.append((right_idx, last_interior, above_last))
# Lower triangle: right border → vertex below last interior → last interior
faces.append((right_idx, below_last, last_interior))
return verts, faces
def generate_uvs(self, mesh):
"""Generate simple 0-1 UV coordinates based on X,Y coordinates"""
if not mesh.uv_layers:
mesh.uv_layers.new(name="UVMap")
uv_layer = mesh.uv_layers.active.data
# Calculate bounds for normalization
xs = [v.co.x for v in mesh.vertices]
ys = [v.co.y for v in mesh.vertices]
min_x, max_x = min(xs), max(xs)
min_y, max_y = min(ys), max(ys)
width = max_x - min_x or 1.0
height = max_y - min_y or 1.0
# Assign UVs
for poly in mesh.polygons:
for loop_idx in poly.loop_indices:
vert_idx = mesh.loops[loop_idx].vertex_index
v = mesh.vertices[vert_idx].co
uv = (
(v.x - min_x) / width,
(v.y - min_y) / height
)
uv_layer[loop_idx].uv = uv
def draw(self, context):
"""Draw the options panel in the dialog"""
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
# Dimensions
layout.label(text="Dimensions:")
col = layout.column(align=True)
col.prop(self, "width")
col.prop(self, "height")
col.prop(self, "density")
# Additional options
layout.separator()
layout.prop(self, "use_uv")
layout.prop(self, "align")
# Transformations
layout.separator()
col = layout.column(align=True)
col.prop(self, "location", text="Location X", index=0)
col.prop(self, "location", text="Y", index=1)
col.prop(self, "location", text="Z", index=2)
col = layout.column(align=True)
col.prop(self, "rotation", text="Rotation X", index=0)
col.prop(self, "rotation", text="Y", index=1)
col.prop(self, "rotation", text="Z", index=2)
@@ -1,7 +1,7 @@
schema_version = "1.0.0"
id = "extra_mesh_objects"
name = "Extra Mesh Objects"
version = "0.4.0"
version = "0.4.1"
tagline = "Add extra mesh object types"
maintainer = "Community"
type = "add-on"