def border(left, right, start, gapy, end, height, randheight, gaptrans, randgaptrans, lengthparquet, translatey): height = randheight * randuni(0, height) # Add randomness to the height of the boards gaptrans = gaptrans + (randgaptrans * randuni(0, gaptrans)) tdogapy = gapy tupgapy = gapy if end + tupgapy > lengthparquet: tupgapy = (lengthparquet - end) tipdown = start - tdogapy / 2 + gaptrans tipup = end + tupgapy / 2 - gaptrans if tipup < end: tipup = end if tipdown < 0: tipdown = 0 elif tipdown > start: tipdown = start td = Vector(((left + right) / 2, tipdown, height)) # Tip down tdl = Vector((left, start, height)) # Tip down left tup = Vector((left, end, height)) # Tip up left tu = Vector(((left + right) / 2, tipup, height)) # Tip up tur = Vector((right, end, height)) # Tip up right tdr = Vector((right, start, height)) # Tip down right verts = (td, tdl, tup, tu, tur, tdr) return verts
def border(left, right, start, gapy, end, height, randheight, gaptrans, randgaptrans, lengthparquet, translatey): height = randheight * randuni( 0, height) # Add randomness to the height of the boards gaptrans = gaptrans + (randgaptrans * randuni(0, gaptrans)) tdogapy = gapy tupgapy = gapy if end + tupgapy > lengthparquet: tupgapy = (lengthparquet - end) tipdown = start - tdogapy / 2 + gaptrans tipup = end + tupgapy / 2 - gaptrans if tipup < end: tipup = end if tipdown < 0: tipdown = 0 elif tipdown > start: tipdown = start td = Vector(((left + right) / 2, tipdown, height)) # Tip down tdl = Vector((left, start, height)) # Tip down left tup = Vector((left, end, height)) # Tip up left tu = Vector(((left + right) / 2, tipup, height)) # Tip up tur = Vector((right, end, height)) # Tip up right tdr = Vector((right, start, height)) # Tip down right verts = (td, tdl, tup, tu, tur, tdr) return verts
def planks(n, m, length, lengthvar, width, widthvar, longgap, shortgap, offset, randomoffset, nseed, randrotx, randroty, randrotz): #n=Number of planks, m=Floor Length, length = Planklength verts = [] faces = [] shortedges = [] longedges = [] seed(nseed) widthoffset = 0 s = 0 e = offset c = offset # Offset per row ws = 0 p = 0 while p < n: p += 1 w = width + randuni(0, widthvar) we = ws + w if randomoffset: e = randuni(4 * shortgap, length) # we don't like negative plank lengths while (m - e) > (4 * shortgap): ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, e, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = e e += length + randuni(0, lengthvar) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, m, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = 0 #e = e - m if c <= (length): c = c + offset if c > (length): c = c - length e = c ws = we return verts, faces, shortedges, longedges
def interval(left, right, start, translatex, gapy, end, height, randheight, width, gapx, gaptrans, borders, endfloor, tilt, shifty): height = randheight * randuni( 0, height) # Add randomness to the height of the boards if gaptrans == gapx: bgap = 0 else: bgap = gaptrans if shifty == 0 and borders and tilt == 0: tipleft = left - gapx / 2 + bgap tipright = right + gapx / 2 - bgap if tipleft < 0: tipleft = 0 # Constrain the first left tip to 0... elif tipleft > left: tipleft = left # ...and the other to the left of the board if tipright < right: tipright = right # Constrain the right tips to the right of the board.. if endfloor > 0: tipright = endfloor # ...and the last one to the last board of the floor dr = Vector((right, start, height)) # Down right dl = Vector((left, start, height)) # Down left tl = Vector((tipleft, start + (width / 2), height)) # Tip left ul = Vector((left, end, height)) # Up left ur = Vector((right, end, height)) # Up right tr = Vector((tipright, start + (width / 2), height)) # Tip right verts = (dr, dl, tl, ul, ur, tr) else: dr = Vector((right + translatex, start, height)) # Down right dl = Vector((left + translatex, start, height)) # Down left ul = Vector((left + translatex, end, height)) # Up left ur = Vector((right + translatex, end, height)) # Up right verts = (dl, ul, ur, dr) return verts
def interval(left, right, start, translatex, gapy, end, height, randheight, width, gapx, gaptrans, borders, endfloor, tilt, shifty): height = randheight * randuni(0, height) # Add randomness to the height of the boards if gaptrans == gapx: bgap = 0 else: bgap = gaptrans if shifty == 0 and borders and tilt == 0: tipleft = left-gapx/2+bgap tipright = right+gapx/2-bgap if tipleft < 0: tipleft = 0 # Constrain the first left tip to 0... elif tipleft > left: tipleft = left # ...and the other to the left of the board if tipright < right: tipright = right # Constrain the right tips to the right of the board.. if endfloor > 0 : tipright = endfloor # ...and the last one to the last board of the floor dr = Vector((right, start, height)) # Down right dl = Vector((left, start, height)) # Down left tl = Vector((tipleft, start+(width/2), height)) # Tip left ul = Vector((left, end, height)) # Up left ur = Vector((right, end, height)) # Up right tr = Vector((tipright, start+(width/2), height)) # Tip right verts = (dr, dl, tl, ul, ur, tr) else: dr = Vector((right + translatex, start, height)) # Down right dl = Vector((left + translatex, start, height)) # Down left ul = Vector((left + translatex, end, height)) # Up left ur = Vector((right + translatex, end, height)) # Up right verts = (dl, ul, ur, dr) return verts
def planks(n, m, length, lengthvar, width, widthvar, longgap, shortgap, offset, randomoffset, nseed, randrotx, randroty, randrotz): #n=Number of planks, m=Floor Length, length = Planklength verts = [] faces = [] shortedges = [] longedges = [] seed(nseed) widthoffset = 0 s = 0 e = offset c = offset # Offset per row ws = 0 p = 0 while p < n: p += 1 w = width + randuni(0, widthvar) we = ws + w if randomoffset: e = randuni( 0, length ) # I think we should change length into offset. That way we have indepent control of of the offset variation while e < m: ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, e, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = e e += length + randuni(0, lengthvar) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, m, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = 0 #e = e - m if c <= (length): c = c + offset if c > (length): c = c - length e = c ws = we return verts, faces, shortedges, longedges
def transversal(left, right, start, tilt, translatex, gapy, gapx, gaptrans, randgaptrans, end, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty): gaptrans = gaptrans + ( randgaptrans * randuni(0, gaptrans) ) # Add randomness to the gap of the transversal of the boards if borders: nbrtrans = 1 # Constrain the transversal to 1 board if borders activate if gaptrans < (end - start) / ( nbrtrans + 1): # The gap can't be > to the width of the interval x = 0 lengthint = 0 if tilt > 0: translatex = 0 # Constrain the board to 0 on the x axis width = ((end - start) - (gaptrans * (nbrtrans + 1))) * ( 1 / nbrtrans) # Width of 1 board in the interval startint = start + gaptrans # Find the start of the first board while right > lengthint: # While the transversal is < to the right edge of the floor (if unlock) or the board (if locked) if locktrans: # If the length of the transversal is unlock lengthint += lengthtrans # Add the length if not locktrans or (lengthint > right): lengthint = right # Constrain the length of the transversal to th length of the board (locked) while x < nbrtrans: # Nbr of boards in the transversal x += 1 endtrans = startint + width # Find the end of the board # Create the boards in the interval nbvert = len(verts) verts.extend( interval(left, lengthint, startint, translatex, gapy, endtrans, height, randheight, width, gapx, gaptrans, borders, endfloor, tilt, shifty)) if shifty == 0 and borders and tilt == 0: faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3, nbvert + 4, nbvert + 5)) else: faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3)) startint = endtrans + gaptrans # Find the start of the next board #------------------------------------------------------------ # Increment / initialize #------------------------------------------------------------ if locktrans: left = lengthint + gaptrans lengthint += gaptrans x = 0 endtrans = start + width startint = start + gaptrans # The boards can't be > to the length of the floor if left > right: lengthint = left
def planks(n, m, length, lengthvar, width, widthvar, longgap, shortgap, offset, randomoffset, nseed, randrotx, randroty, randrotz): #n=Number of planks, m=Floor Length, length = Planklength verts = [] faces = [] shortedges = [] longedges = [] seed(nseed) widthoffset = 0 s = 0 e = offset c = offset # Offset per row ws = 0 p = 0 while p < n: p += 1 w = width + randuni(0, widthvar) we = ws + w if randomoffset: e = randuni(0, length) # I think we should change length into offset. That way we have indepent control of of the offset variation while e < m: ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, e, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = e e += length + randuni(0, lengthvar) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') verts.extend(plank(s, m, ws, we, longgap, shortgap, rot)) faces.append((ll, ll + 1, ll + 2, ll + 3)) shortedges.extend([(ll, ll + 1), (ll + 2, ll + 3)]) longedges.extend([(ll + 1, ll + 2), (ll + 3, ll)]) s = 0 #e = e - m if c <= (length): c = c + offset if c > (length): c = c - length e = c ws = we return verts, faces, shortedges, longedges
def herringbone(rows, cols, planklength, plankwidth, longgap, shortgap, nseed, randrotx, randroty, randrotz, originx, originy): verts = [] faces = [] uvs = [] seed(nseed) ll=0 longside = (planklength-shortgap)/sqrt(2.0) shortside = (plankwidth-longgap)/sqrt(2.0) vstep = Vector((0,plankwidth * sqrt(2.0),0)) hstepl = Vector((planklength * sqrt(2.0),0,0)) hstep = Vector((planklength/sqrt(2.0)-(plankwidth-longgap)/sqrt(2.0),planklength/sqrt(2.0)+(plankwidth-longgap)/sqrt(2.0),0)) dy = Vector((0,-planklength/sqrt(2.0),0)) pu = [Vector((0,0,0)),Vector((longside,0,0)),Vector((longside,shortside,0)),Vector((0,shortside,0))] pv = [Vector((0,0,0)),Vector((longside,longside,0)),Vector((longside-shortside,longside+shortside,0)),Vector((-shortside,shortside,0))] rot = Euler((0,0,-PI/2),"XYZ") pvm = [rotate(v, rot)+hstep for v in pv] midpointpv = sum(pv,Vector())/4.0 midpointpvm = sum(pvm,Vector())/4.0 o = Vector((-originx, -originy, 0)) midpointpvo = midpointpv - o midpointpvmo = midpointpvm - o for col in range(cols): for row in range(rows): # CLEANUP: this could be shorter: for P in pv,pvm rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pvo = [ v + o for v in pv] pverts = [rotate(v - midpointpvo, rot) + midpointpvo + row * vstep + col * hstepl + dy for v in pvo] verts.extend(deepcopy(pverts)) uvs.append([v + Vector((col*2*longside,row*shortside,0)) for v in pu]) faces.append((ll, ll + 1, ll + 2, ll + 3)) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pvmo = [ v + o for v in pvm] pverts = [rotate(v - midpointpvmo, rot) + midpointpvmo + row * vstep + col * hstepl + dy for v in pvmo] verts.extend(deepcopy(pverts)) uvs.append([v + Vector(((1+col*2)*longside,row*shortside,0)) for v in pu]) faces.append((ll, ll + 1, ll + 2, ll + 3)) ll = len(verts) for i in range(len(uvs)): pp1 = randrange(len(uvs)) pp2 = randrange(len(uvs)) swap(uvs,pp1,pp2) fuvs = [v for p in uvs for v in p] return verts, faces, fuvs
def board(start, left, right, end, tilt, translatex, hyp, herringbone, gapy, height, randheight): gapx = 0 height = randheight * randuni( 0, height) # Add randomness to the height of the boards if not herringbone: gapy = 0 if tilt > 0: # / / / -> 1 board, 3 board, 5 board... shiftdown = translatex shiftup = 0 if herringbone: gapy = gapy / 2 gapx = 0 else: # \ \ \-> 2 board, 4 board, 6 board... shiftdown = 0 shiftup = -translatex if herringbone: gapy = gapy / 2 gapx = gapy * 2 dl = Vector( (left + shiftdown + gapx, start - gapy, height)) # down left [0,0,0] dr = Vector( (right + shiftdown + gapx, start - gapy, height)) # down right [1,0,0] ur = Vector( (right - shiftup + gapx, end - gapy, height)) # up right [1,1,0] ul = Vector((left - shiftup + gapx, end - gapy, height)) # up left [0,1,0] if herringbone: if tilt > 0: # / / / -> 1 board, 3 board, 5 board... ur[0] = ur[0] - (hyp / 2) ur[1] = ur[1] + (hyp / 2) dr[0] = dr[0] - (hyp / 2) dr[1] = dr[1] + (hyp / 2) else: # \ \ \-> 2 board, 4 board, 6 board... dl[0] = dl[0] + (hyp / 2) dl[1] = dl[1] + (hyp / 2) ul[0] = ul[0] + (hyp / 2) ul[1] = ul[1] + (hyp / 2) verts = (dl, ul, ur, dr) return (verts)
def transversal(left, right, start, tilt, translatex, gapy, gapx, gaptrans, randgaptrans, end, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty): gaptrans = gaptrans + (randgaptrans * randuni(0, gaptrans)) # Add randomness to the gap of the transversal of the boards if borders: nbrtrans = 1 # Constrain the transversal to 1 board if borders activate if gaptrans < (end - start) / (nbrtrans + 1): # The gap can't be > to the width of the interval x = 0 lengthint = 0 if tilt > 0: translatex = 0 # Constrain the board to 0 on the x axis width = ((end - start) - (gaptrans * (nbrtrans + 1))) * (1 / nbrtrans) # Width of 1 board in the interval startint = start + gaptrans # Find the start of the first board while right > lengthint: # While the transversal is < to the right edge of the floor (if unlock) or the board (if locked) if locktrans: # If the length of the transversal is unlock lengthint += lengthtrans # Add the length if not locktrans or (lengthint > right): lengthint = right # Constrain the length of the transversal to th length of the board (locked) while x < nbrtrans: # Nbr of boards in the transversal x += 1 endtrans = startint + width # Find the end of the board # Create the boards in the interval nbvert = len(verts) verts.extend(interval(left, lengthint, startint, translatex, gapy, endtrans, height, randheight, width, gapx, gaptrans, borders, endfloor, tilt, shifty)) if shifty == 0 and borders and tilt == 0: faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3, nbvert + 4, nbvert + 5)) else: faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3)) startint = endtrans + gaptrans # Find the start of the next board #------------------------------------------------------------ # Increment / initialize #------------------------------------------------------------ if locktrans: left = lengthint + gaptrans lengthint += gaptrans x = 0 endtrans = start + width startint = start + gaptrans # The boards can't be > to the length of the floor if left > right: lengthint = left
def board(start, left, right, end, tilt, translatex, hyp, herringbone, gapy, height, randheight): gapx = 0 height = randheight * randuni(0, height) # Add randomness to the height of the boards if not herringbone: gapy = 0 if tilt > 0: # / / / -> 1 board, 3 board, 5 board... shiftdown = translatex shiftup = 0 if herringbone: gapy = gapy / 2 gapx = 0 else: # \ \ \-> 2 board, 4 board, 6 board... shiftdown = 0 shiftup = -translatex if herringbone: gapy = gapy / 2 gapx = gapy * 2 dl = Vector((left + shiftdown + gapx, start - gapy, height)) # down left [0,0,0] dr = Vector((right + shiftdown + gapx, start - gapy, height)) # down right [1,0,0] ur = Vector((right - shiftup + gapx, end - gapy, height)) # up right [1,1,0] ul = Vector((left - shiftup + gapx, end - gapy, height)) # up left [0,1,0] if herringbone: if tilt > 0: # / / / -> 1 board, 3 board, 5 board... ur[0] = ur[0] - (hyp / 2) ur[1] = ur[1] + (hyp / 2) dr[0] = dr[0] - (hyp / 2) dr[1] = dr[1] + (hyp / 2) else: # \ \ \-> 2 board, 4 board, 6 board... dl[0] = dl[0] + (hyp / 2) dl[1] = dl[1] + (hyp / 2) ul[0] = ul[0] + (hyp / 2) ul[1] = ul[1] + (hyp / 2) verts = (dl, ul, ur, dr) return (verts)
def square(rows, cols, planklength, n, border, longgap, shortgap, nseed, randrotx, randroty, randrotz, originx, originy): verts = [] verts2 = [] faces = [] faces2 = [] uvs = [] uvs2 = [] seed(nseed) ll=0 ll2=0 net_planklength = planklength - 2.0 * border plankwidth = net_planklength/n longside = (net_planklength-shortgap) shortside = (plankwidth-longgap) stepv = Vector((0,planklength ,0)) steph = Vector((planklength,0 ,0)) nstepv = Vector((0,plankwidth ,0)) nsteph = Vector((plankwidth,0 ,0)) pv = [Vector((0,0,0)),Vector((longside,0,0)),Vector((longside,shortside,0)),Vector((0,shortside,0))] rot = Euler((0,0,-PI/2),"XYZ") pvm = [rotate(v, rot) + Vector((0,planklength - border,0)) for v in pv] midpointpv = sum(pv,Vector())/4.0 midpointpvm = sum(pvm,Vector())/4.0 offseth = Vector((border, border, 0)) offsetv = Vector((border, 0, 0)) bw = border - shortgap b1 = [(0,longgap/2.0,0),(0,planklength - longgap/2.0,0),(bw,planklength - longgap/2.0 - border,0),(bw,longgap/2.0 + border,0)] b1 = [Vector(v) for v in b1] d = Vector((planklength/2.0, planklength/2.0, 0)) rot = Euler((0,0,- PI/2),"XYZ") b2 = [rotate(v-d,rot)+d for v in b1] rot = Euler((0,0,- PI ),"XYZ") b3 = [rotate(v-d,rot)+d for v in b1] rot = Euler((0,0,-3*PI/2),"XYZ") b4 = [rotate(v-d,rot)+d for v in b1] o = Vector((-originx, -originy, 0)) # CLEANUP: duplicate code, suboptimal loop nesting and a lot of repeated calculations # note that the uv map we create here is always aligned in the same direction even though planks alternate. This matches the saw direction in real life for col in range(cols): for row in range(rows): # add the regular planks for p in range(n): rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') if (col ^ row) %2 == 1: pverts = [rotate(v - midpointpv, rot) + midpointpv + row * stepv + col * steph + nstepv * p + offseth + o for v in pv] uverts = [v + row * stepv + col * steph + nstepv * p for v in pv] else: pverts = [rotate(v - midpointpv, rot) + midpointpv + row * stepv + col * steph + nsteph * p + offsetv + o for v in pvm] uverts = [v + row * stepv + col * steph + nstepv * p for v in pv] verts.extend(deepcopy(pverts)) uvs.append(deepcopy(uverts)) faces.append((ll, ll + 1, ll + 2, ll + 3)) ll = len(verts) # add the border planks if bw > 0.001: for vl in b1,b2,b3,b4: rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') midpointvl = sum(vl,Vector())/4.0 verts2.extend([rotate(v - midpointvl, rot) + midpointvl + row * stepv + col * steph + o for v in vl]) uvs2.append(deepcopy([v + row * stepv + col * steph for v in b1])) # again, always the unrotated uvs to match the saw direction faces2.append((ll2, ll2 + 3, ll2 + 2, ll2 + 1)) ll2 = len(verts2) for i in range(len(uvs)): pp1 = randrange(len(uvs)) pp2 = randrange(len(uvs)) swap(uvs,pp1,pp2) for i in range(len(uvs2)): pp1 = randrange(len(uvs2)) pp2 = randrange(len(uvs2)) swap(uvs2,pp1,pp2) fuvs = [v for p in uvs for v in p] fuvs2 = [v for p in uvs2 for v in p] return verts + verts2, faces + [(f[0]+ll,f[1]+ll,f[2]+ll,f[3]+ll) for f in faces2], fuvs + fuvs2
def planks(n, m, length, lengthvar, width, widthvar, longgap, shortgap, offset, randomoffset, minoffset, nseed, randrotx, randroty, randrotz, originx, originy): #n=Number of planks, m=Floor Length, length = Planklength verts = [] faces = [] uvs = [] seed(nseed) widthoffset = 0 s = 0 e = offset c = offset # Offset per row ws = 0 p = 0 while p < n: p += 1 uvs.append([]) w = width + randuni(0, widthvar) we = ws + w if randomoffset: e = randuni(4 * shortgap + (offset if minoffset else 0.0), length) # we don't like negative plank lengths while (m - e) > (4 * shortgap + (offset if minoffset else 0.0)): ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pverts = plank(s - originx, e - originx, ws - originy, we - originy, longgap, shortgap, rot) verts.extend(pverts) uvs[-1].append(deepcopy(pverts)) faces.append((ll, ll + 3, ll + 2, ll + 1)) s = e e += length + randuni(0, lengthvar) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pverts = plank(s - originx, m - originx, ws - originy, we - originy, longgap, shortgap, rot) verts.extend(pverts) uvs[-1].append(deepcopy(pverts)) faces.append((ll, ll + 3, ll + 2, ll + 1)) s = 0 #e = e - m if c <= (length): c = c + offset if c > (length): c = c - length e = c ws = we # randomly swap uvs of planks. Note: we only swap within one set of planks because different sets can have different widths. nplanks = len(uvs[-1]) if nplanks < 2 : continue for pp in range(nplanks//2): # // to make sure it stays an int i = randrange(nplanks-1) swapx(uvs[-1],i) fuvs = [uv for col in uvs for plank in col for uv in plank] return verts, faces, fuvs
def updateMesh(self, context): o = context.object material_list = getMaterialList(o) if o.pattern == 'Regular': nplanks = (o.width + o.originy) / o.plankwidth verts, faces, uvs = planks(nplanks, o.length + o.originx, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Herringbone': # note that there is a lot of extra length and width here to make sure that we create a pattern w.o. gaps at the edges v = o.plankwidth * sqrt(2.0) w = o.planklength * sqrt(2.0) nplanks = int((o.width + o.planklength + o.originy * 2) / v) + 1 nplanksc = int((o.length + o.originx * 2) / w) + 1 verts, faces, uvs = herringbone(nplanks, nplanksc, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Square': rows = int((o.width + o.originy) / o.planklength) + 1 cols = int((o.length + o.originx) / o.planklength) + 1 verts, faces, uvs = square(rows, cols, o.planklength, o.nsquare, o.border, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Versaille': rows = int((o.width + o.originy) / o.planklength) + 2 cols = int((o.length + o.originx) / o.planklength) + 2 verts, faces, uvs = versaille(rows, cols, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy, o.borderswitch) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) # more than one object can refer to the same emesh for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear( ) # this way the old mesh is marked as used by noone and not saved on exit bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors rot = Euler((0, 0, o.uvrotation)) mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data offset = Vector() # note that the uvs that are returned are shuffled for poly in mesh.polygons: color = [rand(), rand(), rand()] if o.randomuv == 'Random': offset = Vector((rand(), rand(), 0)) if o.randomuv == 'Restricted': offset = Vector((rand() * 2 - 1, rand() * 2 - 1, 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): co = offset + mesh.vertices[ mesh.loops[loop_index].vertex_index].co if co.x > o.length or co.x < 0: offset[0] = 0 if co.y > o.width or co.y < 0: offset[1] = 0 elif o.randomuv == 'Packed': x = [] y = [] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): x.append(uvs[mesh.loops[loop_index].vertex_index].x) y.append(uvs[mesh.loops[loop_index].vertex_index].y) offset = Vector((-min(x), -min(y), 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): if o.randomuv == 'Shuffle': coords = uvs[mesh.loops[loop_index].vertex_index] elif o.randomuv in ('Random', 'Restricted'): coords = mesh.vertices[ mesh.loops[loop_index].vertex_index].co + offset elif o.randomuv == 'Packed': coords = uvs[mesh.loops[loop_index].vertex_index] + offset else: coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co coords = Vector(coords) # copy coords.x *= o.uvscalex coords.y *= o.uvscaley coords.rotate(rot) uv_layer[loop_index].uv = coords.xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len( v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert( v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges ) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len( v2.link_edges ) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() # remove all modifiers to make sure the boolean will be last & only modifier n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name) # add thickness bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(o.data) # extrude to give thickness ret = bmesh.ops.extrude_face_region(bm, geom=bm.faces[:]) ret = bmesh.ops.translate( bm, vec=Vector((0, 0, self.thickness)), verts=[el for el in ret['geom'] if isinstance(el, bmesh.types.BMVert)]) # trim excess flooring ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], plane_co=(o.length, 0, 0), plane_no=(1, 0, 0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], plane_co=(0, 0, 0), plane_no=(-1, 0, 0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], plane_co=(0, o.width, 0), plane_no=(0, 1, 0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], plane_co=(0, 0, 0), plane_no=(0, -1, 0), clear_outer=True) # fill in holes caused by the trimming open_edges = [e for e in bm.edges if len(e.link_faces) == 1] bmesh.ops.edgeloop_fill(bm, edges=open_edges, mat_nr=0, use_smooth=False) creases = bm.edges.layers.crease.active if creases is not None: for edge in open_edges: edge[creases] = 1 bmesh.update_edit_mesh(o.data) bpy.ops.object.mode_set(mode='OBJECT') # intersect with a floorplan. Note the floorplan must be 2D (all z-coords must be identical) and a closed polygon. if self.usefloorplan and self.floorplan != ' None ': # make the floorplan the only active an selected object bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = bpy.data.objects[self.floorplan] bpy.data.objects[self.floorplan].select = True # duplicate the selected geometry into a separate object me = context.scene.objects.active.data selected_faces = [p.index for p in me.polygons if p.select] bpy.ops.object.editmode_toggle() bpy.ops.mesh.duplicate() bpy.ops.mesh.separate() bpy.ops.object.editmode_toggle() me = context.scene.objects.active.data for i in selected_faces: me.polygons[i].select = True # now there will be two selected objects # the one with the new name will be the copy for ob in context.selected_objects: if ob.name != self.floorplan: fpob = ob # make that copy active and selected for ob in context.selected_objects: ob.select = False fpob.select = True context.scene.objects.active = fpob # add thickness # let normals of select faces point in same direction bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # add solidify modifier # NOTE: for some reason bpy.ops.object.modifier_add doesn't work here # even though fpob at this point is verifyable the active and selected object ... mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY') mod.offset = 1.0 # in the direction of the normals mod.thickness = 2000 # very thick bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() fpob.location -= Vector( (0, 0, 1000) ) # actually this should be in the negative direction of the normals not just plain downward... # at this point the floorplan object is the active and selected object if True: # make the floorboards active and selected for ob in context.selected_objects: ob.select = False context.scene.objects.active = o o.select = True # add-and-apply a boolean modifier to get the intersection with the floorplan copy bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect o.modifiers[-1].object = fpob if True: bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean") # delete the copy bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = fpob fpob.select = True bpy.ops.object.delete() # make the floorboards active and selected context.scene.objects.active = o o.select = True if self.modify: mods = o.modifiers if len(mods) == 0: # always true bpy.ops.object.modifier_add(type='BEVEL') #bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False #mods[1].show_expanded = False mods[0].width = self.bevel mods[0].segments = 2 mods[0].limit_method = 'ANGLE' mods[0].angle_limit = (85 / 90.0) * PI / 2 if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf') if self.preservemats and len(material_list) > 0: rebuildMaterialList(o, material_list) assignRandomMaterial(len(material_list))
def versaille(rows, cols, planklength, plankwidth, longgap=0, shortgap=0, randrotx=0, randroty=0, randrotz=0, originx=0, originy=0, switch=False): o = Vector((-originx, -originy, 0)) * planklength # (8*w+w/W2)*W2 + w = 8*w*W2+w = (8*W2+1)*w = 1 w = 1.0 / (8 * W2 + 2) #w1 = 1 - w q = w / W2 #k = w*4*W2-w #s = (k - w)/2 #d = ((s+2*w)/W2)/2 #S = s/W2 sg = shortgap s2 = sg / W2 lg = longgap dd = -q if switch else 0 planks1 = ( # rectangles (0, [(0 + sg, 0, 0), (w * 5 - sg, 0, 0), (w * 5 - sg, w, 0), (0 + sg, w, 0)]), (0, [(6 * w + sg, 0, 0), (w * 11 - sg, 0, 0), (w * 11 - sg, w, 0), (6 * w + sg, w, 0)]), (90, [(5 * w, -2 * w + sg, 0), (w * 6, -2 * w + sg, 0), (w * 6, 3 * w - sg, 0), (5 * w, 3 * w - sg, 0)]), (0, [(3 * w + sg, 3 * w, 0), (w * 8 - sg, 3 * w, 0), (w * 8 - sg, w * 4, 0), (3 * w + sg, w * 4, 0)]), (0, [(3 * w + sg, -3 * w, 0), (w * 8 - sg, -3 * w, 0), (w * 8 - sg, w * -2, 0), (3 * w + sg, w * -2, 0)]), (90, [(5 * w, 4 * w + sg, 0), (6 * w, 4 * w + sg, 0), (6 * w, 6 * w - sg, 0), (5 * w, 6 * w - sg, 0)]), (90, [(5 * w, -3 * w - sg, 0), (5 * w, -5 * w + sg, 0), (6 * w, -5 * w + sg, 0), (6 * w, -3 * w - sg, 0)]), # squares (0, [(0 + sg, w + sg, 0), (w * 2 - sg, w + sg, 0), (w * 2 - sg, w * 3 - sg, 0), (0 + sg, w * 3 - sg, 0)]), (0, [(3 * w + sg, w + sg, 0), (w * 5 - sg, w + sg, 0), (w * 5 - sg, w * 3 - sg, 0), (3 * w + sg, w * 3 - sg, 0)]), (0, [(6 * w + sg, w + sg, 0), (w * 8 - sg, w + sg, 0), (w * 8 - sg, w * 3 - sg, 0), (6 * w + sg, w * 3 - sg, 0)]), (0, [(9 * w + sg, w + sg, 0), (w * 11 - sg, w + sg, 0), (w * 11 - sg, w * 3 - sg, 0), (9 * w + sg, w * 3 - sg, 0)]), (0, [(0 + sg, -2 * w + sg, 0), (w * 2 - sg, -2 * w + sg, 0), (w * 2 - sg, 0 - sg, 0), (0 + sg, 0 - sg, 0)]), (0, [(3 * w + sg, -2 * w + sg, 0), (w * 5 - sg, -2 * w + sg, 0), (w * 5 - sg, 0 - sg, 0), (3 * w + sg, 0 - sg, 0)]), (0, [(6 * w + sg, -2 * w + sg, 0), (w * 8 - sg, -2 * w + sg, 0), (w * 8 - sg, 0 - sg, 0), (6 * w + sg, 0 - sg, 0)]), (0, [(9 * w + sg, -2 * w + sg, 0), (w * 11 - sg, -2 * w + sg, 0), (w * 11 - sg, 0 - sg, 0), (9 * w + sg, 0 - sg, 0)]), (0, [(3 * w + sg, 4 * w + sg, 0), (5 * w - sg, 4 * w + sg, 0), (5 * w - sg, 6 * w - sg, 0), (3 * w + sg, 6 * w - sg, 0)]), (0, [(6 * w + sg, 4 * w + sg, 0), (8 * w - sg, 4 * w + sg, 0), (8 * w - sg, 6 * w - sg, 0), (6 * w + sg, 6 * w - sg, 0)]), (0, [(3 * w + sg, -5 * w + sg, 0), (5 * w - sg, -5 * w + sg, 0), (5 * w - sg, -3 * w - sg, 0), (3 * w + sg, -3 * w - sg, 0)]), (0, [(6 * w + sg, -5 * w + sg, 0), (8 * w - sg, -5 * w + sg, 0), (8 * w - sg, -3 * w - sg, 0), (6 * w + sg, -3 * w - sg, 0)]), # pointed (0, [(0 + sg, 3 * w, 0), (2 * w - sg, 3 * w, 0), (2 * w - sg, 4 * w, 0), (w + sg, 4 * w, 0)]), #left (0, [(w + sg, 4 * w, 0), (2 * w - sg, 4 * w, 0), (2 * w - sg, 5 * w - sg * 2, 0)]), (0, [(9 * w + sg, 3 * w, 0), (11 * w - sg, 3 * w, 0), (10 * w - sg, 4 * w, 0), (9 * w + sg, 4 * w, 0)]), #top (0, [(9 * w + sg, 4 * w, 0), (10 * w - sg, 4 * w, 0), (9 * w + sg, 5 * w - sg * 2, 0)]), (0, [(0 + sg, -2 * w, 0), (w + sg, -3 * w, 0), (2 * w - sg, -3 * w, 0), (2 * w - sg, -2 * w, 0)]), #bottom (0, [(1 * w + sg, -3 * w, 0), (2 * w - sg, -4 * w + sg + sg, 0), (2 * w - sg, -3 * w, 0)]), (0, [(9 * w + sg, -3 * w, 0), (10 * w - sg, -3 * w, 0), (11 * w - sg, -2 * w, 0), (9 * w + sg, -2 * w, 0)]), #right (0, [(9 * w + sg, -3 * w, 0), (9 * w + sg, -4 * w + sg * 2, 0), (10 * w - sg, -3 * w, 0)]), # long pointed (90, [(2 * w, 0 - sg, 0), (2 * w, -4 * w + sg, 0), (3 * w, -5 * w + sg, 0), (3 * w, 0 - sg, 0)]), (90, [(8 * w, 0 - sg, 0), (8 * w, -5 * w + sg, 0), (9 * w, -4 * w + sg, 0), (9 * w, 0 - sg, 0)]), (90, [(2 * w, w + sg, 0), (3 * w, w + sg, 0), (3 * w, 6 * w - sg, 0), (2 * w, 5 * w - sg, 0)]), (90, [(8 * w, w + sg, 0), (9 * w, w + sg, 0), (9 * w, 5 * w - sg, 0), (8 * w, 6 * w - sg, 0)]), # corner planks (90, [(0, -2 * w + sg, 0), (0, 3 * w - sg, 0), (-1 * w, 2 * w - sg, 0), (-1 * w, -1 * w + sg, 0)]), (90, [(11 * w, -2 * w + sg, 0), (12 * w, -1 * w + sg, 0), (12 * w, 2 * w - sg, 0), (11 * w, 3 * w - sg, 0)]), (0, [(3 * w + sg, -5 * w, 0), (4 * w + sg, -6 * w, 0), (7 * w - sg, -6 * w, 0), (8 * w - sg, -5 * w, 0)]), (0, [(3 * w + sg, 6 * w, 0), (8 * w - sg, 6 * w, 0), (7 * w - sg, 7 * w, 0), (4 * w + sg, 7 * w, 0)]), # corner triangles (90, [(-w - s2, -w + s2 * 2, 0), (-w - s2, 2 * w - s2 * 2, 0), (-2.5 * w + s2, 0.5 * w, 0)]), (90, [(12 * w + s2, 2 * w - s2 * 2, 0), (12 * w + s2, -w + s2 * 2, 0), (13.5 * w - s2, 0.5 * w, 0)]), (0, [(4 * w + s2 * 2, 7 * w + s2, 0), (7 * w - s2 * 2, 7 * w + s2, 0), (5.5 * w, 8.5 * w - s2, 0)]), (0, [(4 * w + s2 * 2, -6 * w - s2, 0), (5.5 * w, -7.5 * w + s2, 0), (7 * w - s2 * 2, -6 * w - s2, 0)]), # border planks # bottom (45, [(-2.5 * w - q + q + dd + lg, 0.5 * w + q - q - dd - lg, 0), (-2.5 * w - 2 * q + q + dd + lg + lg, 0.5 * w - q - dd + lg - lg, 0), (5.5 * w - q + lg - lg, -7.5 * w - q + lg + lg, 0), (5.5 * w - lg, -7.5 * w + lg, 0)]), # right (135, [(5.5 * w - q + lg, -7.5 * w - q + lg, 0), (5.5 * w + lg - lg, -7.5 * w - 2 * q + lg + lg, 0), (13.5 * w + 2 * q + dd - lg - lg, 0.5 * w + dd - lg + lg, 0), (13.5 * w + q + dd - lg, 0.5 * w + q + dd - lg, 0)]), #top (45, [(13.5 * w - dd - lg, 0.5 * w + dd + lg, 0), (13.5 * w + q - dd - lg - lg, 0.5 * w + q + dd - lg + lg, 0), (5.5 * w + q - lg + lg, 8.5 * w + q - lg - lg, 0), (5.5 * w + lg, 8.5 * w - lg, 0)]), #left (135, [(-2.5 * w - q - dd + lg, 0.5 * w - q - dd + lg, 0), (5.5 * w + q - lg, 8.5 * w + q - lg, 0), (5.5 * w - lg + lg, 8.5 * w + 2 * q - lg - lg, 0), (-2.5 * w - q - q - dd + lg + lg, 0.5 * w + q - q - dd + lg - lg, 0)])) verts = [] faces = [] uvs = [] left = 0 center = Vector((5.5 * w, 0.5 * w, 0)) * planklength delta = Vector((w, -10 * q, 0)) * planklength for col in range(cols): start = 0 for row in range(rows): origin = Vector((start, left, 0)) for uvrot, p in planks1: ll = len(verts) rot = Euler( (randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') # randomly rotate the plank a little bit around its own center pverts = [rotate(Vector(v) * planklength, rot) for v in p] pverts = [ origin + delta + o + rotatep(v, Euler((0, 0, radians(45)), 'XYZ'), center) for v in pverts ] verts.extend(pverts) midpoint = vcenter(pverts) if uvrot > 0: print(uvrot) print([v - midpoint for v in pverts]) print([ rotatep(v, Euler( (0, 0, radians(uvrot)), 'XYZ'), midpoint) - midpoint for v in pverts ]) print() uvs.append([ rotatep(v, Euler((0, 0, radians(uvrot)), 'XYZ'), midpoint) for v in pverts ]) faces.append((ll, ll + 3, ll + 2, ll + 1) if len(pverts) == 4 else (ll, ll + 2, ll + 1)) start += planklength left += planklength fuvs = [v for p in uvs for v in p] return verts, faces, fuvs
def square(rows, cols, planklength, n, border, longgap, shortgap, nseed, randrotx, randroty, randrotz, originx, originy): verts = [] verts2 = [] faces = [] faces2 = [] uvs = [] uvs2 = [] seed(nseed) ll = 0 ll2 = 0 net_planklength = planklength - 2.0 * border plankwidth = net_planklength / n longside = (net_planklength - shortgap) shortside = (plankwidth - longgap) stepv = Vector((0, planklength, 0)) steph = Vector((planklength, 0, 0)) nstepv = Vector((0, plankwidth, 0)) nsteph = Vector((plankwidth, 0, 0)) pv = [ Vector((0, 0, 0)), Vector((longside, 0, 0)), Vector((longside, shortside, 0)), Vector((0, shortside, 0)) ] rot = Euler((0, 0, -PI / 2), "XYZ") pvm = [rotate(v, rot) + Vector((0, planklength - border, 0)) for v in pv] midpointpv = sum(pv, Vector()) / 4.0 midpointpvm = sum(pvm, Vector()) / 4.0 offseth = Vector((border, border, 0)) offsetv = Vector((border, 0, 0)) bw = border - shortgap b1 = [(0, longgap / 2.0, 0), (0, planklength - longgap / 2.0, 0), (bw, planklength - longgap / 2.0 - border, 0), (bw, longgap / 2.0 + border, 0)] b1 = [Vector(v) for v in b1] d = Vector((planklength / 2.0, planklength / 2.0, 0)) rot = Euler((0, 0, -PI / 2), "XYZ") b2 = [rotate(v - d, rot) + d for v in b1] rot = Euler((0, 0, -PI), "XYZ") b3 = [rotate(v - d, rot) + d for v in b1] rot = Euler((0, 0, -3 * PI / 2), "XYZ") b4 = [rotate(v - d, rot) + d for v in b1] o = Vector((-originx, -originy, 0)) # CLEANUP: duplicate code, suboptimal loop nesting and a lot of repeated calculations # note that the uv map we create here is always aligned in the same direction even though planks alternate. This matches the saw direction in real life for col in range(cols): for row in range(rows): # add the regular planks for p in range(n): rot = Euler( (randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') if (col ^ row) % 2 == 1: pverts = [ rotate(v - midpointpv, rot) + midpointpv + row * stepv + col * steph + nstepv * p + offseth + o for v in pv ] uverts = [ v + row * stepv + col * steph + nstepv * p for v in pv ] else: pverts = [ rotate(v - midpointpv, rot) + midpointpv + row * stepv + col * steph + nsteph * p + offsetv + o for v in pvm ] uverts = [ v + row * stepv + col * steph + nstepv * p for v in pv ] verts.extend(deepcopy(pverts)) uvs.append(deepcopy(uverts)) faces.append((ll, ll + 1, ll + 2, ll + 3)) ll = len(verts) # add the border planks if bw > 0.001: for vl in b1, b2, b3, b4: rot = Euler( (randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') midpointvl = sum(vl, Vector()) / 4.0 verts2.extend([ rotate(v - midpointvl, rot) + midpointvl + row * stepv + col * steph + o for v in vl ]) uvs2.append( deepcopy([v + row * stepv + col * steph for v in b1]) ) # again, always the unrotated uvs to match the saw direction faces2.append((ll2, ll2 + 3, ll2 + 2, ll2 + 1)) ll2 = len(verts2) for i in range(len(uvs)): pp1 = randrange(len(uvs)) pp2 = randrange(len(uvs)) swap(uvs, pp1, pp2) for i in range(len(uvs2)): pp1 = randrange(len(uvs2)) pp2 = randrange(len(uvs2)) swap(uvs2, pp1, pp2) fuvs = [v for p in uvs for v in p] fuvs2 = [v for p in uvs2 for v in p] return verts + verts2, faces + [ (f[0] + ll, f[1] + ll, f[2] + ll, f[3] + ll) for f in faces2 ], fuvs + fuvs2
def updateMesh(self, context): o = context.object verts, faces, shortedges, longedges = planks(o.nplanks, o.length, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data for poly in mesh.polygons: offset = Vector((rand(), rand(), 0)) if o.randomuv else Vector((0, 0, 0)) color = [rand(), rand(), rand()] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co uv_layer[loop_index].uv = (coords + offset).xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len(v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert(v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len(v2.link_edges) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() if self.modify: mods = o.modifiers if len(mods) == 0: bpy.ops.object.modifier_add(type='SOLIDIFY') bpy.ops.object.modifier_add(type='BEVEL') bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False mods[1].show_expanded = False mods[2].show_expanded = False mods[0].thickness = self.thickness mods[1].width = self.bevel if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf') else: n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name)
def parquet(switch, nbrboards, height, randheight, width, randwith, gapx, lengthboard, gapy, shifty, nbrshift, tilt, herringbone, randoshifty, lengthparquet, trans, gaptrans, randgaptrans, glue, borders, lengthtrans, locktrans, nbrtrans): x = 0 y = 0 verts = [] faces = [] listinter = [] start = 0 left = 0 bool_translatey = True # shifty = 0 end = lengthboard interleft = 0 interright = 0 if locktrans: shifty = 0 # No shift with unlock ! glue = False borders = False if shifty: locktrans = False # Can't have the boards shifted and the tranversal unlocked if herringbone : switch = True # Constrain the computation of the length using the boards if herringbone if randoshifty > 0: # If randomness in the shift of the boards randomshift = shifty * (1-randoshifty) # Compute the amount of randomness in the shift else: randomshift = shifty # No randomness if shifty > 0: tilt = 0 herringbone = False if gapy == 0: # If no gap on the Y axis : the transversal is not possible trans = False if herringbone: # Constraints if herringbone is choose : shifty = 0 # - no shift tilt = math.radians(45) # - Tilt = 45° randwith = 0 # - No random on the width trans = False # - No transversal # Compute the new length and width of the board if tilted hyp, translatex, translatey = calculangle(left, end, tilt, start, width, end) randwidth = hyp + (randwith * randuni(0, hyp)) # Randomness in the width right = randwidth # Right = width of the board end = translatey - (translatey * randuni(randomshift, shifty)) # Randomness in the length if herringbone or switch: # Compute the length of the floor based on the length of the boards lengthparquet = ((round(lengthparquet / (translatey + gapy))) * (translatey + gapy)) - gapy noglue = gapx #------------------------------------------------------------ # Loop for the boards on the X axis #------------------------------------------------------------ while x < nbrboards: # X axis x += 1 if glue and (x % nbrshift != 0): gapx = gaptrans else: gapx = noglue if (x % nbrshift != 0): bool_translatey = not bool_translatey # Invert the shift if end > lengthparquet : # Cut the last board if it's > than the floor end = lengthparquet # Creation of the first board nbvert = len(verts) verts.extend(board(start, left, right, end, tilt, translatex, hyp, herringbone, gapy, height, randheight)) faces.append((nbvert,nbvert+1, nbvert+2, nbvert+3)) # Start a new column (Y) start2 = end + gapy end2 = start2 #------------------------------------------------------------ # TRANSVERSAL #------------------------------------------------------------ # listinter = List of the length (left) of the interval || x = nbr of the actual column || nbrshift = nbr of columns to shift || nbrboards = Total nbr of column # The modulo (%) is here to determined if the actual interval as to be shift listinter.append(left) # Keep the length of the actual interval endfloor = 0 if x == nbrboards: endfloor = right if trans and ((x % nbrshift == 0) or ((x % nbrshift != 0) and (x == nbrboards))) and (end < lengthparquet) and not locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) elif trans and (x == nbrboards) and locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) #------------------------------------------------------------ # BORDERS #------------------------------------------------------------ # Create the borders in the X gap if boards are glued if borders and glue and (x % nbrshift == 0) and translatex == 0 and (x != nbrboards) and (shifty == 0) and (gaptrans*2 < gapx): nbvert = len(verts) verts.extend(border(right+gaptrans, right+noglue-gaptrans, start, gapy, end, height, randheight, gaptrans, randgaptrans, lengthparquet, start2 + translatey)) faces.append((nbvert, nbvert+1, nbvert+2, nbvert+3, nbvert+4, nbvert+5)) #------------------------------------------------------------ # Loop for the boards on the Y axis #------------------------------------------------------------ while lengthparquet > end2 : # Y axis end2 = start2 + translatey # New column if end2 > lengthparquet : # Cut the board if it's > than the floor end2 = lengthparquet if tilt < 0: # This part is used to inversed the tilt of the boards tilt = tilt * (-1) else: tilt = -tilt # Creation of the board nbvert = len(verts) verts.extend(board(start2, left, right, end2, tilt, translatex, hyp, herringbone, gapy, height, randheight)) faces.append((nbvert,nbvert+1, nbvert+2, nbvert+3)) #------------------------------------------------------------ # BORDERS #------------------------------------------------------------ # Create the borders in the X gap if boards are glued if borders and glue and (x % nbrshift == 0) and translatex == 0 and (x != nbrboards) and (shifty == 0) and (gaptrans*2 < gapx): nbvert = len(verts) verts.extend(border(right+gaptrans, right+noglue-gaptrans, start2, gapy, end2, height, randheight, gaptrans, randgaptrans, lengthparquet, start2 + translatey)) faces.append((nbvert, nbvert+1, nbvert+2, nbvert+3, nbvert+4, nbvert+5)) # New column start2 += translatey + gapy #------------------------------------------------------------ # TRANSVERSAL #------------------------------------------------------------ # x = nbr of the actual column || nbrshift = nbr of columns to shift || nbrboards = Total nbr of column # The modulo (%) is here to determined if the actual interval as to be shift endfloor = 0 if x == nbrboards: endfloor = right if trans and ((x % nbrshift == 0) or ((x % nbrshift != 0) and (x == nbrboards))) and (end2 < lengthparquet) and not locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end2, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) elif trans and locktrans and (x == nbrboards) and (end2 < lengthparquet) : if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end2, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) end2 = start2 # End of the loop on Y axis #------------------------------------------------------------# #------------------------------------------------------------ # Increment / initialize #------------------------------------------------------------ if (x % nbrshift == 0) and not locktrans: listinter = [] # Initialize the list of interval if the nbr of boards to shift is reaches if not herringbone: # If not herringbone left += gapx # Add the value of gapx to the left side of the boards right += gapx # Add the value of gapx to the right side of the boards else: # If herringbone, we don't use the gapx anymore in the panel right += gapy * 2 # used only the gapy left += gapy * 2 # "" "" "" left += randwidth # Add randomness on the left side of the boards randwidth = hyp + (randwith * randuni(0, hyp)) # Compute the new randomness on the width (hyp) right += randwidth # Add randomness on the right side of the boards #------------------------------------------------------------# #------------------------------------------------------------ # Shift on the Y axis #------------------------------------------------------------ # bool_translatey is turn on and off at each new column to reverse the direction of the shift up or down. if (bool_translatey and shifty > 0): # If the columns are shifted if (x % nbrshift == 0 ): # If the nbr of column to shift is reach end = translatey * randuni(randomshift, shifty) # Compute and add the randomness to the new end (translatey) shifted bool_translatey = False # Turn on the boolean, so it will be inverted for the next colmun else: if (x % nbrshift == 0 ): end = translatey - (translatey * randuni(randomshift, shifty)) # Compute and add the randomness to the new end (translatey) shifted bool_translatey = True # Turn on the boolean, so it will be inverted for the next colmun #------------------------------------------------------------# #------------------------------------------------------------ # Herringbone only #------------------------------------------------------------ # Invert the value of the tilted parameter if tilt < 0: # The tilted value is inverted at each column tilt = tilt * (-1) # so the boards will be reverse #------------------------------------------------------------# #------------------------------------------------------------ # End of the loop on X axis return verts, faces
def updateMesh(self, context): o = context.object verts, faces, shortedges, longedges = planks(o.nplanks, o.length, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data for poly in mesh.polygons: offset = Vector((rand(), rand(), 0)) if o.randomuv else Vector((0, 0, 0)) color = [rand(), rand(), rand()] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co uv_layer[loop_index].uv = (coords + offset).xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len(v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert(v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len(v2.link_edges) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() # remove all modifiers to make sure the boolean will be last & only modifier n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name) # add thickness # simply extruding would be simpler and cheaper but we get a warning convertViewVec: called in an invalid context # overriding the context of the operator to explicitly set the area crashes Blender, which is a known bug # http://blenderartists.org/forum/showthread.php?338387-addon-related-to-System-console-tells-me-quot-convertViewVec-called-in-an-invalid-contex # so we opt for the add-solidify-modifier-and-apply approach even though it's just a warning. #bpy.ops.object.editmode_toggle() #bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={'value':(0,0,self.thickness)}) #bpy.ops.mesh.select_all(action='SELECT') #bpy.ops.mesh.normals_make_consistent(inside=False) #bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_add(type='SOLIDIFY') o.modifiers[-1].thickness = self.thickness bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # intersect with a floorplan if self.usefloorplan and self.floorplan != ' None ': # make the floorplan the only active an selected object bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = bpy.data.objects[self.floorplan] bpy.data.objects[self.floorplan].select = True # duplicate the selected geometry into a separate object me = context.scene.objects.active.data selected_faces = [p.index for p in me.polygons if p.select] bpy.ops.object.editmode_toggle() bpy.ops.mesh.duplicate() bpy.ops.mesh.separate() bpy.ops.object.editmode_toggle() me = context.scene.objects.active.data for i in selected_faces: me.polygons[i].select = True # now there will be two selected objects # the one with the new name will be the copy for ob in context.selected_objects: if ob.name != self.floorplan: fpob = ob print('floorplan copy',fpob.name) # make that copy active and selected for ob in context.selected_objects: ob.select = False fpob.select = True context.scene.objects.active = fpob if True: # add thickness # let normals of select faces point in same direction bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # add solidify modifier # NOTE: for some reason bpy.ops.object.modifier_add doesn't work here # even though fpob at this point is verifyable the active and selected object ... mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY') mod.offset = 1.0 # in the direction of the normals mod.thickness = 2000 # very thick bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() fpob.location -= Vector((0,0,1000)) # actually this should be in the negative direction of the normals not just plain downward... # make the floorboards active and selected for ob in context.selected_objects: ob.select = False context.scene.objects.active = o o.select = True # add-and-apply a boolean modifier to get the intersection with the floorplan copy bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect o.modifiers[-1].object = fpob bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean") # delete the copy bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = fpob fpob.select = True bpy.ops.object.delete() # make the floorboards active and selected context.scene.objects.active = o o.select = True if self.modify: mods = o.modifiers if len(mods) == 0: # always true bpy.ops.object.modifier_add(type='BEVEL') bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False mods[1].show_expanded = False mods[0].width = self.bevel if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf')
def parquet(switch, nbrboards, height, randheight, width, randwith, gapx, lengthboard, gapy, shifty, nbrshift, tilt, herringbone, randoshifty, lengthparquet, trans, gaptrans, randgaptrans, glue, borders, lengthtrans, locktrans, nbrtrans): x = 0 y = 0 verts = [] faces = [] listinter = [] start = 0 left = 0 bool_translatey = True # shifty = 0 end = lengthboard interleft = 0 interright = 0 if locktrans: shifty = 0 # No shift with unlock ! glue = False borders = False if shifty: locktrans = False # Can't have the boards shifted and the tranversal unlocked if herringbone: switch = True # Constrain the computation of the length using the boards if herringbone if randoshifty > 0: # If randomness in the shift of the boards randomshift = shifty * ( 1 - randoshifty) # Compute the amount of randomness in the shift else: randomshift = shifty # No randomness if shifty > 0: tilt = 0 herringbone = False if gapy == 0: # If no gap on the Y axis : the transversal is not possible trans = False if herringbone: # Constraints if herringbone is choose : shifty = 0 # - no shift tilt = math.radians(45) # - Tilt = 45° randwith = 0 # - No random on the width trans = False # - No transversal # Compute the new length and width of the board if tilted hyp, translatex, translatey = calculangle(left, end, tilt, start, width, end) randwidth = hyp + (randwith * randuni(0, hyp)) # Randomness in the width right = randwidth # Right = width of the board end = translatey - (translatey * randuni(randomshift, shifty) ) # Randomness in the length if herringbone or switch: # Compute the length of the floor based on the length of the boards lengthparquet = ((round(lengthparquet / (translatey + gapy))) * (translatey + gapy)) - gapy noglue = gapx #------------------------------------------------------------ # Loop for the boards on the X axis #------------------------------------------------------------ while x < nbrboards: # X axis x += 1 if glue and (x % nbrshift != 0): gapx = gaptrans else: gapx = noglue if (x % nbrshift != 0): bool_translatey = not bool_translatey # Invert the shift if end > lengthparquet: # Cut the last board if it's > than the floor end = lengthparquet # Creation of the first board nbvert = len(verts) verts.extend( board(start, left, right, end, tilt, translatex, hyp, herringbone, gapy, height, randheight)) faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3)) # Start a new column (Y) start2 = end + gapy end2 = start2 #------------------------------------------------------------ # TRANSVERSAL #------------------------------------------------------------ # listinter = List of the length (left) of the interval || x = nbr of the actual column || nbrshift = nbr of columns to shift || nbrboards = Total nbr of column # The modulo (%) is here to determined if the actual interval as to be shift listinter.append(left) # Keep the length of the actual interval endfloor = 0 if x == nbrboards: endfloor = right if trans and ((x % nbrshift == 0) or ( (x % nbrshift != 0) and (x == nbrboards))) and (end < lengthparquet) and not locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) elif trans and (x == nbrboards) and locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) #------------------------------------------------------------ # BORDERS #------------------------------------------------------------ # Create the borders in the X gap if boards are glued if borders and glue and (x % nbrshift == 0) and translatex == 0 and ( x != nbrboards) and (shifty == 0) and (gaptrans * 2 < gapx): nbvert = len(verts) verts.extend( border(right + gaptrans, right + noglue - gaptrans, start, gapy, end, height, randheight, gaptrans, randgaptrans, lengthparquet, start2 + translatey)) faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3, nbvert + 4, nbvert + 5)) #------------------------------------------------------------ # Loop for the boards on the Y axis #------------------------------------------------------------ while lengthparquet > end2: # Y axis end2 = start2 + translatey # New column if end2 > lengthparquet: # Cut the board if it's > than the floor end2 = lengthparquet if tilt < 0: # This part is used to inversed the tilt of the boards tilt = tilt * (-1) else: tilt = -tilt # Creation of the board nbvert = len(verts) verts.extend( board(start2, left, right, end2, tilt, translatex, hyp, herringbone, gapy, height, randheight)) faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3)) #------------------------------------------------------------ # BORDERS #------------------------------------------------------------ # Create the borders in the X gap if boards are glued if borders and glue and ( x % nbrshift == 0) and translatex == 0 and ( x != nbrboards) and (shifty == 0) and (gaptrans * 2 < gapx): nbvert = len(verts) verts.extend( border(right + gaptrans, right + noglue - gaptrans, start2, gapy, end2, height, randheight, gaptrans, randgaptrans, lengthparquet, start2 + translatey)) faces.append((nbvert, nbvert + 1, nbvert + 2, nbvert + 3, nbvert + 4, nbvert + 5)) # New column start2 += translatey + gapy #------------------------------------------------------------ # TRANSVERSAL #------------------------------------------------------------ # x = nbr of the actual column || nbrshift = nbr of columns to shift || nbrboards = Total nbr of column # The modulo (%) is here to determined if the actual interval as to be shift endfloor = 0 if x == nbrboards: endfloor = right if trans and ((x % nbrshift == 0) or ((x % nbrshift != 0) and (x == nbrboards))) and ( end2 < lengthparquet) and not locktrans: if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end2, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) elif trans and locktrans and (x == nbrboards) and (end2 < lengthparquet): if start2 > lengthparquet: start2 = lengthparquet # Cut the board if it's > than the floor transversal(listinter[0], right, end2, tilt, translatex, gapy, noglue, gaptrans, randgaptrans, start2, nbrtrans, verts, faces, locktrans, lengthtrans, height, randheight, borders, endfloor, shifty) end2 = start2 # End of the loop on Y axis #------------------------------------------------------------# #------------------------------------------------------------ # Increment / initialize #------------------------------------------------------------ if (x % nbrshift == 0) and not locktrans: listinter = [ ] # Initialize the list of interval if the nbr of boards to shift is reaches if not herringbone: # If not herringbone left += gapx # Add the value of gapx to the left side of the boards right += gapx # Add the value of gapx to the right side of the boards else: # If herringbone, we don't use the gapx anymore in the panel right += gapy * 2 # used only the gapy left += gapy * 2 # "" "" "" left += randwidth # Add randomness on the left side of the boards randwidth = hyp + (randwith * randuni(0, hyp) ) # Compute the new randomness on the width (hyp) right += randwidth # Add randomness on the right side of the boards #------------------------------------------------------------# #------------------------------------------------------------ # Shift on the Y axis #------------------------------------------------------------ # bool_translatey is turn on and off at each new column to reverse the direction of the shift up or down. if (bool_translatey and shifty > 0): # If the columns are shifted if (x % nbrshift == 0): # If the nbr of column to shift is reach end = translatey * randuni( randomshift, shifty ) # Compute and add the randomness to the new end (translatey) shifted bool_translatey = False # Turn on the boolean, so it will be inverted for the next colmun else: if (x % nbrshift == 0): end = translatey - ( translatey * randuni(randomshift, shifty) ) # Compute and add the randomness to the new end (translatey) shifted bool_translatey = True # Turn on the boolean, so it will be inverted for the next colmun #------------------------------------------------------------# #------------------------------------------------------------ # Herringbone only #------------------------------------------------------------ # Invert the value of the tilted parameter if tilt < 0: # The tilted value is inverted at each column tilt = tilt * (-1) # so the boards will be reverse #------------------------------------------------------------# #------------------------------------------------------------ # End of the loop on X axis return verts, faces
def updateMesh(self, context): o = context.object verts, faces, shortedges, longedges = planks( o.nplanks, o.length, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data for poly in mesh.polygons: offset = Vector((rand(), rand(), 0)) if o.randomuv else Vector( (0, 0, 0)) color = [rand(), rand(), rand()] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co uv_layer[loop_index].uv = (coords + offset).xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len( v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert( v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges ) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len( v2.link_edges ) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() # remove all modifiers to make sure the boolean will be last & only modifier n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name) # add thickness # simply extruding would be simpler and cheaper but we get a warning convertViewVec: called in an invalid context # overriding the context of the operator to explicitly set the area crashes Blender, which is a known bug # http://blenderartists.org/forum/showthread.php?338387-addon-related-to-System-console-tells-me-quot-convertViewVec-called-in-an-invalid-contex # so we opt for the add-solidify-modifier-and-apply approach even though it's just a warning. #bpy.ops.object.editmode_toggle() #bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate={'value':(0,0,self.thickness)}) #bpy.ops.mesh.select_all(action='SELECT') #bpy.ops.mesh.normals_make_consistent(inside=False) #bpy.ops.object.editmode_toggle() bpy.ops.object.modifier_add(type='SOLIDIFY') o.modifiers[-1].thickness = self.thickness bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # intersect with a floorplan if self.usefloorplan and self.floorplan != ' None ': # make the floorplan the only active an selected object bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = bpy.data.objects[self.floorplan] bpy.data.objects[self.floorplan].select = True # duplicate the selected geometry into a separate object me = context.scene.objects.active.data selected_faces = [p.index for p in me.polygons if p.select] bpy.ops.object.editmode_toggle() bpy.ops.mesh.duplicate() bpy.ops.mesh.separate() bpy.ops.object.editmode_toggle() me = context.scene.objects.active.data for i in selected_faces: me.polygons[i].select = True # now there will be two selected objects # the one with the new name will be the copy for ob in context.selected_objects: if ob.name != self.floorplan: fpob = ob print('floorplan copy', fpob.name) # make that copy active and selected for ob in context.selected_objects: ob.select = False fpob.select = True context.scene.objects.active = fpob if True: # add thickness # let normals of select faces point in same direction bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # add solidify modifier # NOTE: for some reason bpy.ops.object.modifier_add doesn't work here # even though fpob at this point is verifyable the active and selected object ... mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY') mod.offset = 1.0 # in the direction of the normals mod.thickness = 2000 # very thick bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() fpob.location -= Vector( (0, 0, 1000) ) # actually this should be in the negative direction of the normals not just plain downward... # make the floorboards active and selected for ob in context.selected_objects: ob.select = False context.scene.objects.active = o o.select = True # add-and-apply a boolean modifier to get the intersection with the floorplan copy bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect o.modifiers[-1].object = fpob bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean") # delete the copy bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = fpob fpob.select = True bpy.ops.object.delete() # make the floorboards active and selected context.scene.objects.active = o o.select = True if self.modify: mods = o.modifiers if len(mods) == 0: # always true bpy.ops.object.modifier_add(type='BEVEL') bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False mods[1].show_expanded = False mods[0].width = self.bevel if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf')
def versaille(rows, cols, planklength, plankwidth,longgap=0, shortgap=0, randrotx=0, randroty=0, randrotz=0, originx=0, originy=0, switch=False): o = Vector((-originx, -originy, 0)) * planklength # (8*w+w/W2)*W2 + w = 8*w*W2+w = (8*W2+1)*w = 1 w = 1.0 / (8*W2+2) #w1 = 1 - w q = w/W2 #k = w*4*W2-w #s = (k - w)/2 #d = ((s+2*w)/W2)/2 #S = s/W2 sg = shortgap s2 = sg/W2 lg = longgap dd=-q if switch else 0 planks1 = ( # rectangles (0,[(0+sg,0,0), (w*5-sg,0,0), (w*5-sg,w,0), (0+sg,w,0)]), (0,[(6*w+sg,0,0), (w*11-sg,0,0), (w*11-sg,w,0), (6*w+sg,w,0)]), (90,[(5*w,-2*w+sg,0), (w*6,-2*w+sg,0), (w*6,3*w-sg,0), (5*w,3*w-sg,0)]), (0,[(3*w+sg,3*w,0), (w*8-sg,3*w,0), (w*8-sg,w*4,0), (3*w+sg,w*4,0)]), (0,[(3*w+sg,-3*w,0), (w*8-sg,-3*w,0), (w*8-sg,w*-2,0), (3*w+sg,w*-2,0)]), (90,[(5*w,4*w+sg,0),(6*w,4*w+sg,0),(6*w,6*w-sg,0),(5*w,6*w-sg,0)]), (90,[(5*w,-3*w-sg,0),(5*w,-5*w+sg,0),(6*w,-5*w+sg,0),(6*w,-3*w-sg,0)]), # squares (0,[(0+sg,w+sg,0), (w*2-sg,w+sg,0), (w*2-sg,w*3-sg,0), (0+sg,w*3-sg,0)]), (0,[(3*w+sg,w+sg,0), (w*5-sg,w+sg,0), (w*5-sg,w*3-sg,0), (3*w+sg,w*3-sg,0)]), (0,[(6*w+sg,w+sg,0), (w*8-sg,w+sg,0), (w*8-sg,w*3-sg,0), (6*w+sg,w*3-sg,0)]), (0,[(9*w+sg,w+sg,0), (w*11-sg,w+sg,0), (w*11-sg,w*3-sg,0), (9*w+sg,w*3-sg,0)]), (0,[(0+sg,-2*w+sg,0), (w*2-sg,-2*w+sg,0), (w*2-sg,0-sg,0), (0+sg,0-sg,0)]), (0,[(3*w+sg,-2*w+sg,0), (w*5-sg,-2*w+sg,0), (w*5-sg,0-sg,0), (3*w+sg,0-sg,0)]), (0,[(6*w+sg,-2*w+sg,0), (w*8-sg,-2*w+sg,0), (w*8-sg,0-sg,0), (6*w+sg,0-sg,0)]), (0,[(9*w+sg,-2*w+sg,0), (w*11-sg,-2*w+sg,0), (w*11-sg,0-sg,0), (9*w+sg,0-sg,0)]), (0,[(3*w+sg,4*w+sg,0),(5*w-sg,4*w+sg,0),(5*w-sg,6*w-sg,0),(3*w+sg,6*w-sg,0)]), (0,[(6*w+sg,4*w+sg,0),(8*w-sg,4*w+sg,0),(8*w-sg,6*w-sg,0),(6*w+sg,6*w-sg,0)]), (0,[(3*w+sg,-5*w+sg,0),(5*w-sg,-5*w+sg,0),(5*w-sg,-3*w-sg,0),(3*w+sg,-3*w-sg,0)]), (0,[(6*w+sg,-5*w+sg,0),(8*w-sg,-5*w+sg,0),(8*w-sg,-3*w-sg,0),(6*w+sg,-3*w-sg,0)]), # pointed (0,[(0+sg,3*w,0),(2*w-sg,3*w,0),(2*w-sg,4*w,0),(w+sg,4*w,0)]), #left (0,[(w+sg,4*w,0),(2*w-sg,4*w,0),(2*w-sg,5*w-sg*2,0)]), (0,[(9*w+sg,3*w,0),(11*w-sg,3*w,0),(10*w-sg,4*w,0),(9*w+sg,4*w,0)]), #top (0,[(9*w+sg,4*w,0),(10*w-sg,4*w,0),(9*w+sg,5*w-sg*2,0)]), (0,[(0+sg,-2*w,0),(w+sg,-3*w,0),(2*w-sg,-3*w,0),(2*w-sg,-2*w,0)]), #bottom (0,[(1*w+sg,-3*w,0),(2*w-sg,-4*w+sg+sg,0),(2*w-sg,-3*w,0)]), (0,[(9*w+sg,-3*w,0),(10*w-sg,-3*w,0),(11*w-sg,-2*w,0),(9*w+sg,-2*w,0)]), #right (0,[(9*w+sg,-3*w,0),(9*w+sg,-4*w+sg*2,0),(10*w-sg,-3*w,0)]), # long pointed (90,[(2*w,0-sg,0),(2*w,-4*w+sg,0),(3*w,-5*w+sg,0),(3*w,0-sg,0)]), (90,[(8*w,0-sg,0),(8*w,-5*w+sg,0),(9*w,-4*w+sg,0),(9*w,0-sg,0)]), (90,[(2*w,w+sg,0),(3*w,w+sg,0),(3*w,6*w-sg,0),(2*w,5*w-sg,0)]), (90,[(8*w,w+sg,0),(9*w,w+sg,0),(9*w,5*w-sg,0),(8*w,6*w-sg,0)]), # corner planks (90,[(0,-2*w+sg,0),(0,3*w-sg,0),(-1*w,2*w-sg,0),(-1*w,-1*w+sg,0)]), (90,[(11*w,-2*w+sg,0),(12*w,-1*w+sg,0),(12*w,2*w-sg,0),(11*w,3*w-sg,0)]), (0,[(3*w+sg,-5*w,0),(4*w+sg,-6*w,0),(7*w-sg,-6*w,0),(8*w-sg,-5*w,0)]), (0,[(3*w+sg,6*w,0),(8*w-sg,6*w,0),(7*w-sg,7*w,0),(4*w+sg,7*w,0)]), # corner triangles (90,[(-w-s2,-w+s2*2,0),(-w-s2,2*w-s2*2,0),(-2.5*w+s2,0.5*w,0)]), (90,[(12*w+s2,2*w-s2*2,0),(12*w+s2,-w+s2*2,0),(13.5*w-s2,0.5*w,0)]), (0,[(4*w+s2*2,7*w+s2,0),(7*w-s2*2,7*w+s2,0),(5.5*w,8.5*w-s2,0)]), (0,[(4*w+s2*2,-6*w-s2,0),(5.5*w,-7.5*w+s2,0),(7*w-s2*2,-6*w-s2,0)]), # border planks # bottom (45,[(-2.5*w-q+q+dd+lg,0.5*w+q-q-dd-lg,0),(-2.5*w-2*q+q+dd+lg+lg,0.5*w-q-dd+lg-lg,0),(5.5*w-q+lg-lg,-7.5*w-q+lg+lg,0),(5.5*w-lg,-7.5*w+lg,0)]), # right (135,[(5.5*w-q+lg,-7.5*w-q+lg,0),(5.5*w+lg-lg,-7.5*w-2*q+lg+lg,0),(13.5*w+2*q+dd-lg-lg,0.5*w+dd-lg+lg,0),(13.5*w+q+dd-lg,0.5*w+q+dd-lg,0)]), #top (45,[(13.5*w-dd-lg,0.5*w+dd+lg,0),(13.5*w+q-dd-lg-lg,0.5*w+q+dd-lg+lg,0),(5.5*w+q-lg+lg,8.5*w+q-lg-lg,0),(5.5*w+lg,8.5*w-lg,0)]), #left (135,[(-2.5*w-q-dd+lg,0.5*w-q-dd+lg,0),(5.5*w+q-lg,8.5*w+q-lg,0),(5.5*w-lg+lg,8.5*w+2*q-lg-lg,0),(-2.5*w-q-q-dd+lg+lg,0.5*w+q-q-dd+lg-lg,0)]) ) verts = [] faces = [] uvs = [] left = 0 center = Vector((5.5*w,0.5*w,0))*planklength delta = Vector((w, -10*q, 0)) * planklength for col in range(cols): start = 0 for row in range(rows): origin = Vector((start, left, 0)) for uvrot,p in planks1: ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') # randomly rotate the plank a little bit around its own center pverts = [rotate(Vector(v)*planklength, rot) for v in p] pverts = [origin + delta + o + rotatep(v, Euler((0,0,radians(45)),'XYZ'), center) for v in pverts] verts.extend(pverts) midpoint = vcenter(pverts) if uvrot > 0: print(uvrot) print([v - midpoint for v in pverts]) print([rotatep(v, Euler((0,0,radians(uvrot)),'XYZ'), midpoint) - midpoint for v in pverts]) print() uvs.append([rotatep(v, Euler((0,0,radians(uvrot)),'XYZ'), midpoint) for v in pverts]) faces.append((ll, ll + 3, ll + 2, ll + 1) if len(pverts)==4 else (ll, ll + 2, ll + 1)) start += planklength left += planklength fuvs = [v for p in uvs for v in p] return verts, faces, fuvs
def planks(n, m, length, lengthvar, width, widthvar, longgap, shortgap, offset, randomoffset, nseed, randrotx, randroty, randrotz, originx, originy): #n=Number of planks, m=Floor Length, length = Planklength verts = [] faces = [] uvs = [] seed(nseed) widthoffset = 0 s = 0 e = offset c = offset # Offset per row ws = 0 p = 0 while p < n: p += 1 uvs.append([]) w = width + randuni(0, widthvar) we = ws + w if randomoffset: e = randuni(4 * shortgap, length) # we don't like negative plank lengths while (m - e) > (4 * shortgap): ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pverts = plank(s - originx, e - originx, ws - originy, we - originy, longgap, shortgap, rot) verts.extend(pverts) uvs[-1].append(deepcopy(pverts)) faces.append((ll, ll + 3, ll + 2, ll + 1)) s = e e += length + randuni(0, lengthvar) ll = len(verts) rot = Euler((randrotx * randuni(-1, 1), randroty * randuni(-1, 1), randrotz * randuni(-1, 1)), 'XYZ') pverts = plank(s - originx, m - originx, ws - originy, we - originy, longgap, shortgap, rot) verts.extend(pverts) uvs[-1].append(deepcopy(pverts)) faces.append((ll, ll + 3, ll + 2, ll + 1)) s = 0 #e = e - m if c <= (length): c = c + offset if c > (length): c = c - length e = c ws = we # randomly swap uvs of planks. Note: we only swap within one set of planks because different sets can have different widths. nplanks = len(uvs[-1]) if nplanks < 2: continue for pp in range(nplanks // 2): # // to make sure it stays an int i = randrange(nplanks - 1) swapx(uvs[-1], i) fuvs = [uv for col in uvs for plank in col for uv in plank] return verts, faces, fuvs
def updateMesh(self, context): o = context.object material_list = getMaterialList(o) if o.pattern == 'Regular': nplanks = (o.width + o.originy) / o.plankwidth verts, faces, uvs = planks(nplanks, o.length + o.originx, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.minoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Herringbone': # note that there is a lot of extra length and width here to make sure that we create a pattern w.o. gaps at the edges v = o.plankwidth * sqrt(2.0) w = o.planklength * sqrt(2.0) nplanks = int((o.width+o.planklength + o.originy*2) / v)+1 nplanksc = int((o.length + o.originx*2) / w)+1 verts, faces, uvs = herringbone(nplanks, nplanksc, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Square': rows = int((o.width + o.originy)/ o.planklength)+1 cols = int((o.length + o.originx)/ o.planklength)+1 verts, faces, uvs = square(rows, cols, o.planklength, o.nsquare, o.border, o.longgap, o.shortgap, o.randomseed, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy) elif o.pattern == 'Versaille': rows = int((o.width + o.originy)/ o.planklength)+2 cols = int((o.length + o.originx)/ o.planklength)+2 verts, faces, uvs = versaille(rows, cols, o.planklength, o.plankwidth, o.longgap, o.shortgap, o.randrotx, o.randroty, o.randrotz, o.originx, o.originy, o.borderswitch) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) # more than one object can refer to the same emesh for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() # this way the old mesh is marked as used by noone and not saved on exit bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors rot = Euler((0,0,o.uvrotation)) mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data offset = Vector() # note that the uvs that are returned are shuffled for poly in mesh.polygons: color = [rand(), rand(), rand()] if o.randomuv == 'Random': offset = Vector((rand(), rand(), 0)) if o.randomuv == 'Restricted': offset = Vector((rand()*2-1, rand()*2-1, 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): co = offset + mesh.vertices[mesh.loops[loop_index].vertex_index].co if co.x > o.length or co.x < 0: offset[0] = 0 if co.y > o.width or co.y < 0: offset[1] = 0 elif o.randomuv == 'Packed': x = [] y = [] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): x.append(uvs[mesh.loops[loop_index].vertex_index].x) y.append(uvs[mesh.loops[loop_index].vertex_index].y) offset = Vector((-min(x), -min(y), 0)) for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): if o.randomuv == 'Shuffle': coords = uvs[mesh.loops[loop_index].vertex_index] elif o.randomuv in ('Random', 'Restricted'): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co + offset elif o.randomuv == 'Packed': coords = uvs[mesh.loops[loop_index].vertex_index] + offset else: coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co coords = Vector(coords) # copy coords.x *= o.uvscalex coords.y *= o.uvscaley coords.rotate(rot) uv_layer[loop_index].uv = coords.xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len(v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert(v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len(v2.link_edges) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() # remove all modifiers to make sure the boolean will be last & only modifier n = len(o.modifiers) while n > 0: n -= 1 bpy.ops.object.modifier_remove(modifier=o.modifiers[-1].name) # add thickness bpy.ops.object.mode_set(mode='EDIT') bm = bmesh.from_edit_mesh(o.data) # extrude to give thickness ret=bmesh.ops.extrude_face_region(bm,geom=bm.faces[:]) ret=bmesh.ops.translate(bm,vec=Vector((0,0,self.thickness)),verts=[el for el in ret['geom'] if isinstance(el, bmesh.types.BMVert)] ) # trim excess flooring ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(o.length,0,0), plane_no=(1,0,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(-1,0,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,o.width,0), plane_no=(0,1,0), clear_outer=True) ret = bmesh.ops.bisect_plane(bm, geom=bm.verts[:]+bm.edges[:]+bm.faces[:], plane_co=(0,0,0), plane_no=(0,-1,0), clear_outer=True) # fill in holes caused by the trimming open_edges = [e for e in bm.edges if len(e.link_faces)==1] bmesh.ops.edgeloop_fill(bm, edges=open_edges, mat_nr=0, use_smooth=False) creases = bm.edges.layers.crease.active if creases is not None: for edge in open_edges: edge[creases] = 1 bmesh.update_edit_mesh(o.data) bpy.ops.object.mode_set(mode='OBJECT') # intersect with a floorplan. Note the floorplan must be 2D (all z-coords must be identical) and a closed polygon. if self.usefloorplan and self.floorplan != ' None ': # make the floorplan the only active an selected object bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = bpy.data.objects[self.floorplan] bpy.data.objects[self.floorplan].select = True # duplicate the selected geometry into a separate object me = context.scene.objects.active.data selected_faces = [p.index for p in me.polygons if p.select] bpy.ops.object.editmode_toggle() bpy.ops.mesh.duplicate() bpy.ops.mesh.separate() bpy.ops.object.editmode_toggle() me = context.scene.objects.active.data for i in selected_faces: me.polygons[i].select = True # now there will be two selected objects # the one with the new name will be the copy for ob in context.selected_objects: if ob.name != self.floorplan: fpob = ob # make that copy active and selected for ob in context.selected_objects: ob.select = False fpob.select = True context.scene.objects.active = fpob # add thickness # let normals of select faces point in same direction bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() # add solidify modifier # NOTE: for some reason bpy.ops.object.modifier_add doesn't work here # even though fpob at this point is verifyable the active and selected object ... mod = fpob.modifiers.new(name='Solidify', type='SOLIDIFY') mod.offset = 1.0 # in the direction of the normals mod.thickness = 2000 # very thick bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Solidify") bpy.ops.object.editmode_toggle() bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.normals_make_consistent(inside=False) bpy.ops.object.editmode_toggle() fpob.location -= Vector((0,0,1000)) # actually this should be in the negative direction of the normals not just plain downward... # at this point the floorplan object is the active and selected object if True: # make the floorboards active and selected for ob in context.selected_objects: ob.select = False context.scene.objects.active = o o.select = True # add-and-apply a boolean modifier to get the intersection with the floorplan copy bpy.ops.object.modifier_add(type='BOOLEAN') # default is intersect o.modifiers[-1].object = fpob if True: bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean") # delete the copy bpy.ops.object.select_all(action='DESELECT') context.scene.objects.active = fpob fpob.select = True bpy.ops.object.delete() # make the floorboards active and selected context.scene.objects.active = o o.select = True if self.modify: mods = o.modifiers if len(mods) == 0: # always true bpy.ops.object.modifier_add(type='BEVEL') #bpy.ops.object.modifier_add(type='EDGE_SPLIT') mods = o.modifiers mods[0].show_expanded = False #mods[1].show_expanded = False mods[0].width = self.bevel mods[0].segments = 2 mods[0].limit_method = 'ANGLE' mods[0].angle_limit = (85/90.0)*PI/2 if warped and not ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_add(type='SUBSURF') mods[-1].show_expanded = False mods[-1].levels = 2 if not warped and ('SUBSURF' in [m.type for m in mods]): bpy.ops.object.modifier_remove(modifier='Subsurf') if self.preservemats and len(material_list)>0: rebuildMaterialList(o, material_list) assignRandomMaterial(len(material_list))
def updateMesh(self, context): o = context.object verts, faces, shortedges, longedges = planks( o.nplanks, o.length, o.planklength, o.planklengthvar, o.plankwidth, o.plankwidthvar, o.longgap, o.shortgap, o.offset, o.randomoffset, o.randomseed, o.randrotx, o.randroty, o.randrotz) # create mesh &link object to scene emesh = o.data mesh = bpy.data.meshes.new(name='Planks') mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) for i in bpy.data.objects: if i.data == emesh: i.data = mesh name = emesh.name emesh.user_clear() bpy.data.meshes.remove(emesh) mesh.name = name if bpy.context.mode != 'EDIT_MESH': bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() bpy.ops.object.shade_smooth() # add uv-coords and per face random vertex colors mesh.uv_textures.new() uv_layer = mesh.uv_layers.active.data vertex_colors = mesh.vertex_colors.new().data for poly in mesh.polygons: offset = Vector((rand(), rand(), 0)) if o.randomuv else Vector( (0, 0, 0)) color = [rand(), rand(), rand()] for loop_index in range(poly.loop_start, poly.loop_start + poly.loop_total): coords = mesh.vertices[mesh.loops[loop_index].vertex_index].co uv_layer[loop_index].uv = (coords + offset).xy vertex_colors[loop_index].color = color # subdivide mesh and warp it warped = o.hollowlong > 0 or o.hollowshort > 0 or o.twist > 0 if warped: bm = bmesh.new() bm.from_mesh(mesh) # calculate hollowness for each face dshortmap = {} dlongmap = {} for face in bm.faces: dshort = o.hollowshort * rand() dlong = o.hollowlong * rand() for v in face.verts: dshortmap[v.index] = dshort dlongmap[v.index] = dlong bm.to_mesh(mesh) bm.free() # at this point all new geometry is selected and subdivide works in all selection modes bpy.ops.object.editmode_toggle() bpy.ops.mesh.subdivide() # bmesh subdivide doesn't work for me ... bpy.ops.object.editmode_toggle() bm = bmesh.new() bm.from_mesh(mesh) for v in bm.verts: if o.twist and len( v.link_edges) == 4: # vertex in the middle of the plank dtwist = o.twist * randuni(-1, 1) for e in v.link_edges: v2 = e.other_vert( v) # the vertices on the side of the plank if shortside(v2): for e2 in v2.link_edges: v3 = e2.other_vert(v2) if len(v3.link_edges) == 2: v3.co.z += dtwist dtwist = -dtwist # one corner up, the other corner down elif len(v.link_edges ) == 3: # vertex in the middle of a side of the plank for e in v.link_edges: v2 = e.other_vert(v) if len( v2.link_edges ) == 2: # hollowness values are stored with the all original corner vertices dshort = dshortmap[v2.index] dlong = dlongmap[v2.index] break if shortside(v): v.co.z -= dlong else: v.co.z -= dshort creases = bm.edges.layers.crease.new() for edge in bm.edges: edge[creases] = 1 for vert in edge.verts: if len(vert.link_edges) == 4: edge[creases] = 0 break bm.to_mesh(mesh) bm.free() if self.modify: mods = o.modifiers if len(mods) == 0: bpy.ops.object.modifier_add(type='SOLIDIFY') bpy.ops.object.modifier_add(type='BEVEL') bpy.ops.object.modifier_add(type='EDGE_SPLIT') if warped: bpy.ops.object.modifier_add(type='SUBSURF') mods = o.modifiers mods[0].show_expanded = False mods[1].show_expanded = False mods[2].show_expanded = False mods[0].thickness = self.thickness mods[1].width = self.bevel else: # maybe change this to walk the modifier stack and remove all if warped: bpy.ops.object.modifier_remove(modifier='Subsurf') bpy.ops.object.modifier_remove(modifier='EdgeSplit') bpy.ops.object.modifier_remove(modifier='Bevel') bpy.ops.object.modifier_remove(modifier='Solidify')