"""Nebelchor: flowing ghost ribbons and mask/bell silhouettes from Phase 3.""" from math import sin, cos, pi from common import ellipsoid, ring, beam from reference_geometry import r_plate, r_rock, r_sweep, r_lathe, r_arch_shell def n_ribbon(name,points,widths,mat): if name.startswith('Head_ChoirHorn'): return r_sweep(name,points,widths,mat,6,ribbon=True) # One interpolated section per span gives flowing curves instead of zigzag rods. from mathutils import Vector refined=[]; radii=[] for i in range(len(points)-1): p0=Vector(points[max(i-1,0)]); p1=Vector(points[i]) p2=Vector(points[i+1]); p3=Vector(points[min(i+2,len(points)-1)]) for t in (0,.5): p=.5*((2*p1)+(-p0+p2)*t+(2*p0-5*p1+4*p2-p3)*t*t+(-p0+3*p1-3*p2+p3)*t*t*t) refined.append(tuple(p)); radii.append(widths[i]*(1-t)+widths[i+1]*t) refined.append(points[-1]);radii.append(widths[-1]) return r_sweep(name,refined,radii,mat,6,ribbon=True) def n_mask(name,loc,scale,m,singing=False): x,y,z=loc outline=[(-.12,.14),(-.05,.24),(.055,.22),(.145,.11),(.12,-.075),(0,-.24),(-.12,-.08)] r_plate(name,loc,[(a*scale,b*scale) for a,b in outline],.09*scale,m['light'],.055*scale) for s in [-1,1]: r_plate(name+'_Eye'+str(s),(x+s*.065*scale,y-.091*scale,z+.025*scale), [(s*-.032*scale,.005*scale),(s*.030*scale,.027*scale),(s*.027*scale,-.014*scale),(s*-.019*scale,-.040*scale)], .012,m['accent'],.003) if singing: r_rock(name+'_Mouth',(x,y-.092*scale,z-.09*scale),(.035*scale,.018*scale,.061*scale),m['primary']) def n_wisps(m,wide=False,tall=False): """Tapering curved ribbons replace human legs and the rigid cone skirt.""" top=1.16 if tall else .90 narrow=.55 if tall and not wide else 1 for s,side in [(-1,'L'),(1,'R')]: spread=.28 if wide else .16 pts=[(s*spread,.08,top),(s*.08,.06,top*.75),(s*.20,.025,top*.54), (s*.075,0,top*.34),(s*.20,-.015,top*.17),(s*.26,-.025,.055),(s*.36,-.025,.075)] n_ribbon('Body_Wisp'+side,pts,[v*narrow for v in [.15 if wide else .11,.18,.14,.085,.048,.03,0]],m['secondary']) pts2=[(s*.16,.16,top*.86),(s*.33,.10,top*.64),(s*.18,.07,top*.39), (s*.35,.03,.20),(s*.30,.015,.08),(s*.22,0,.01)] n_ribbon('Body_Tail'+side,pts2,[v*narrow for v in [.09,.105,.085,.057,.025,0]],m['primary']) n_ribbon('Body_CentralFlow',[(0,.06,top),(-.10,-.055,top*.73),(.13,-.11,top*.46),(-.04,-.09,top*.19),(.07,-.08,.12)], [v*narrow for v in [.18,.24 if wide else .16,.16,.045,0]],m['primary']) def n_hood(m,up=False,z=1.22): n_mask('Head_Mask',(0,-.15,z),1.0,m) n_ribbon('Head_CurledHood',[(.14,.045,z-.10),(.09,.06,z+.15),(-.10,.04,z+.28), (-.22,.015,z+.31),(-.25,0,z+.42),(-.15,-.01,z+.43)], [.18,.17,.13,.075,.04,0],m['secondary']) def n_crescent(name,loc,scale,m,light=True,flip=1): x,y,z=loc pts=[(x-flip*.13*scale,y,z+.17*scale),(x-flip*.17*scale,y,z), (x-flip*.045*scale,y-.01,z-.14*scale),(x+flip*.15*scale,y-.02,z-.13*scale), (x+flip*.23*scale,y-.02,z-.025*scale)] n_ribbon(name,pts,[0,.085*scale,.10*scale,.06*scale,0],m['light'] if light else m['secondary']) def n_tank(up,m): n_wisps(m,up) n_hood(m,up,1.20 if up else 1.14) for k in range(3): z=.89-k*.16 w=(.40 if up else .27)-k*.045 outline=[(-w,.10),(0,.045),(w,.10),(w*.65,-.11),(0,-.21),(-w*.65,-.11)] # Each layer is a thick wrapped plate, with a light inner leading edge. r_plate('Body_WrappedArmor'+str(k),(0,-.12,z),outline,.26,m['light'] if up and k%2==0 else m['secondary']) for s,side in [(-1,'L'),(1,'R')]: n_ribbon('Arm'+side,[(s*.19,.04,1.02),(s*.32,0,.94),(s*.38,-.06,.75)], [.11,.13,.08],m['secondary']) if up: n_ribbon('Arm'+side+'_GreatShield',[(s*.29,-.12,.67),(s*.51,-.08,.81), (s*.48,-.05,1.13),(s*.37,-.01,1.39)], [0,.19,.18,0],m['light']) n_ribbon('Arm'+side+'_ShieldInlay',[(s*.35,-.145,.74),(s*.48,-.12,.90),(s*.43,-.09,1.15)], [0,.11,0],m['secondary']) else: n_crescent('Weapon'+side+'_Claw',(s*.33,-.09,.79),.82,m,flip=s) def n_dancer(up,m): n_wisps(m,False,True) n_hood(m,up,1.31) for s,side in [(-1,'L'),(1,'R')]: high=(s<0 and not up) tip=(s*.46,-.15,1.49 if high else .87) n_ribbon('Arm'+side,[(s*.12,.025,1.12),(s*.31,.015,1.20 if high else 1.02),tip], [.085,.10,.055],m['secondary']) if not up: r_sweep('Weapon'+side+'_Sickle',[tip,(tip[0]+s*.12,-.17,tip[2]-.12), (tip[0]+s*.11,-.19,tip[2]-.28)],[.045,.045,0],m['light'],5) if up: pivot=(.27,-.25,.94) r_rock('Weapon_ShearPivot',pivot,(.065,.04,.065),m['accent']) for s,side in [(-1,'Lower'),(1,'Upper')]: n_ribbon('Weapon_Shear'+side,[pivot,(.48,-.25,.94+s*.16),(.70,-.21,.94+s*.24),(.78,-.17,.94+s*.40)], [.045,.115,.095,0],m['light']) pts=[(.22,-.245,.94),(.01,-.24,.94+s*.14),(-.16,-.21,.94+s*.10), (-.15,-.20,.94-s*.045),(.02,-.225,.94-s*.02),(.20,-.245,.94)] n_ribbon('Weapon_ShearLoop'+side,pts,[.025,.035,.035,.035,.035,.025],m['light']) n_ribbon('Head_CrescentCrown',[(.04,.03,1.44),(-.10,.02,1.64),(-.04,0,1.76)], [.095,.105,0],m['light']) def n_horn(name,loc,radius,depth,m,axis): r_lathe(name,loc,[(0,0),(.035,.015),(.048,depth*.42),(radius*.55,depth*.78), (radius,depth),(radius*.82,depth),(radius*.42,depth*.78),(.022,depth*.30),(0,depth*.29)], m['light'],axis,10) from mathutils import Vector lip=Vector(loc)+Vector(axis).normalized()*depth r_lathe(name+'_MintLip',lip,[(radius*1.015,-.025),(radius*1.025,.01), (radius*.80,.01),(radius*.80,-.025)],m['accent'],axis,10) def n_ranged(up,m): n_wisps(m,False,True) n_hood(m,up,1.29) if up: for s,side in [(-1,'L'),(1,'R')]: n_ribbon('Arm'+side,[(s*.14,0,1.06),(s*.28,-.16,.97),(s*.43,-.20,1.04)], [.09,.10,.025],m['light']) n_ribbon('Weapon_HornArch'+side,[(s*.14,.09,1.24),(s*.28,.10,1.48), (s*.45,.05,1.49),(s*.55,-.05,1.32)], [.14,.13,.115,.08],m['secondary']) n_horn('Weapon_Horn'+side,(s*.54,-.025,1.36),.23,.43,m,(s*.28,-.8,-.35)) else: n_horn('Weapon_MouthHorn',(.025,-.25,1.24),.13,.60,m,(1,-.22,-.03)) n_ribbon('ArmL',[(-.18,0,1.06),(-.23,-.17,1.10),(.16,-.25,1.19)], [.10,.095,.035],m['light']) n_ribbon('ArmR',[(.15,0,1.07),(.30,-.12,1.02),(.38,-.27,1.19)], [.09,.10,.025],m['secondary']) def n_bell(up,m): if up: n_wisps(m,True) r_arch_shell('Body_CathedralShell',(0,.045,0),[(.13,1.48),(.22,1.15),(.43,.58),(.48,.48), (.43,.45),(.35,.60),(.15,1.17),(.085,1.48)],m['secondary']) ring('Body_BellSkirt',(0,.045,.49),.46,.055,m['light'],segments=14) arch=[(-.38,-.13,.54),(-.29,-.115,.98),(-.12,-.05,1.34),(0,-.01,1.45), (.12,-.05,1.34),(.29,-.115,.98),(.38,-.13,.54)] n_ribbon('Body_CathedralFrontArch',arch,[.035]*len(arch),m['light']) beam('Weapon_ClapperChain',(0,-.055,1.27),(0,-.075,.84),.016,m['accent'],vertices=6) r_rock('Weapon_Clapper',(0,-.075,.80),(.125,.11,.15),m['accent']) n_mask('Body_ArchMask',(0,-.07,1.22),.48,m) for s,side in [(-1,'L'),(1,'R')]: n_ribbon('Head_Spire'+side,[(s*.17,.055,1.27),(s*.28,.055,1.53), (s*.24,.05,1.69)],[.085,.07,0],m['light']) n_crescent('Arm'+side+'_Sickle',(s*.43,0,.89),1,m,flip=s) n_ribbon('Head_CentralSpire',[(0,.05,1.42),(-.025,.06,1.71),(.02,.02,1.83)], [.10,.065,0],m['light']) else: n_wisps(m,True) n_hood(m,False,1.39) axis=(0,-.85,-.40) r_lathe('Weapon_HangingBell',(0,.03,1.15),[(0,0),(.16,.02),(.22,.14),(.28,.42),(.44,.68), (.45,.73),(.38,.73),(.23,.43),(.16,.15),(0,.12)],m['secondary'],axis,12) from mathutils import Vector lip=Vector((0,.03,1.15))+Vector(axis).normalized()*.70 r_lathe('Weapon_BellRim',lip,[(.455,0),(.46,.045),(.375,.045),(.375,0)],m['light'],axis,12) beam('Weapon_ClapperStem',(0,-.08,1.10),(0,-.55,.80),.018,m['accent'],vertices=6) r_rock('Weapon_Clapper',(0,-.56,.78),(.10,.085,.115),m['accent']) for s,side in [(-1,'L'),(1,'R')]: n_ribbon('Arm'+side,[(s*.18,.07,1.21),(s*.41,.02,1.13), (s*.36,-.26,1.02),(s*.23,-.30,1.12)], [.13,.15,.11,.02],m['secondary']) def n_singer(up,m): n_wisps(m,up,True) n_hood(m,up,1.33) # Singing mask has an open mouth, and floating masks have their own wisps. r_rock('Head_SingingMouth',(0,-.248,1.23),(.035,.018,.061),m['primary']) for k in range(2): r_plate('Body_ChoirCollar'+str(k),(0,-.115,1.08-k*.13),[(-.25,.12),(0,.045),(.25,.12),(.17,-.045),(0,-.14),(-.17,-.045)], .17,m['light'] if k==0 else m['secondary']) r_rock('Body_ChoirGem',(0,-.225,.93),(.065,.045,.105),m['accent']) for s,side in [(-1,'L'),(1,'R')]: n_ribbon('Arm'+side,[(s*.18,0,1.04),(s*.32,-.035,.91),(s*.40,-.11,1.02)], [.11,.12,.05],m['secondary']) n_crescent('Arm'+side+'_Cuff',(s*.41,-.10,1.04),1,m,flip=-s) floating=[(.42,.06,1.52)] if not up else [(-.40,.09,1.53),(.38,.08,1.50),(.28,.16,1.86)] for k,loc in enumerate(floating): x,y,z=loc n_mask('Head_ChoirMask'+str(k),loc,.60,m,True) n_ribbon('Head_ChoirWisp'+str(k),[(x,y,z-.08),(x-.055,y+.025,z-.20),(x+.02,y,z-.27)], [.06,.04,0],m['secondary']) for s in [-1,1]: n_ribbon('Head_ChoirHorn'+str(k)+'_'+str(s),[(x+s*.06,y+.02,z+.09), (x+s*.13,y+.02,z+.20),(x+s*.09,y,z+.25)],[.045,.045,0],m['light']) if up: for s in [-1,1]: n_ribbon('Head_GreatHorn'+str(s),[(s*.10,.06,1.46),(s*.23,.04,1.65),(s*.16,0,1.79)], [.09,.08,0],m['light']) def build_nebelchor(spec,m): role=spec['role']; up=spec['upgraded'] {'tank':n_tank,'melee':n_dancer,'ranged':n_ranged,'artillery':n_bell,'support':n_singer}[role](up,m)