Skip to content

Instantly share code, notes, and snippets.

@binitshah
Created October 4, 2019 18:08
Show Gist options
  • Save binitshah/34a8979c00fdde0845b819473f084ce2 to your computer and use it in GitHub Desktop.
Save binitshah/34a8979c00fdde0845b819473f084ce2 to your computer and use it in GitHub Desktop.
Downloads a model from Blender, performs subdivisions on it, and send it back to Blender
import bpy
cam = bpy.data.objects['Camera']
model = bpy.data.objects['model']
step_count = 1
Class SubdivisionModel:
def __init__(vertices):
self._vertices = vertices
self._quads = []
def subdivide(self):
# A list of the new quads we will be creating. We will replace the old quads
# with these when we're done
newQuads = []
# These data-structures will hold the intermediary vertices for edge midpoints
# and face centers. We will need ready access to these after we generate them
edgeMids = {}
quadCtrList = []
oldVertexCount = len(self._vertices)
# STEP ONE: Generate face points
# -----------------------------------------------------------
for quadVerts in self._quads:
polyCount = len(quadVerts)
# create the center point
ctr = vec3(0, 0, 0)
for idx in quadVerts:
ctr = ctr.add(self._vertices[idx])
ctr = ctr.div_f(polyCount)
centerIdx = self.addVertex(ctr)
quadCtrList.append(centerIdx)
# STEP TWO: Generate edge points
# -----------------------------------------------------------
for curQuad, quadVerts in enumerate(self._quads, 0):
polyCount = len(quadVerts)
# create center points for every edge
for quadIdx in range(polyCount):
idx = quadVerts[quadIdx]
idx2 = quadVerts[(quadIdx+1) % polyCount]
# For sanity/indexing sake, we always want idx < idx2
if idx > idx2:
tmp = idx
idx = idx2
idx2 = tmp
# if we don't have an entry, add one
if not idx in edgeMids.keys():
edgeMids[idx] = {}
# if we haven't already created this edge midpoint while working
# on another quad, then build it
if not idx2 in edgeMids[idx]:
# The new edge midpoints will be an average of the terminal vertices as well
# as the new face points in the quads this edge straddles
# First, find those quads
connectedQuads = self.quadsContain(idx, idx2)
assert len(connectedQuads) == 2
avg = self.midpoint(idx, idx2, quadCtrList[connectedQuads[0]], quadCtrList[connectedQuads[1]])
edgeMids[idx][idx2] = self.addVertex(avg)
# STEP THREE: Modify the existing vertices
# -----------------------------------------------------------
for idx in range(oldVertexCount):
# Modify original edge point according to complex system. Mark it as done
connectedQuads = self.quadsContain(idx)
n = float(len(connectedQuads))
# M1: Generate old coord weight
m1 = self._vertices[idx]
# M2: Generate average face points weight
m2 = self.midpoint(*[quadCtrList[quadIdx] for quadIdx in connectedQuads])
# M3: Generate average edge points weight
connectedVertIndices = self.connectedVerts(idx)
connectedEdgeMids = []
# Given all vertices that have edges connecting to this current vertex,
# find and average all of the midpoints
for connectedVertIdx in connectedVertIndices:
# Again, index using the smaller vert index value first
if idx < connectedVertIdx:
cIdx1 = idx
cIdx2 = connectedVertIdx
else:
cIdx1 = connectedVertIdx
cIdx2 = idx
connectedEdgeMids.append(edgeMids[cIdx1][cIdx2])
m3 = self.midpoint(*connectedEdgeMids)
# Weights (for easy modification)
# There are many methods of weighing the various elements
# Technique 1
#w1 = (n - 3.0) / n
#w2 = 1.0 / n
#w3 = 2.0 / n
# Technique 2
w1 = (n - 2.5) / n
w2 = 1.0 / n
w3 = 1.5 / n
# Technique 3
#w1 = ((4.0 * n) - 7.0) / (4.0 * n)
#w2 = 1.0 / (4.0 * (n * n))
#w3 = 1.0 / (2.0 * (n * n))
m1 = m1.mul_f(w1)
m2 = m2.mul_f(w2)
m3 = m3.mul_f(w3)
self._vertices[idx] = m1.add(m2).add(m3)
# STEP FOUR: Create new quads
# -----------------------------------------------------------
for curQuad, quadVerts in enumerate(self._quads, 0):
polyCount = len(quadVerts)
# create four new quads in the new quad data-structure
for quadIdx in range(len(quadVerts)):
idx0 = quadVerts[(quadIdx-1) % polyCount]
idx1 = quadVerts[quadIdx]
idx2 = quadVerts[(quadIdx+1) % polyCount]
if idx0 < idx1:
mpoint1 = edgeMids[idx0][idx1]
else:
mpoint1 = edgeMids[idx1][idx0]
if idx1 < idx2:
mpoint2 = edgeMids[idx1][idx2]
else:
mpoint2 = edgeMids[idx2][idx1]
centerIdx = quadCtrList[curQuad]
newQuads.append([centerIdx, mpoint1, idx1, mpoint2])
# STEP FIVE: Rebuild quads
# -----------------------------------------------------------
self._quads = []
for quad in newQuads:
self.addQuad(*quad)
if __name__ == "__main__":
vertices = model.getVertices()
ss = SubdivisionModel(vertices)
for _ in range(step_count):
ss.subdivide()
model.data.vertices = ss._vertices
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment