def create(self, dson_material, sg_node): self.material = pm.shadingNode('lambert', asShader=True) pm.rename(self.material, 'Mat_Viewport_%s' % mh.cleanup_node_name(self.name)) self.material.attr('diffuse').set(1) material_type = self._get_dson_material_type(dson_material) self.set_attr_to_texture_with_color(self.material.attr('color'), self.images.get('diffuse'), self.channels['diffuse'], nodeName=self.name) if material_type == 'studio/material/uber_iray': # Refraction isn't really opacity, but we'll approximate it that way in the viewport. refraction_opacity = self.get_texture_with_alpha( self.images.get('Refraction Weight'), self.channels['Refraction Weight'], zero_is_invisible=True) transparency = self.get_texture_with_alpha( self.images.get('Cutout Opacity'), self.channels['Cutout Opacity']) # "Transparency" is a terrible way to represent opacity, because instead of just multiplying # values to combine them, you have to do 1-((1-t1)*(1-t2)). That gives an ugly shader. # Cutout opacity and refraction are used for very different types of materials and I've never # seen them used together, so we cheat here and just add them. transparency = mh.math_op('add', transparency, refraction_opacity) else: transparency = self.get_texture_with_alpha( self.images.get('transparency'), self.channels['transparency']) # If transparency is constant, don't let it be 0. Clamp it to 0.5, so it's not completely # invisible in the viewport. In the real materials there are usually other things causing # it to be visible, like reflections or refraction. Hack: don't do this for certain eye # materials, or it'll wash out eyes. allow_completely_transparent_shaders = [ 'EyeMoisture', 'Cornea', ] allow_completely_transparent = any( s in str(dson_material) for s in allow_completely_transparent_shaders) if not isinstance(transparency, pm.PyNode) and not allow_completely_transparent: transparency = min(transparency, 0.5) mh.set_or_connect(self.material.attr('transparency'), transparency) # Connect the material. Force this connection, so if it's already connected to lambert1 # we'll override it. self.material.attr('outColor').connect(sg_node.attr('surfaceShader'), f=True)
def create(self, dson_material, sg_node): super(MaterialPlastic, self).create(dson_material, sg_node) material = pm.shadingNode('aiStandard', asShader=True) pm.rename(material, 'Mat_Arnold_%s' % mh.cleanup_node_name(self.name)) # Don't apply transparency if there's no texture and transparency is 1 (transparency is really alpha). if self.channels['transparency'] < 1 or self.images.get('transparency'): self.set_attr_to_transparency(material.attr('opacity'), self.images.get('transparency'), self.channels['transparency'], zero_is_invisible=True) self.uses_transparency = True # Bump # Daz has a positive and negative bump value. That's odd and I'm not sure if anyone actually uses this. # This isn't used for now. bump_negative = self.channels['bump_min'] bump_positive = self.channels['bump_max'] bump_scale = abs(bump_positive - bump_negative) if bump_scale > 0: self._set_normal_map(material, bump_texture=self.images.get('bump'), bump_scale=bump_scale * 0.5) # # reflectionStrength = self.channels['Reflection Strength'] # # if reflectionStrength > 0: # # pass # # Specular (XXX untested) specular_strength = self.channels.get('specular_strength', 0) if specular_strength > 0: mh.set_or_connect(material.attr('Ks'), specular_strength) # We currently ignore any glossiness map. You can set one, but Iray seems to ignore it. # self.set_attr_to_roughness_from_glossiness(self.images.get('glossiness'), self.channels['glossiness'], spec_layer.node.attr('roughness')) self.set_attr_to_roughness_from_glossiness(None, self.channels['glossiness'], material.attr('specularRoughness')) self.set_attr_to_texture_with_color(material.attr('KsColor'), self.images.get('specular'), self.channels['specular']) # Diffuse color. We don't currently implement textures for diffuse strength. self.set_attr_to_texture_with_color(material.attr('color'), self.images.get('diffuse'), self.channels['diffuse']) self.set_attr_to_texture_with_color(material.attr('Kd'), self.images.get('diffuse_strength'), self.channels['diffuse_strength'], mode='r') # Unimplemented: ambient/ambient_strength, reflection/reflection_strength, refraction/refraction_strength/ior, # displacement/displacement_min/displacement_max, normal, u_offset/u_scale/v_offset/v_scale self._post_create(sg_node, material)
def create(self, dson_material, sg_node): super(MaterialDazShader, self).create(dson_material, sg_node) material = pm.shadingNode('aiStandard', asShader=True) pm.rename(material, 'Mat_Arnold_%s' % mh.cleanup_node_name(self.name)) diffuse_weight = 1 # Bump: if self.channels['Bump Active']: # XXX: Normal maps? self._set_normal_map(material, bump_texture=self.images.get('Bump Strength'), bump_scale=self.channels.get('Bump Strength', 0) * 0.025) if self.channels['Opacity Active'] and (self.channels['transparency'] < 1 or self.images.get('transparency')): self.set_attr_to_transparency(material.attr('opacity'), self.images.get('transparency'), self.channels['transparency'], zero_is_invisible=True) self.uses_transparency = True # Specular (Primary) if self.channels['Specular Active']: self.set_attr_to_texture_with_color(material.attr('KsColor'), self.images.get('Specular Color'), self.channels['Specular Color']) self.set_attr_to_roughness_from_glossiness(self.images.get('Glossiness'), self.channels['Glossiness'], material.attr('specularRoughness')) specular_strength = self.channels['Specular Strength'] # diffuse_weight = mh.math_op('sub', diffuse_weight, specular_strength) mh.set_or_connect(material.attr('Ks'), specular_strength) # Diffuse if self.channels['Diffuse Active'] and self.channels['Diffuse Strength'] > 0: self.set_attr_to_texture_with_color(material.attr('color'), self.images.get('diffuse'), self.channels['diffuse']) diffuse_weight = mh.math_op('mult', diffuse_weight, self.channels['Diffuse Strength']) mh.set_or_connect(material.attr('Kd'), diffuse_weight) self.set_attr_to_texture_with_color(material.attr('diffuseRoughness'), self.images.get('Diffuse Roughness'), self.channels['Diffuse Roughness'], mode='alpha') self._post_create(sg_node, material)
def set_attr_to_roughness_from_glossiness(self, texture, value, output_attr): value = self.get_roughness_from_glossiness(texture, value) mh.set_or_connect(output_attr, value)
def set_attr_to_transparency(self, output_attr, *args, **kwargs): texture_node = self.get_texture_with_alpha(*args, **kwargs) mh.set_or_connect(output_attr, texture_node)
def set_attr_to_texture_with_color(self, output_attr, *args, **kwargs): texture_node = self.get_texture_with_color(*args, **kwargs) mh.set_or_connect(output_attr, texture_node)
def create(self, dson_material, sg_node): super(MaterialDazBrick, self).create(dson_material, sg_node) material = pm.shadingNode('aiStandard', asShader=True) pm.rename(material, 'Mat_Arnold_%s' % mh.cleanup_node_name(self.name)) # Don't apply transparency if there's no texture and transparency is 1 (transparency is really alpha). if self.channels['transparency'] < 1 or self.images.get('transparency'): self.set_attr_to_transparency(material.attr('opacity'), self.images.get('transparency'), self.channels['transparency'], zero_is_invisible=True) self.uses_transparency = True # Normals: # # This material has a positive and negative bump value. That's odd and I'm not sure if anyone actually uses this. bump_negative = self.channels.get('Negative Bump', 0) bump_positive = self.channels.get('Positive Bump', 0) bump_scale = abs(bump_positive - bump_negative) bump_scale = mh.math_op('mult', bump_scale, self.channels['Bump Strength']) self._set_normal_map(material, normal_texture=self.images.get('Normal Map'), bump_texture=self.images.get('Bump Strength'), bump_scale=bump_scale*0.5) # # reflectionStrength = self.channels['Reflection Strength'] # # if reflectionStrength > 0: # # pass # Specular 1. specularStrength = self.channels.get('Specular Strength', 0) if specularStrength > 0: # XXX: calibrate material.attr('Ks').set(specularStrength * 0.075) # We currently ignore any glossiness map. You can set one, but Iray seems to ignore it. # self.set_attr_to_roughness_from_glossiness(self.images.get('Glossiness'), self.channels['Glossiness'], material.attr('specularRoughness')) self.set_attr_to_roughness_from_glossiness(None, self.channels['Glossiness'], material.attr('specularRoughness')) self.set_attr_to_texture_with_color(material.attr('KsColor'), self.images.get('Specular Color'), self.channels['Specular Color']) # # # Specular 2. This is a phong specular. This isn't very well tested. # specular2Strength = self.channels['value222'] # if specular2Strength > 0: # pass # This material allows Diffuse Strength to be greater than 1, but aiStandard doesn't, # so apply diffuse strength as part of the diffuse color instead. #diffuse_color = util.srgb_vector_to_linear(self.channels['diffuse']) #diffuse_color = mh.math_op('mult', diffuse_color, self.channels['Diffuse Strength']) #diffuse_texture_node = self.find_or_create_texture(path=self.images.get('diffuse')) #if diffuse_texture_node is not None: # diffuse_color = mh.math_op('mult', diffuse_color, diffuse_texture_node.attr('outColor')) #mh.set_or_connect(material.attr('color'), diffuse_color) #mh.set_or_connect(material.attr('Kd'), 1) diffuse_color = self.get_texture_with_color(self.images.get('diffuse'), self.channels['diffuse']) mh.set_or_connect(material.attr('color'), diffuse_color) # Note that the diffuse strength isn't quite the same as a multiplier to the diffuse color, # since it's a layering weight and affected by other material layers. diffuse_strength = self.get_texture_with_color(self.images.get('Diffuse Strength'), self.channels['Diffuse Strength'], mode='alpha') if not isinstance(diffuse_strength, pm.PyNode): diffuse_strength = min(diffuse_strength, 1) mh.set_or_connect(material.attr('Kd'), diffuse_strength) # Subsurface # # "value23" is "Subsurface Off - On". # "Ambient Strength" is "Subsurface Strength" (huh?). # "Ambient Color" is "Subsurface Color" # Multiply these together to get the SSS weight, and to see if we need to set up SSS at # all. "Subsurface Off - On" is probably 0 or 1 most of the time. # # This material's scatter is very different from ours, so we don't really try to emulate # it. We just set up basic texture maps if available, so it's easier to turn it on manually. scatter_weight = self._scatter_weight() # If we have an ambient color (which is actually Subsurface Color), connect it to SSS color. # Otherwise, connect the diffuse color, since it's the usually what you want if you're turning # on simple SSS. self.set_attr_to_texture_with_color(material.attr('KsssColor'), self.images.get('Ambient Color'), [1,1,1]) # Set a reasonable default for skin SSS. This won't be used unless SSS is actually weighted on. material.attr('sssRadius').set((1, 0.5, 0.25)) # XXX: Not implemented: ambient, displacement, opacity, reflection, shadows, tiling, velvet self._post_create(sg_node, material)
def _create_metallic(self, dson_material, sg_node, metallic=False, top_weight=1): """ Create a material for "PBM Metallicity",. If metallic is true, create a material for metallicity 1. Otherwise, create metallicity 0. top_weight is the weight for this layer. If we're not being added to a layeredShader this will be 1. This is multiplied into the cutout opacity. """ assert self.channels['Base Mixing'] == 0 material = pm.shadingNode('aiStandard', asShader=True) cutout_opacity = self.get_texture_with_alpha(self.images.get('Cutout Opacity'), self.channels['Cutout Opacity'], mode='rgb', zero_is_invisible=True) if cutout_opacity != 1: # Tricky: We need to set uses_transparency if the final material will be transparent. In this # case, that's only if the actual cutout opacity value isn't 1, not the value combined with # top_weight. If top_weight is 0.25, then the other metallicity layer will have a top_weight # of 0.75 and the final material won't be transparent due to that. self.uses_transparency = True # Include the layer's weight in opacity. cutout_opacity = mh.math_op('mult', cutout_opacity, top_weight) mh.set_or_connect(material.attr('opacity'), cutout_opacity) # Turn off diffuse by default. We'll turn it on later if we want it. mh.set_or_connect(material.attr('Kd'), 0) # Bump: bump_strength = self.channels.get('Bump Strength', 0) self._set_normal_map(material, normal_texture=self.images.get('Normal Map'), bump_texture=self.images.get('Bump Strength'), bump_scale=bump_strength*0.025) # Diffuse. Set this even though in some cases we won't use it, so texture connections are available # during material tweaking. self.set_attr_to_texture_with_color(material.attr('color'), self.images.get('diffuse'), self.channels['diffuse']) self.set_attr_to_texture_with_color(material.attr('diffuseRoughness'), self.images.get('Diffuse Roughness'), self.channels['Diffuse Roughness'], mode='alpha') # Shared glossy settings # # Grr. Arnold's specular behaves completely differently when it has a value of 0 than 0.001, and always # reflects a ton of light even with low weights. This makes it act like a mirror, and makes texture # mapped roughness behave strangely. Clamp roughness to 0.001 so this doesn't happen. roughness = self.get_texture_with_color(self.images.get('Glossy Roughness'), self.channels['Glossy Roughness'], mode='alpha') roughness = mh.math_op('clamp', roughness, 0.001, 1) mh.set_or_connect(material.attr('specularRoughness'), roughness) # Convert anisotropy from [0,1] to [0.5,1]. With this material, 0.5 is isotropic and values towards 0 and 1 # are anisotropic in each axis. anisotropy = self.get_texture_with_color(self.images.get('Glossy Anisotropy'), self.channels['Glossy Anisotropy'], mode='r') anisotropy = mh.math_op('mult', anisotropy, 0.5) anisotropy = mh.math_op('add', anisotropy, 0.5) mh.set_or_connect(material.attr('specularAnisotropy'), anisotropy) self.set_attr_to_texture_with_color(material.attr('specularRotation'), self.images.get('Glossy Anisotropy Rotations'), self.channels['Glossy Anisotropy Rotations'], mode='alpha') material.attr('enableInternalReflections').set(0) # Always enable fresnel. If we don't want fresnel, we'll just set Ksn to 1. This has the same # effect on weighting, but avoids the weird side-effect of making the diffuse channel blending mode # change as if FresnelAffectDiff is false. material.attr('specularFresnel').set(1) material.attr('Ksn').set(1) # The top-level mixing is clamped: each layer is added in order with its weight, and once # we reach 100% no further layers are added. remaining_weight = 1 # Refraction # # This is on top regardless of whether we're metallic or not. refraction_weight = self.get_texture_with_color(self.images.get('Refraction Weight'), self.channels['Refraction Weight'], mode='alpha') mh.set_or_connect(material.attr('Kt'), refraction_weight) material.attr('dispersionAbbe').set(self.channels['Abbe']) # Refraction Index in refraction isn't actually the IOR of refraction. It's really the IOR for reflections # on top of refractions. There seems to be no IOR built into refractions for this material. # material.attr('IOR').set(self.channels['Refraction Index']) if isinstance(refraction_weight, pm.PyNode) or refraction_weight > 0: self.uses_transparency = True # Only set these if we have any refraction, so we don't create connections to glossiness if we're not using it. # # If the Share Glossy Inputs setting is true, use the reflection settings for roughness/glossiness and color. # Note that we don't connect the roughness value, since the metallicity adjustments we make for # specular roughness shouldn't be made to refraction roughness (a non-metallic surface should have # rough reflections, but not rough refraction). share_glossy_inputs = self.channels['Share Glossy Inputs'] diffuse_channel_name = 'Glossy Color' if share_glossy_inputs else 'Refraction Color' self.set_attr_to_texture_with_color(material.attr('KtColor'), self.images.get(diffuse_channel_name), self.channels[diffuse_channel_name]) self.set_attr_to_texture_with_color( material.attr('refractionRoughness'), self.images.get('Glossy Roughness' if share_glossy_inputs else 'Refraction Roughness'), self.channels['Glossy Roughness' if share_glossy_inputs else'Refraction Roughness'], mode='alpha') # Subtract the weight used by refraction. The remainder is the amount available for the remaining layers. remaining_weight = mh.math_op('sub', remaining_weight, refraction_weight) # Refraction reflections # # The top refraction layer has its own built-in reflections. If you have Glossy Layered Weight on with # 100% refraction, this is the reflection you're seeing, not anything in the metallic or plastic layer. # # Unlike the other reflection layers, this one isn't multiplied by diffuse color. This makes this tricky, # since we only have one main glossy layer to work with. Currently we only implement this if refraction # is 100%, which means none of the other layers are visible. If refraction is less than 100% or textured, # we won't set up this glossy layer (but you'll get the glossiness layers beneath it instead). glossy_layered_weight = self.get_texture_with_color(self.images.get('Glossy Layered Weight'), self.channels['Glossy Layered Weight'], mode='alpha') reflection_ior = self.channels['Refraction Index'] if remaining_weight == 0 and glossy_layered_weight != 0 and reflection_ior != 1: facing_reflectance = _ior_to_schlick(reflection_ior) log.debug('%s using refraction reflections, %s %s', dson_material, reflection_ior, facing_reflectance) mh.set_or_connect(material.attr('Ksn'), facing_reflectance) # fresnel_ramp = schlick.create_ramp_for_schlick(facing_reflectance, max_points=16) # glossy_layered_weight = mh.math_op('mult', glossy_layered_weight, fresnel_ramp) mh.set_or_connect(material.attr('Ks'), glossy_layered_weight) return material # Metallic glossiness if metallic: # Disable diffuse for the metallic layer. We're using up the rest of the layering weight, so there's # no diffuse underneath it. mh.set_or_connect(material.attr('Kd'), 0) # This is the metallic layer. This layer is completely specular, minus any weight used up by refraction. # (The glossiness weight for the metallicity layer is the metallicity, and we're implementing metallicity 1.) mh.set_or_connect(material.attr('Ks'), remaining_weight) # When metallic, the fresnel reflectance is always 0.7. mh.set_or_connect(material.attr('Ksn'), 0.7) # top_coat_directional_normal_color for metallic seems to be the base color, and top_coat_directional_grazing_color # is white. The IOR is 0.7 which gives a lot of reflectance at the facing angle anyway, so we just mix the base # color into the glossy color. glossy_color = self.get_texture_with_color(self.images.get('Glossy Color'), self.channels['Glossy Color']) diffuse_color = self.get_texture_with_color(self.images.get('diffuse'), self.channels['diffuse']) glossy_color_combined = mh.math_op('mult', diffuse_color, glossy_color) mh.set_or_connect(material.attr('KsColor'), glossy_color_combined) return material # This is the plastic layer. None of the rest applies to the metallic layer. # # Backscatter (not sub-surface scatter) # # When this is enabled, an object can be lit from behind. The usual example is paper. # In the original material, diffuse weight had backscatter weight subtracted. The # backscatter layer probably includes diffuse, so this prevents it from being doubled. # Here, backscatter isn't a separate layer but just a weight on diffuse, so we just apply # the backscatter weight and don't subtract it from diffuse. # # Backscatter has color, roughness and anisotropy, but we don't have separate control over # that. All we can do is set a weight. We don't need to set uses_transparency here. self.set_attr_to_texture_with_color(material.attr('Kb'), self.images.get('Backscattering Weight'), self.channels['Backscattering Weight'], mode='alpha') # The remaining weight not taken up by refraction and scatter is shared by the glossy and diffuse # layer. These two layers are mixed with reflection on top, using fresnel for weighting (Glossy Reflectivity) # multiplied by Glossy Layered Weight. That is, if refraction is 10% and scatter is 15%, we have 75% # remaining. That layer is weighted to glossiness with fresnel multiplied by Glossy Layered Weight. # # Glossy Reflectivity doesn't map 1:1 to Schlick reflectivity. It's not clear what the # translation is. Empirically, the MDL receives 0.28 for 1.0, 0.24 for 0.75, 0.20 for 0.5, # 0.14 for 0.25, and 0 for 0. Just approximate it by scaling. glossy_reflectivity = self.get_texture_with_color(self.images.get('Glossy Reflectivity'), self.channels['Glossy Reflectivity'], mode='alpha') glossy_reflectivity = mh.math_op('mult', glossy_reflectivity, 0.25) mh.set_or_connect(material.attr('Ksn'), glossy_reflectivity) glossy_weight = mh.math_op('mult', glossy_layered_weight, remaining_weight) mh.set_or_connect(material.attr('Ks'), glossy_weight) # remaining_weight is the weight remaining for diffuse. aiStandard will subtract the weight of # the specular (and reflective) layer, since FresnelAffectDiff is true. mh.set_or_connect(material.attr('Kd'), remaining_weight) # The dialectric layer sets its base to diffuse, which seems to effectively mix in the # diffuse color with the glossy color. glossy_color = self.get_texture_with_color(self.images.get('Glossy Color'), self.channels['Glossy Color']) diffuse_color = self.get_texture_with_color(self.images.get('diffuse'), self.channels['diffuse']) glossy_color_combined = mh.math_op('mult', diffuse_color, glossy_color) mh.set_or_connect(material.attr('KsColor'), glossy_color_combined) # The scatter component of diffuse isn't implemented. The SSS model is complex: a translucency weight, reflectance # tint, translucency color, transmission color and lots of weights, deriving an absorbance coefficient and a scattering # coefficient. It's hard to estimate what the results are in order to even emulate the overall basic color. If # your material uses scatter, you'll need to set this up manually. # # If we have a SSS texture, hook that up to make it easier to turn this on manually. self.set_attr_to_texture_with_color(material.attr('KsssColor'), self.images.get('Translucency Color'), self.channels['Translucency Color']) # XXX: Thin film using the reflection layer? return material
def _create_glossy_or_weighted(self, dson_material, sg_node): material = pm.shadingNode('aiStandard', asShader=True) diffuse_weight = 1 opacity = self.channels['Cutout Opacity'] if self.images.get('Cutout Opacity') or self.channels['Cutout Opacity'] != 1: self.set_attr_to_transparency(material.attr('opacity'), self.images.get('Cutout Opacity'), opacity, mode='rgb', zero_is_invisible=True) self.uses_transparency = True # Bump: bump_strength = self.channels.get('Bump Strength', 0) self._set_normal_map(material, normal_texture=self.images.get('Normal Map'), bump_texture=self.images.get('Bump Strength'), bump_scale=bump_strength*0.025) # Glossiness # 0: PBR Metallicity/Roughness # 1: PBR Specular/Glossiness # 2: Weighted base_mixing = self.channels['Base Mixing'] log.debug('%s: %s, %s', sg_node, dson_material, base_mixing) assert base_mixing in (1,2) if base_mixing == 1: # "Specular/Glossiness" # # Glossy Layered Weight has the same effect here as in the above mode, blending from diffuse to glossy. glossy_weight = self.get_texture_with_color(self.images.get('Glossy Layered Weight'), self.channels['Glossy Layered Weight'], mode='alpha') mh.set_or_connect(material.attr('Ks'), glossy_weight) diffuse_weight = mh.math_op('sub', diffuse_weight, glossy_weight) # In this mode, the diffuse color is not mixed into the glossy color: if you have 100% glossy # layered weight and a blue diffuse, the blue isn't visible at all. self.set_attr_to_texture_with_color(material.attr('KsColor'), self.images.get('Glossy Color'), self.channels['Glossy Color']) roughness = self.get_roughness_from_glossiness(self.images.get('Glossiness'), self.channels['Glossiness']) else: # "Weighted" # # This mode replaces Glossy Layered Weight with a Glossy Weight and Diffuse Weight. # # The docs say that it normalizes them, but that's wrong: if you set them both to 0.25 the result # is darker than if you set them both to 1. If they were normalized, 0.25+0.25 would be normalized # to 0.5+0.5. It actually only normalizes if the sum is greater than 1. Note that most of the # time we don't have textures on both of these and all of this math is just done at setup time, # so this doesn't always create a complicated node network. # # This mode doesn't have fresnel reflections. unnormalized_glossy = self.get_texture_with_color(self.images.get('Glossy Weight'), self.channels['Glossy Weight'], mode='alpha') unnormalized_diffuse = self.get_texture_with_color(self.images.get('Diffuse Weight'), self.channels['Diffuse Weight'], mode='alpha') log.debug('... %s, %s', unnormalized_glossy, unnormalized_diffuse) total_weight = mh.math_op('add', unnormalized_glossy, unnormalized_diffuse) normalized_glossy = mh.math_op('div', unnormalized_glossy, total_weight) normalized_diffuse = mh.math_op('div', unnormalized_diffuse, total_weight) # If the total is less than one, use the original weight. Otherwise, use the normalized weight. glossy_weight = mh.math_op('lt', total_weight, 1, unnormalized_glossy, normalized_glossy) assert diffuse_weight == 1 # should not have been changed yet diffuse_weight = mh.math_op('lt', total_weight, 1, unnormalized_diffuse, normalized_diffuse) mh.set_or_connect(material.attr('Ks'), glossy_weight) self.set_attr_to_texture_with_color(material.attr('KsColor'), self.images.get('Glossy Color'), self.channels['Glossy Color']) roughness = self.get_texture_with_color(self.images.get('Glossy Roughness'), self.channels['Glossy Roughness'], mode='alpha') # Grr. Arnold's specular behaves completely differently when it has a value of 0 than 0.001, and always # reflects a ton of light even with low weights. This makes it act like a mirror, and makes texture # mapped roughness behave strangely. Clamp roughness to 0.001 so this doesn't happen. roughness = mh.math_op('clamp', roughness, 0.001, 1) mh.set_or_connect(material.attr('specularRoughness'), roughness) # Convert anisotropy from [0,1] to [0.5,1]. With this material, 0.5 is isotropic and values towards 0 and 1 # are anisotropic in each axis. anisotropy = self.get_texture_with_color(self.images.get('Glossy Anisotropy'), self.channels['Glossy Anisotropy'], mode='r') anisotropy = mh.math_op('mult', anisotropy, 0.5) anisotropy = mh.math_op('add', anisotropy, 0.5) mh.set_or_connect(material.attr('specularAnisotropy'), anisotropy) self.set_attr_to_texture_with_color(material.attr('specularRotation'), self.images.get('Glossy Anisotropy Rotations'), self.channels['Glossy Anisotropy Rotations'], mode='alpha') # Refraction # # Refraction in this material is strange. For example, if we're in weighted mode and the diffuse weight # is 1, refraction still makes the material transparent, but the refraction color isn't applied at all. refraction_weight = self.get_texture_with_color(self.images.get('Refraction Weight'), self.channels['Refraction Weight'], mode='alpha') diffuse_weight = mh.math_op('sub', diffuse_weight, refraction_weight) if isinstance(refraction_weight, pm.PyNode) or refraction_weight > 0: # Only set these if we have any refraction, so we don't create connections to glossiness if we're not using it. mh.set_or_connect(material.attr('Kt'), refraction_weight) self.uses_transparency = True # If the Share Glossy Inputs setting is true, use the reflection settings for roughness/glossiness and color. # Note that we don't connect the roughness value, since the metallicity adjustments we make for # specular roughness shouldn't be made to refraction roughness (a non-metallic surface should have # rough reflections, but not rough refraction). share_glossy_inputs = self.channels['Share Glossy Inputs'] diffuse_channel_name = 'Glossy Color' if share_glossy_inputs else 'Refraction Color' self.set_attr_to_texture_with_color(material.attr('KtColor'), self.images.get(diffuse_channel_name), self.channels[diffuse_channel_name]) # Use the base mixing mode to determine whether it uses Refraction Roughness or Refraction Glossiness. if base_mixing == 1: # "Specular/Glossiness" self.set_attr_to_roughness_from_glossiness( self.images.get('Glossiness' if share_glossy_inputs else 'Refraction Glossiness'), self.channels['Glossiness' if share_glossy_inputs else 'Refraction Glossiness'], material.attr('refractionRoughness')) else: # "Weighted" self.set_attr_to_texture_with_color( material.attr('refractionRoughness'), self.images.get('Glossy Roughness' if share_glossy_inputs else 'Refraction Roughness'), self.channels['Glossy Roughness' if share_glossy_inputs else'Refraction Roughness'], mode='alpha') # XXX material.attr('IOR').set(self.channels['Refraction Index']) material.attr('dispersionAbbe').set(self.channels['Abbe']) # XXX: Backscatter # XXX: Thin film using the reflection layer? # Diffuse self.set_attr_to_texture_with_color(material.attr('color'), self.images.get('diffuse'), self.channels['diffuse']) self.set_attr_to_texture_with_color(material.attr('diffuseRoughness'), self.images.get('Diffuse Roughness'), self.channels['Diffuse Roughness'], mode='alpha') # Diffuse, glossy and transparency are additive. Set the diffuse weight to the remainder after # subtracting the other parts. A completely transparent or reflective object shouldn't have any # diffuse. If refraction + glossy > 1, set diffuse to 0. diffuse_weight = mh.math_op('clamp', diffuse_weight, 0, 1) mh.set_or_connect(material.attr('Kd'), diffuse_weight) return material