Skip to content

Instantly share code, notes, and snippets.

View semagnum's full-sized avatar
🎯
Focusing

Spencer Magnusson semagnum

🎯
Focusing
View GitHub Profile
@semagnum
semagnum / raytracer.py
Last active July 18, 2022 18:20
Ray tracing Blender objects from the camera
import numpy as np
from mathutils import Vector
import bpy
def occlusion_test(scene, depsgraph, camera, resolution_x, resolution_y):
# get vectors which define view frustum of camera
top_right, _, bottom_left, top_left = camera.data.view_frame(scene=scene)
camera_quaternion = camera.matrix_world.to_quaternion()
@semagnum
semagnum / coverage.ps1
Last active October 16, 2021 21:04
Reads a pytest coverage xml file and gets the total coverage percentage, ignoring packages or classes based on regex
$coverageFilePath = "coverage.xml"
$matchPackagePattern = "nViewAddon"
$ignoreClassPatternList = @("__init__", "panel")
$ignoreClassPattern = $ignoreClassPatternList -join "|"
if (-not (Test-Path $coverageFilePath)) {
Write-Error "Cannot find coverage report: $coverageFilePath"
return
}
@semagnum
semagnum / test_prop.py
Created October 22, 2021 23:44
Pytest to ensure that every declared property is properly deleted
def test_variables_declared_deleted():
import re
declaration_re = r"\s*(\w+\.?)+\s+=\s+[\w\d\.]+Property\("
deletion_re = r"\s*del\s+(\w+\.?)+"
init_file = open(path_to_addon_init, 'r')
deletion_vars = []
declaration_vars = []
while True:
line = init_file.readline()
@semagnum
semagnum / interior_vertex_select.py
Created October 24, 2021 22:16
Select vertices within a given object
import bpy
import bmesh
# source: https://blender.stackexchange.com/questions/177559/select-vertices-within-a-given-object/241467#241467
# must create an object with many interior points (apply a array modifer on a cube 3 times)
# create another object (here named "Sphere") to be the hull
# go into edit mode for the first object
def is_inside(p, max_dist, obj):
result, point, normal, face = obj.closest_point_on_mesh(p, distance=max_dist) # you weren't using max_dist in yours, is that intentional?
@semagnum
semagnum / SJ.py
Created October 25, 2021 22:17
Save sets of selections and recall them when needed
import bpy
import collections
import json
def select_current_selset(self, context):
"""Selection"""
if len(context.scene.sj_sel_set_items) is 0:
return None
@semagnum
semagnum / view_frustrum_cull.py
Created November 4, 2021 02:35
Culls objects whose bounding boxes are not intersecting or within camera frustrum
from mathutils.geometry import normal
from mathutils import Vector
from bpy import context
def camera_as_planes(scene, obj):
"""
Return planes in world-space which represent the camera view bounds.
"""
camera = obj.data
@semagnum
semagnum / bpy_text_wrap.py
Created November 12, 2021 20:29
text wrap for Blender UI panels (credit to Graswald3d in his G Scatter addon)
import blf
import bpy
def wrap_text(text: str, context):
return_text = []
row_text = ''
width = context.region.width
system = context.preferences.system
ui_scale = system.ui_scale
@semagnum
semagnum / instance_generators.py
Created January 20, 2022 15:18
Utility functions to iterate over collections and related instanced collections
def coll_iter(curr_coll):
"""
Iterate through hierarchy of collections
:param curr_coll: current collection
:return: generator of collections
"""
yield curr_coll
for child in curr_coll.children:
yield from coll_iter(child)
@semagnum
semagnum / build.py
Last active April 9, 2023 12:07
Zips a Blender add-on, using the version as part of the filename
import ast
import os
import zipfile
allowed_file_extensions = {'.py', '.md', 'LICENSE'}
exclude_folders = {'doc', 'venv', '.git', '.idea'}
def zipdir(path, ziph: zipfile.ZipFile, zip_subdir_name):
for root, dirs, files in os.walk(path):
@semagnum
semagnum / Flowmap generator.py
Created December 30, 2022 19:16
From painted vertex color attributes, create an RGB flowmap that shows the "flow" of colors
import bpy
import bmesh
from mathutils import Vector
obj = bpy.context.active_object
me = obj.data
# cannot access color attributes within bmesh,
# so we will create a dict of indices to access the linked edges in object mode
bpy.ops.object.mode_set(mode='EDIT')