Created
October 4, 2019 18:08
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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