top of page
Search

Wall Maker v2.0 update

  • Writer: anderson Yang
    anderson Yang
  • Apr 4, 2023
  • 7 min read

2023 March Update:

1. Material added, users can replace the path of HDRI map for the skydome light.

2. Created button for automatically assigning a default materials to the bricks, which includes OSL Shader based noise pattern , displacement, and aiStandardSurface.

3. New GUI control.

4. Python in Class hierarchy


A Python script for create brick wall. This script incluides two options to choose, one is cross arrangement, the other one is without arrangement. Users can also adjust how many bricks of row and column, the minimum/maximun is 1 and 9999. There are 3 different bricks that users can choose, solid bricks, Two-holes Hollow bricks, and Three-holes Hollow bricks. And the wall is RBD ready.



Python Module


"""Script for Maya


Version 02

Author: Anderson Yang

Date: 03/17/23

Contacts:

-Instagram: yang_vfx

-Mail: besthans0127@gmail.com

Description: This code will generate bricks and wall, and if selecting the arrangement option, it can also generate cross structure wall.Also, Assigning material and environment light with Arnold renderer.


Tested on Maya 2022.3


"""

import maya.cmds as mc

import random


class OptionsWindow(object):

"""OptionWindow() base class definition is creating a window with

three buttons on the bottom. Users should be subclassing OptionsWindow()

and implementing callback functions, implementing displayOptions() method

to display custom GUI controls"""


def __init__(self):

self.window = "Wall Maker"

self.title = "Wall Maker"

self.size = (300,500)

self.actionName = "Apply and Close"

self.applyName = "Apply"


def create(self):

if mc.window(self.window,exists=True):

mc.deleteUI(self.window,window=True)


self.window = mc.window(self.window, title=self.title,widthHeight=self.size,menuBar=True)

self.mainForm = mc.formLayout(nd=100)

self.commandMenu()

self.commonButtons()

self.optionsForm = mc.formLayout(nd=100)

mc.formLayout(self.mainForm,e=True,

attachForm=([self.optionsForm,"top",0],

[self.optionsForm,"left",2],

[self.optionsForm,"right",2]),

attachControl=([self.optionsForm,"bottom",5,self.applyBtn]))

self.displayOptions()

mc.showWindow()

def commandMenu(self):

"""

commandMenu(self) method is adding pull down menu to the main window menu bar

"""

self.editMenu = mc.menu(label = "Edit")

self.editMenuTri = mc.menuItem(label = "Triangulate", command = self.editMenuTriCmd)

self.editMenuQuad = mc.menuItem(label = "Quadrangulate", command = self.editMenuQuadCmd)

self.helpMenu = mc.menu(label = "Help")

self.helpMenuItem = mc.menuItem(label = "Bugs Report on %s" % (self.title), command = self.helpMenuBugsCmd)

self.helpMenuAbout = mc.menuItem(label = "About", command = self.helpMenuAboutCmd)

def helpMenuBugsCmd(self,*args):

mc.launch(web = "https://forms.gle/xLMFcqLyyB1rmEaK6")

def editMenuSaveCmd(self,*args):pass

def editMenuResetCmd(self,*args):pass

def helpMenuAboutCmd(self, *args):

aboutInformation = mc.window(title = "Wall Maker for Maya by Anderson Yang", wh = (512, 200))

mc.rowColumnLayout(adjustableColumn = True, backgroundColor = (0.15, 0.15, 0.15))

mc.text(label = "Wall Maker for Maya 1.0 © 2023 Anderson Yang 02-13-2023")

mc.separator(height = 50, style = "out")

mc.text(label = "This is the first release of the Wall Maker for Maya.\n Please report any bugs or requests, and stay tuned for the full release.")

mc.separator(height = 50, style = "out")

mc.text(label = "Feel free to contact me directly about any issue at besthans0127@gmail.com \n ")

mc.showWindow(aboutInformation)

def actionCmd(self,*args):

"""Call back function that should be implemented in a subclass"""

# print( "ACTION" )

self.createWall()

mc.deleteUI(self.window,window=True)

def applyBtnCmd(self,*args):

"""Call back function that should be implemented in a subclass"""

#print( "APPLY" )

self.createWall()

def closeBtnCmd(self,*args):

mc.deleteUI(self.window,window=True)

def editMenuTriCmd(self, *args):

sel = mc.ls(selection = True)

for i in sel:

mc.polyTriangulate(i)

def editMenuQuadCmd(self, *args):

sel = mc.ls(selection = True)

for i in sel:

mc.polyQuad(i)

def assignMatCmd(self, *arg):

self.assigntMaterial()

mc.select("*Brick*")

mc.hyperShade(assign = brickSurface)

def assignHdriCmd(self, *arg):

self.assignHdri()



def commonButtons(self):

"""

commonButtons(self) method will edit layout self.mainForm and add three buttons on the bottom: action, apply, close

"""

self.commonBtnSize=(self.size[0]-18/3,26)

self.acctionBtn=mc.button(label=self.actionName,height=self.commonBtnSize[1], command = self.actionCmd)

self.applyBtn=mc.button(label=self.applyName,height=self.commonBtnSize[1],command=self.applyBtnCmd)

self.closeBtn = mc.button(label="Close",height=self.commonBtnSize[1],command=self.closeBtnCmd)

mc.formLayout(self.mainForm, e=True,

attachForm=([self.acctionBtn,"left",5],[self.acctionBtn,"bottom",5],[self.applyBtn,"bottom",5],[self.closeBtn,"bottom",5],[self.closeBtn,"right",5]),

attachPosition=([self.acctionBtn,"right",1,33],[self.closeBtn,"left",0,67]),

attachControl=([self.applyBtn,"left",4,self.acctionBtn],[self.applyBtn,"right",4,self.closeBtn]),

attachNone=([self.acctionBtn,"top"],[self.applyBtn,"top"],[self.closeBtn,"top"]))

def displayOptions(self):

""" displayOptions() All custom UI controlls should be added to this method

These controlls will be childred of the formLayout whose name is self.optionsForm """

# Frame layout

mc.setParent("..")

self.layout1 = mc.columnLayout(adj = True)

mc.formLayout(self.mainForm, e= True, attachForm=([self.layout1, "left", 0],[self.layout1, "right", 0]))

# Brick framlayout

self.brickFrame = mc.frameLayout(cll = True, label = "Brick")

self.subFrameBrick = mc.radioCollection()

mc.columnLayout()

self.brickType = mc.radioButtonGrp(label = "Style", labelArray3 = ["Solid", "Two Holes", "Three Holes"], numberOfRadioButtons = 3, cal = [1, "center"], onc = "createWall()")


mc.setParent("..")

mc.setParent("..")


# Mansonry Wall framlayout

self.mansonryFrame = mc.frameLayout(collapsable = True, label = "Mansonry Wall")

self.mansonryCheck = mc.radioButtonGrp(label = "", labelArray2 = ["No Arrangement", "Cross Arrangement"], numberOfRadioButtons = 2, cal = [1, "center"])

mc.setParent("..")

# Row and Column

self.wallFrame = mc.frameLayout(collapsable = True, label = "Row & Column")

self.row = mc.intSliderGrp(field=True, label = "Row", minValue = 0, maxValue = 10, fieldMinValue = 0, fieldMaxValue = 9999, value = 0, cal = [1, "center"] )

self.column = mc.intSliderGrp(field=True, label = "Column", minValue = 0, maxValue = 10, fieldMinValue = 0, fieldMaxValue = 9999, value = 0, cal = [1, "center"] )

mc.setParent("..")

self.matFrame = mc.frameLayout(collapsable = True, label = "Brick Material")

self.matButton = mc.button(label = "Assign Material", command = self.assignMatCmd)

self.lightButton = mc.button(label = "Assign Env Light", command = self.assignHdriCmd)

mc.setParent("..")

self.columnValue = mc.intSliderGrp(self.column, query = True, value = True)

self.rowValue = mc.intSliderGrp(self.row, query = True, value = True)

self.pattern = mc.radioButtonGrp(self.brickType, query = True, select = True)

self.mansonryPattern = mc.radioButtonGrp(self.mansonryCheck, query = True, select = True)

def createWall(self, *args):


# grab the value from options

self.columnValue = mc.intSliderGrp(self.column, query = True, value = True)

self.rowValue = mc.intSliderGrp(self.row, query = True, value = True)

self.pattern = mc.radioButtonGrp(self.brickType, query = True, select = True)

self.mansonryPattern = mc.radioButtonGrp(self.mansonryCheck, query = True, select = True)

# Solid bricks and no mansonry

if (self.pattern == 1 and self.mansonryPattern == 1):

for r in range(0, self.rowValue):

mc.polyCube(w = 2, h = 0.5, d = 1, name = "Brick" + str(r))

mc.move((2 * r), 0, 0)

mc.select(all = True)

mc.group(name = "G1")

for c in range(1, self.columnValue):

mc.duplicate(name = "G" + "_" + str(c))

mc.move(0, ((0.5 * c)), 0, "G_" + str(c))

mc.select(all = True)

mc.ungroup()

mc.delete(constructionHistory = True)

# Two holes bricks and no mansonry

elif (self.pattern == 2 and self.mansonryPattern == 1):

cy = mc.polyCylinder(r = 0.5)

mc.select(cy)

mc.move(-1, 0, 0)

cy1 = mc.polyCylinder(r = 0.5)

mc.select(cy1)

mc.move(1, 0, 0)

mc.select(all = True)

mc.polyBoolOp("pCylinder1", "pCylinder2", op = 1)

mc.delete(constructionHistory = True)

mc.polyCube(w = 4, h = 1, d = 2)

mc.polyBoolOp("pCube1", "polySurface1", op = 2)

mc.select("polySurface2")

mc.delete(constructionHistory = True)

mc.rename("polySurface2", "box")

for r in range(0, self.rowValue):

mc.duplicate(name = "Brick" + "_" + str(r))

mc.move((4*r), 0, 0)

mc.delete("box")

mc.select(all = True)

mc.group(name = "G1")

for c in range(1, self.columnValue):

mc.duplicate(name = "G" + "_" + str(c))

mc.move(0, (c), 0, "G_" + str(c))

mc.select(all = True)

mc.ungroup()

mc.delete(constructionHistory = True)

# Three holes bricks and no mansonry

elif (self.pattern == 3 and self.mansonryPattern == 1):

c3 = mc.polyCylinder(r = 0.5)

mc.select(c3)

mc.move(-1.3, 0, 0)

c31 = mc.polyCylinder(r = 0.5)

c32 = mc.polyCylinder(r = 0.5)

mc.select(c32)

mc.move(1.3, 0, 0)

mc.select(all = True)

mc.polyBoolOp("pCylinder1", "pCylinder2", op = 1)

mc.polyBoolOp("pCylinder3", "polySurface1", op = 1)

mc.delete(constructionHistory = True)

mc.polyCube(w = 4, h = 1, d = 2)

mc.polyBoolOp("pCube1", "polySurface2", op = 2)

mc.select("polySurface3")

mc.delete(constructionHistory = True)

mc.rename("polySurface3", "box")

for r in range(0, self.rowValue):

mc.duplicate(name = "Brick" + "_" + str(r))

mc.move((4*r), 0, 0)

mc.delete("box")

mc.select(all = True)

mc.group(name = "G1")

for c in range(1, self.columnValue):

mc.duplicate(name = "G" + "_" + str(c))

mc.move(0, (c), 0, "G_" + str(c))

mc.select(all = True)

mc.ungroup()


# Solid bricks and mansonry

elif (self.pattern == 1 and self.mansonryPattern == 2):

for m in range(0, self.rowValue):

mc.polyCube(w = 2, h = 0.5, d = 1, name = "Brick" + str(m))

mc.move(2 * (m), 0, 0)

mc.select(all = True)

mc.group(name = "G1")

for s in range(1, 2):

mc.duplicate(name = "G" + "_" + str(s))

mc.move(1, (0.5 * s), 0, "G_" + str(s))

mc.select(all = True)

mc.ungroup()

mc.group(name = "G2")

if (self.columnValue % 2 == 0):

for n in range(1, int(abs(self.columnValue*(0.5)))):

mc.duplicate(name = "G" + "_" + str(n))

mc.move(-0.001, n, 0, "G_" + str(n))

mc.select(all = True)

mc.ungroup()

if (self.columnValue % 2 == 1):

for n in range(1, int(abs(self.columnValue * 0.5))+1):

mc.duplicate(name = "G" + "_" + str(n))

mc.move(-0.001, n, 0, "G_" + str(n))

mc.ungroup()

lastLayer = mc.ls(selection = True)

print(lastLayer)

for i in range(self.rowValue, len(lastLayer)):

mc.delete(lastLayer[i])

mc.group(name = "G_")

mc.select(all = True)

mc.ungroup()

# Two holes bricks and mansonry

elif (self.pattern == 2 and self.mansonryPattern == 2):

cy = mc.polyCylinder(r = 0.5)

mc.select(cy)

mc.move(-1.3, 0, 0)

cy1 = mc.polyCylinder(r = 0.5)

mc.select(cy1)

mc.move(1.3, 0, 0)

mc.select(all = True)

mc.polyBoolOp("pCylinder1", "pCylinder2", op = 1)

mc.delete(constructionHistory = True)

mc.polyCube(w = 4, h = 1, d = 2)

mc.polyBoolOp("pCube1", "polySurface1", op = 2)

mc.select("polySurface2")

mc.delete(constructionHistory = True)

mc.rename("polySurface2", "box")

for r in range(0, self.rowValue):

mc.duplicate(name = "Brick" + "_" + str(r))

mc.move((4*r), 0, 0)

mc.delete("box")

mc.select(all = True)

mc.group(name = "G1")

for c in range(1, 2):

mc.duplicate(name = "G" + "_" + str(c))

mc.move(2, (c), 0, "G_" + str(c))

mc.select(all = True)

mc.group(name = "G2")

if (self.columnValue % 2 == 0):

for n in range(1, int(abs(self.columnValue*(0.5)))):

mc.duplicate(name = "Tw" + "_" + str(n))

mc.move(-0.001, 2*n, 0, "Tw_" + str(n))

mc.select(all = True)

mc.ungroup()

mc.ungroup()

if (self.columnValue % 2 == 1):

for n in range(1, int(abs(self.columnValue * 0.5))+1):

mc.duplicate(name = "Tw" + "_" + str(n))

mc.move(-0.001, 2*n, 0, "Tw_" + str(n))

mc.ungroup()

mc.ungroup()

lastLayer = mc.ls(selection = True)

print(lastLayer)

for i in range(self.rowValue, len(lastLayer)):

mc.delete(lastLayer[i])

mc.group(name = "Tw_")

mc.select(all = True)

mc.select("*Tw*", "*G*")

mc.ungroup()

# Three holes bricks and mansonry

elif (self.pattern == 3 and self.mansonryPattern == 2):

c3 = mc.polyCylinder(r = 0.5)

mc.select(c3)

mc.move(-1.3, 0, 0)

c31 = mc.polyCylinder(r = 0.5)

c32 = mc.polyCylinder(r = 0.5)

mc.select(c32)

mc.move(1.3, 0, 0)

mc.select(all = True)

mc.polyBoolOp("pCylinder1", "pCylinder2", op = 1)

mc.polyBoolOp("pCylinder3", "polySurface1", op = 1)

mc.delete(constructionHistory = True)

mc.polyCube(w = 4, h = 1, d = 2)

mc.polyBoolOp("pCube1", "polySurface2", op = 2)

mc.select("polySurface3")

mc.delete(constructionHistory = True)

mc.rename("polySurface3", "box")

for r in range(0, self.rowValue):

mc.duplicate(name = "Brick" + "_" + str(r))

mc.move((4*r), 0, 0)

mc.delete("box")

mc.select(all = True)

mc.group(name = "G1")

for c in range(1, 2):

mc.duplicate(name = "G" + "_" + str(c))

mc.move(2, (c), 0, "G_" + str(c))

mc.select(all = True)

mc.group(name = "G2")

if (self.columnValue % 2 == 0):

for n in range(1, int(abs(self.columnValue*(0.5)))):

mc.duplicate(name = "Tw" + "_" + str(n))

mc.move(-0.001, 2*n, 0, "Tw_" + str(n))

mc.select(all = True)

mc.ungroup()

mc.ungroup()

if (self.columnValue % 2 == 1):

for n in range(1, int(abs(self.columnValue * 0.5))+1):

mc.duplicate(name = "Tw" + "_" + str(n))

mc.move(-0.001, 2*n, 0, "Tw_" + str(n))

mc.ungroup()

mc.ungroup()

lastLayer = mc.ls(selection = True)

print(lastLayer)

for i in range(self.rowValue, len(lastLayer)):

mc.delete(lastLayer[i])

mc.group(name = "Tw_")

mc.select(all = True)

mc.select("*Tw*", "*G*")

mc.ungroup()

# create material for bricks

def assigntMaterial(self, *arg):

# OSL pattern to aiStandardSurface

pattern = mc.shadingNode("aiStandardSurface", asShader = True, name = "Pattern")

mc.setAttr(pattern+".base", 0.364)

mc.setAttr(pattern+".specular", 0.706)

mc.setAttr(pattern+".specularRoughness", 0.2)


# mix shader to constant color and osl noise pattern

oslMix = mc.shadingNode("aiMixShader", asShader = True, name = "oslMix")

mc.connectAttr(oslMix+".outColor",pattern+".baseColor")

renderOslMix = mc.sets(name=oslMix+"SG", empty=True, renderable=True, noSurfaceShader=True)

mc.connectAttr(oslMix+".outColor",renderOslMix+".surfaceShader")


# OSL Pattern

andersonOSL = mc.shadingNode("aiAndersonOSL", asShader = True, name = "Anderson_OSL_Noise")

place2dTextOsl = mc.shadingNode("place2dTexture", asUtility = True)

mc.connectAttr(place2dTextOsl+".outU",andersonOSL+".s")

mc.connectAttr(place2dTextOsl+".outV",andersonOSL+".t")

mc.setAttr(andersonOSL+".f", 0.05)

mc.setAttr(place2dTextOsl+".rotateUV", 109.161)

mc.connectAttr(andersonOSL+".resultRGB",oslMix+".shader1")


# Constant Color and color jitter

color1 = mc.shadingNode("colorConstant", asShader=True, name="color")

Jt = mc.shadingNode("aiColorJitter", asShader=True, name = "jitter")

mc.setAttr(color1+".inColor", 0.642, 0.641, 0.641, type="double3")

mc.setAttr(Jt+".spaceName", "object", type = "string")

mc.setAttr(Jt+".dataHueMin", -1)

mc.setAttr(Jt+".dataHueMax", -0.234)

mc.setAttr(Jt+".dataSeed", 1234)

mc.connectAttr(color1+".outColor", Jt+".input")

mc.connectAttr(Jt+".outColor", oslMix+".shader2")


# connect displacement

displace1 = mc.shadingNode("displacementShader", asShader = True)

OSLsg = mc.sets(name=pattern+"SG", empty=True, renderable=True, noSurfaceShader=True)

mc.connectAttr(andersonOSL+".resultRGBR",displace1+".displacement")

mc.connectAttr(displace1+".displacement",OSLsg+".displacementShader")

mc.connectAttr(pattern+".outColor",OSLsg+".surfaceShader")


# create volume noise for pattern normal

VN = mc.shadingNode("volumeNoise", asShader = True)

VNTexture = mc.shadingNode("place3dTexture", asUtility = True)

VNBump = mc.shadingNode("bump3d", asUtility = True)

mc.connectAttr(VNTexture+".matrix",VN+".placementMatrix")

mc.setAttr(VN+".noiseType", 0)

mc.connectAttr(VN+".outAlpha",VNBump+".bumpValue")

mc.connectAttr(VNBump+".outNormal",pattern+".normalCamera")


# making normal map

normalMap = mc.shadingNode("aiMixShader", asShader = True, name = "normal")

mc.connectAttr(pattern+".outColor",normalMap+".shader1")

mc.connectAttr(VNBump+".outNormal",normalMap+".shader2")

renderNormalMap = mc.sets(name=normalMap+"SG", empty=True, renderable=True, noSurfaceShader=True)

mc.connectAttr(normalMap+".outColor",renderNormalMap+".surfaceShader")


# create render surface for brick

global brickSurface

brickSurface = mc.shadingNode("aiStandardSurface", asShader = True, name = "brickSurface")

mc.setAttr(brickSurface+".baseColor", 0.365, 0.313, 0.306, type="float3")

mc.setAttr(brickSurface+".specular", 0.111)

bumpSurface = mc.shadingNode("bump2d", asShader = True)

mc.connectAttr(normalMap+".outColorR",bumpSurface+".bumpValue")

mc.connectAttr(bumpSurface+".outNormal",brickSurface+".normalCamera")

# Create SkyDome light and assign it HDRI

def assignHdri(self, *arg):

skydome = mc.shadingNode("aiSkyDomeLight", asLight=True)

skyHdri = mc.shadingNode("file", asTexture = True)

place2dText4 = mc.shadingNode("place2dTexture", asUtility = True)

hdriPath = "C:/Users/Anderson/Documents/hdri/garden_nook_4k.exr"

mc.setAttr(skyHdri+".fileTextureName",hdriPath,type = "string")

mc.connectAttr(place2dText4+".outUV", skyHdri+".uvCoord")

mc.connectAttr(place2dText4+".coverage",skyHdri+".coverage")

mc.connectAttr(place2dText4+".translateFrame",skyHdri+".translateFrame")

mc.connectAttr(place2dText4+".rotateFrame",skyHdri+".rotateFrame")

mc.connectAttr(place2dText4+".mirrorU",skyHdri+".mirrorU")

mc.connectAttr(place2dText4+".mirrorV",skyHdri+".mirrorV")

mc.connectAttr(place2dText4+".stagger",skyHdri+".stagger")

mc.connectAttr(place2dText4+".wrapU",skyHdri+".wrapU")

mc.connectAttr(place2dText4+".wrapV",skyHdri+".wrapV")

mc.connectAttr(place2dText4+".repeatUV",skyHdri+".repeatUV")

mc.connectAttr(place2dText4+".offset",skyHdri+".offset")

mc.connectAttr(place2dText4+".rotateUV",skyHdri+".rotateUV")

mc.connectAttr(place2dText4+".noiseUV",skyHdri+".noiseUV")

mc.connectAttr(place2dText4+".vertexUvOne",skyHdri+".vertexUvOne")

mc.connectAttr(place2dText4+".vertexUvTwo",skyHdri+".vertexUvTwo")

mc.connectAttr(place2dText4+".vertexUvThree",skyHdri+".vertexUvThree")

mc.connectAttr(place2dText4+".vertexCameraOne",skyHdri+".vertexCameraOne")

mc.connectAttr(skyHdri+".outColor",skydome+".color")


def finalProjectAndersonYang():

testWindow = OptionsWindow()

testWindow.create()

 
 
 

Comments


bottom of page