独立した表面材質をマスターサーフェスにある程度まとめたい (スクリプト)

独立した表面材質をマスターサーフェスに移行し、同一の表面材質設定のものをまとめます。

これは、Shade3D ver.19までの「Shade3Dマテリアル」に対しての処理になります。
ver.20で搭載された「PBRマテリアル」には未対応です。
表面材質の「基本設定」「効果設定」と「マッピング」のみチェックします。
「ボリューム設定」の移行には対応していません(対応するスクリプトのメソッド/プロパティが存在しないため)。
また、UNDO/REDOには対応していません。

以下のスクリプトを実行すると、シーン内の形状に割り当てられている表面材質をマスターサーフェスに置き換えます。
このとき、同一の材質設定となる場合は、1つのマスターサーフェスにまとめられます。


scene = xshade.scene()

# --------------------------------------------------.
# float型のゼロチェック.
# --------------------------------------------------.
def isZero (v1, v2):
  vv = v1 - v2
  fMin = 0.001
  if vv > -fMin and vv < fMin:
    return True
  return False

# --------------------------------------------------.
# 色(RGB)のゼロチェック.
# --------------------------------------------------.
def isZeroColor (col1, col2):
  fMin = 0.001
  vv1 = col1[0] - col2[0]
  vv2 = col1[1] - col2[1]
  vv3 = col1[2] - col2[2]

  if vv1 > -fMin and vv1 < fMin and vv2 > -fMin and vv2 < fMin and vv3 > -fMin and vv3 < fMin:
    return True
  return False

# --------------------------------------------------.
# matrix(4x4)のゼロチェック.
# --------------------------------------------------.
def isZeroMatrix (matrix1, matrix2):
  retV = True
  for i in range(4):
    for j in range(4):
      if isZero(matrix1[i][j], matrix2[i][j]) == False:
        retV = False
        break
      if retV == False:
        break

  return retV

# --------------------------------------------------.
# 同一の表面材質かチェック.
# --------------------------------------------------.
def isSameSurface (surface1, surface2):
  # その他の設定.
  if surface1.has_aux != surface2.has_aux:
    return False
  if surface1.black_key_mask != surface2.black_key_mask:
    return False
  if isZero(surface1.direct_illumination, surface2.direct_illumination) == False:
    return False
  if isZero(surface1.indirect_illumination, surface2.indirect_illumination) == False:
    return False
  if surface1.dont_reflect_background != surface2.dont_reflect_background:
    return False
  if surface1.dont_visible_to_camera != surface2.dont_visible_to_camera:
    return False
  if surface1.dont_visible_to_indirect_rays != surface2.dont_visible_to_indirect_rays:
    return False
  if surface1.dont_visible_to_reflection_rays != surface2.dont_visible_to_reflection_rays:
    return False
  if surface1.dont_visible_to_refraction_rays != surface2.dont_visible_to_refraction_rays:
    return False
  if surface1.do_not_cast_shadow != surface2.do_not_cast_shadow:
    return False
  if surface1.do_not_reflect_objects != surface2.do_not_reflect_objects:
    return False
  if surface1.do_not_show_shadow != surface2.do_not_show_shadow:
    return False
  if surface1.white_key_mask != surface2.white_key_mask:
    return False
  if surface1.no_shading != surface2.no_shading:
    return False
  if surface1.smoother_shading != surface2.smoother_shading:
    return False
  if surface1.local_coordinates != surface2.local_coordinates:
    return False

  # 基本設定、効果設定.
  if surface1.has_aberration != surface2.has_aberration:
    return False

  if surface1.has_aberration:
    if isZero(surface1.aberration, surface2.aberration) == False:
      return False

  if surface1.has_ambient != surface2.has_ambient:
    return False
  
  if surface1.has_ambient:
    if isZero(surface1.ambient, surface2.ambient) == False:
      return False
    if isZeroColor(surface1.ambient_color, surface2.ambient_color) == False:
      return False

  if surface1.has_anisotropic != surface2.has_anisotropic:
    return False
  
  if surface1.has_anisotropic:
    if isZero(surface1.anisotropic, surface2.anisotropic) == False:
      return False

  if surface1.has_backlight != surface2.has_backlight:
    return False
  
  if surface1.has_backlight:
    if isZero(surface1.backlight, surface2.backlight) == False:
      return False
    if isZeroColor(surface1.backlight_color, surface2.backlight_color) == False:
      return False
  
  if surface1.has_diffuse != surface2.has_diffuse:
    return False
  
  if surface1.has_diffuse:   
    if isZero(surface1.diffuse, surface2.diffuse) == False:
      return False
    if isZeroColor(surface1.diffuse_color, surface2.diffuse_color) == False:
      return False
    
  if surface1.has_fresnel_reflection != surface2.has_fresnel_reflection:
    return False
  
  if surface1.has_fresnel_reflection:   
    if isZero(surface1.fresnel_reflection, surface2.fresnel_reflection) == False:
      return False

  if surface1.has_glow != surface2.has_glow:
    return False

  if surface1.has_glow:
    if isZero(surface1.glow, surface2.glow) == False:
      return False
    if isZeroColor(surface1.glow_color, surface2.glow_color) == False:
      return False
    if isZero(surface1.soft_glow, surface2.soft_glow) == False:
      return False
  
  if surface1.has_metallic != surface2.has_metallic:
    return False
  
  if surface1.has_metallic:
    if isZero(surface1.metallic, surface2.metallic) == False:
      return False
    if isZeroColor(surface1.metallic_color, surface2.metallic_color) == False:
      return False

  if surface1.has_reflection != surface2.has_reflection:
    return False

  if surface1.has_reflection:
    if isZero(surface1.reflection, surface2.reflection) == False:
      return False
    if isZeroColor(surface1.reflection_color, surface2.reflection_color) == False:
      return False

  if surface1.has_refraction != surface2.has_refraction:
    return False

  if surface1.has_refraction:
    if isZero(surface1.refraction, surface2.refraction) == False:
      return False

  if surface1.has_roughness != surface2.has_roughness:
    return False

  if surface1.has_roughness:
    if isZero(surface1.roughness, surface2.roughness) == False:
      return False

  if surface1.has_specular_1 != surface2.has_specular_1:
    return False

  if surface1.has_specular_1:
    if isZero(surface1.highlight, surface2.highlight) == False:
      return False
    if isZeroColor(surface1.highlight_color, surface2.highlight_color) == False:
      return False
    if isZero(surface1.highlight_size, surface2.highlight_size) == False:
      return False

  if surface1.has_specular_2 != surface2.has_specular_2:
    return False

  if surface1.has_specular_2:
    if isZero(surface1.highlight_2, surface2.highlight_2) == False:
      return False
    if isZeroColor(surface1.highlight_color_2, surface2.highlight_color_2) == False:
      return False
    if isZero(surface1.highlight_size_2, surface2.highlight_size_2) == False:
      return False

  if surface1.has_transparency != surface2.has_transparency:
    return False

  if surface1.has_transparency:
    if isZero(surface1.transparency, surface2.transparency) == False:
      return False
    if isZeroColor(surface1.transparency_color, surface2.transparency_color) == False:
      return False

  if surface1.has_pseudo_caustics != surface2.has_pseudo_caustics:
    return False

  if surface1.has_pseudo_caustics:
    if isZero(surface1.pseudo_caustics, surface2.pseudo_caustics) == False:
      return False
    if isZero(surface1.pseudo_caustics_aberration, surface2.pseudo_caustics_aberration) == False:
      return False
    if isZero(surface1.pseudo_caustics_brightness, surface2.pseudo_caustics_brightness) == False:
      return False
    if isZero(surface1.pseudo_caustics_bump, surface2.pseudo_caustics_bump) == False:
      return False

  # マッピング設定.
  if surface1.number_of_mapping_layers != surface2.number_of_mapping_layers:
    return False

  mapingLayerCou = surface1.number_of_mapping_layers
  if mapingLayerCou == 0:
    return True

  if surface1.has_mapping_layers == False and surface2.has_mapping_layers == False:
    return True

  # mapping layer.
  for i in range(mapingLayerCou):
    mLayer1 = surface1.mapping_layer(i)
    mLayer2 = surface2.mapping_layer(i)

    if mLayer1.pattern == 0 and mLayer2.pattern == 0:
      continue

    # イメージのマッピングの場合.
    if mLayer1.pattern == 14 and mLayer2.pattern == 14:
      if mLayer1.image == None and mLayer2.image == None:
        continue
      if mLayer1.image != None and mLayer2.image != None:
        if mLayer1.image.has_image == False or mLayer2.image.has_image == False:
          continue

    if isZero(mLayer1.actual_size[0], mLayer2.actual_size[0]) == False:
      return False
    if isZero(mLayer1.actual_size[1], mLayer2.actual_size[1]) == False:
      return False
    if mLayer1.actual_size_mode != mLayer2.actual_size_mode:
      return False

    if isZero(mLayer1.area[0], mLayer2.area[0]) == False:
      return False
    if isZero(mLayer1.area[1], mLayer2.area[1]) == False:
      return False
    if isZero(mLayer1.area[2], mLayer2.area[2]) == False:
      return False
    if isZero(mLayer1.area[3], mLayer2.area[3]) == False:
      return False

    if mLayer1.blend_mode != mLayer2.blend_mode:
      return False
    if mLayer1.blur != mLayer2.blur:
      return False
    if isZero(mLayer1.bump_height, mLayer2.bump_height) == False:
      return False
    if mLayer1.channel_mix != mLayer2.channel_mix:
      return False
    if mLayer1.flip_color != mLayer2.flip_color:
      return False
    if mLayer1.horizontal_flip != mLayer2.horizontal_flip:
      return False
    if isZeroColor(mLayer1.mapping_color, mLayer2.mapping_color) == False:
      return False
    if isZero(mLayer1.mapping_size, mLayer2.mapping_size) == False:
      return False

    if mLayer1.image != None and mLayer2.image != None:
      if mLayer1.image.has_image != mLayer2.image.has_image:
        return False

      # イメージが同一であるかチェック.
      if mLayer1.image.has_image == True and mLayer2.image.has_image == True:
        if mLayer1.image.equal(mLayer2.image) == False:
          return False

    if isZeroColor(mLayer1.origin, mLayer2.origin) == False:
      return False
    if mLayer1.parameter_mapping != mLayer2.parameter_mapping:
      return False
    if mLayer1.pattern != mLayer2.pattern:
      return False
    if mLayer1.pattern_name != mLayer2.pattern_name:
      return False
    if isZero(mLayer1.phase, mLayer2.phase) == False:
      return False
    if mLayer1.projection != mLayer2.projection:
      return False
    if mLayer1.repeat_image != mLayer2.repeat_image:
      return False
    if mLayer1.repetition_x != mLayer2.repetition_x:
      return False
    if mLayer1.repetition_y != mLayer2.repetition_y:
      return False
    if isZero(mLayer1.softness, mLayer2.softness) == False:
      return False
    if mLayer1.swap_axes != mLayer2.swap_axes:
      return False
    if isZero(mLayer1.turbulence, mLayer2.turbulence) == False:
      return False
    if mLayer1.type != mLayer2.type:
      return False
    if mLayer1.uv_mapping != mLayer2.uv_mapping:
      return False
    if mLayer1.vertical_flip != mLayer2.vertical_flip:
      return False
    if mLayer1.vertex_color_layer != mLayer2.vertex_color_layer:
      return False
    if isZero(mLayer1.weight, mLayer2.weight) == False:
      return False
    if isZeroMatrix(mLayer1.transformation, mLayer2.transformation) == False:
      return False

  return True

# -------------------------------------------------------.
# 指定の形状の独立した表面材質をマスターサーフェスにする.
# -------------------------------------------------------.
def convSurfaceToMasterSurface (shape, index):
  if shape.surface == None or shape.master_surface != None:
    return

  # マスターサーフェスを新しく作成.
  masterSurface = scene.create_master_surface("material_" + str(index))

  # masterSurfaceに、shape.surfaceの情報を複製.

  # その他の複製.
  masterSurface.surface.has_aux = shape.surface.has_aux
  masterSurface.surface.black_key_mask = shape.surface.black_key_mask
  masterSurface.surface.direct_illumination = shape.surface.direct_illumination
  masterSurface.surface.indirect_illumination = shape.surface.indirect_illumination
  masterSurface.surface.dont_reflect_background = shape.surface.dont_reflect_background
  masterSurface.surface.dont_visible_to_camera = shape.surface.dont_visible_to_camera
  masterSurface.surface.dont_visible_to_indirect_rays = shape.surface.dont_visible_to_indirect_rays
  masterSurface.surface.dont_visible_to_reflection_rays = shape.surface.dont_visible_to_reflection_rays
  masterSurface.surface.dont_visible_to_refraction_rays = shape.surface.dont_visible_to_refraction_rays
  masterSurface.surface.do_not_cast_shadow = shape.surface.do_not_cast_shadow
  masterSurface.surface.do_not_reflect_objects = shape.surface.do_not_reflect_objects
  masterSurface.surface.do_not_show_shadow = shape.surface.do_not_show_shadow
  masterSurface.surface.white_key_mask = shape.surface.white_key_mask
  masterSurface.surface.local_coordinates = shape.surface.local_coordinates
  masterSurface.surface.no_shading = shape.surface.no_shading
  masterSurface.surface.smoother_shading = shape.surface.smoother_shading

  # 基本設定/効果設定の複製.
  masterSurface.surface.has_aberration = shape.surface.has_aberration
  if masterSurface.surface.has_aberration:
    masterSurface.surface.aberration = shape.surface.aberration

  masterSurface.surface.has_ambient = shape.surface.has_ambient
  if masterSurface.surface.has_ambient:
    masterSurface.surface.ambient = shape.surface.ambient
    masterSurface.surface.ambient_color = shape.surface.ambient_color

  masterSurface.surface.has_anisotropic = shape.surface.has_anisotropic
  if masterSurface.surface.has_anisotropic:
    masterSurface.surface.anisotropic = shape.surface.anisotropic

  masterSurface.surface.has_backlight = shape.surface.has_backlight
  if masterSurface.surface.has_backlight:
    masterSurface.surface.backlight = shape.surface.backlight
    masterSurface.surface.backlight_color = shape.surface.backlight_color

  masterSurface.surface.has_diffuse = shape.surface.has_diffuse
  if masterSurface.surface.has_diffuse:
    masterSurface.surface.diffuse = shape.surface.diffuse
    masterSurface.surface.diffuse_color = shape.surface.diffuse_color

  masterSurface.surface.has_fresnel_reflection = shape.surface.has_fresnel_reflection
  if masterSurface.surface.has_fresnel_reflection:
    masterSurface.surface.fresnel_reflection = shape.surface.fresnel_reflection

  masterSurface.surface.has_glow = shape.surface.has_glow
  if masterSurface.surface.has_glow:
    masterSurface.surface.glow = shape.surface.glow
    masterSurface.surface.glow_color = shape.surface.glow_color
    masterSurface.surface.soft_glow = shape.surface.soft_glow

  masterSurface.surface.has_metallic = shape.surface.has_metallic
  if masterSurface.surface.has_metallic:
    masterSurface.surface.metallic = shape.surface.metallic
    masterSurface.surface.metallic_color = shape.surface.metallic_color

  masterSurface.surface.has_pseudo_caustics = shape.surface.has_pseudo_caustics
  if masterSurface.surface.has_pseudo_caustics:
    masterSurface.surface.pseudo_caustics = shape.surface.pseudo_caustics
    masterSurface.surface.pseudo_caustics_aberration = shape.surface.pseudo_caustics_aberration
    masterSurface.surface.pseudo_caustics_brightness = shape.surface.pseudo_caustics_brightness
    masterSurface.surface.pseudo_caustics_bump = shape.surface.pseudo_caustics_bump
  
  masterSurface.surface.has_reflection = shape.surface.has_reflection
  if masterSurface.surface.has_reflection:
    masterSurface.surface.reflection = shape.surface.reflection
    masterSurface.surface.reflection_color = shape.surface.reflection_color
  
  masterSurface.surface.has_refraction = shape.surface.has_refraction
  if masterSurface.surface.has_refraction:
    masterSurface.surface.refraction = shape.surface.refraction

  masterSurface.surface.has_roughness = shape.surface.has_roughness
  if masterSurface.surface.has_roughness:
    masterSurface.surface.roughness = shape.surface.roughness
  
  masterSurface.surface.has_specular_1 = shape.surface.has_specular_1
  if masterSurface.surface.has_specular_1:
    masterSurface.surface.highlight = shape.surface.highlight
    masterSurface.surface.highlight_color = shape.surface.highlight_color
    masterSurface.surface.highlight_size = shape.surface.highlight_size
  
  masterSurface.surface.has_specular_2 = shape.surface.has_specular_2
  if masterSurface.surface.has_specular_2:
    masterSurface.surface.highlight_2 = shape.surface.highlight_2
    masterSurface.surface.highlight_color_2 = shape.surface.highlight_color_2
    masterSurface.surface.highlight_size_2 = shape.surface.highlight_size_2
  
  masterSurface.surface.has_transparency = shape.surface.has_transparency
  if masterSurface.surface.has_transparency:
    masterSurface.surface.transparency = shape.surface.transparency
    masterSurface.surface.transparency_color = shape.surface.transparency_color

  # マッピングの複製.
  masterSurface.surface.has_mapping_layers = shape.surface.has_mapping_layers

  mappingLayerCou = shape.surface.number_of_mapping_layers
  if mappingLayerCou == 0 or masterSurface.surface.has_mapping_layers == False:
    shape.master_surface = masterSurface
    return

  # マッピングレイヤ情報を複製.
  for i in range(mappingLayerCou):
    srcMappingLayer = shape.surface.mapping_layer(i)

    # マッピングレイヤを追加.
    masterSurface.surface.append_mapping_layer()
    dstMappingLayer = masterSurface.surface.mapping_layer(i)

    # マッピングレイヤのパラメータをコピー.
    dstMappingLayer.actual_size = srcMappingLayer.actual_size
    dstMappingLayer.actual_size_mode = srcMappingLayer.actual_size_mode
    dstMappingLayer.area = srcMappingLayer.area
    dstMappingLayer.blend_mode = srcMappingLayer.blend_mode
    dstMappingLayer.blur = srcMappingLayer.blur
    dstMappingLayer.bump_height = srcMappingLayer.bump_height
    dstMappingLayer.channel_mix = srcMappingLayer.channel_mix
    dstMappingLayer.flip_color = srcMappingLayer.flip_color
    dstMappingLayer.horizontal_flip = srcMappingLayer.horizontal_flip
    dstMappingLayer.mapping_color = srcMappingLayer.mapping_color
    dstMappingLayer.mapping_size = srcMappingLayer.mapping_size

    dstMappingLayer.origin = srcMappingLayer.origin
    dstMappingLayer.parameter_mapping = srcMappingLayer.parameter_mapping
    dstMappingLayer.pattern = srcMappingLayer.pattern
    dstMappingLayer.phase = srcMappingLayer.phase
    dstMappingLayer.projection = srcMappingLayer.projection
    dstMappingLayer.repeat_image = srcMappingLayer.repeat_image
    dstMappingLayer.repetition_x = srcMappingLayer.repetition_x
    dstMappingLayer.repetition_y = srcMappingLayer.repetition_y
    dstMappingLayer.softness = srcMappingLayer.softness
    dstMappingLayer.swap_axes = srcMappingLayer.swap_axes
    dstMappingLayer.turbulence = srcMappingLayer.turbulence
    dstMappingLayer.type = srcMappingLayer.type
    dstMappingLayer.uv_mapping = srcMappingLayer.uv_mapping
    dstMappingLayer.vertical_flip = srcMappingLayer.vertical_flip
    dstMappingLayer.weight = srcMappingLayer.weight
    dstMappingLayer.vertex_color_layer = srcMappingLayer.vertex_color_layer
    dstMappingLayer.transformation = srcMappingLayer.transformation

    # イメージを指定.
    # これはマッピングパターンを指定後に呼ばないと無効になるため、最後に呼ぶ.
    if srcMappingLayer.image != None and srcMappingLayer.image.has_image:
      dstMappingLayer.image = srcMappingLayer.image

  shape.master_surface = masterSurface

# シーンをたどり、独立した表面材質を持つ形状を探す.
# 階層をたどり、独立した材質を持つ形状を検索
# @param[in]  shape         対象形状.
# @param[out] searchShapes  独立した材質を持つ形状を格納.
def searchMaterials (shape, searchShapes):
  if shape.type == 2 and shape.part_type == 11:  # カメラ.
    return
  if shape.type == 3:  # 光源.
    return
  if shape.type == 10:  # マスターイメージ.
    return
  if shape.type == 8:  # マスターサーフェス.
    return

  # マスターサーフェスを持たない場合.
  if shape.master_surface == None:
    # 表面材質を持つ場合.
    if shape.has_surface_attributes:
      searchShapes.append(shape)

  if shape.has_son:
    s = shape.son
    while s.has_bro:
      s = s.bro
      searchMaterials(s, searchShapes)

# マスターサーフェスを列挙.
# @param[in]  shape           対象形状.
# @param[out] masterSurfaces  マスターサーフェスを格納.
def getMasterSurfaces (shape, masterSurfaces):
  if shape.type == 8:  # マスターサーフェス.
    if shape.master_surface != None:
      masterSurfaces.append(shape.master_surface)

  if shape.has_son:
    s = shape.son
    while s.has_bro:
      s = s.bro
      getMasterSurfaces(s, masterSurfaces)
  
rootShape = scene.shape  # ルート形状.

# マスターサーフェスを列挙.
masterSurfacesA = []
getMasterSurfaces(rootShape, masterSurfacesA)

# 独立した表面材質を持つ形状を列挙.
searchShapesA = []
searchMaterials(rootShape, searchShapesA)

# 形状作成開始.
scene.begin_creating()

# マスターサーフェスと、各形状に割り当てられた独立した表面材質が一致するか.
convCou = 0
newCou = 0
for msLoop in range(len(masterSurfacesA)):
  masterSurface = masterSurfacesA[msLoop]

  for i in range(len(searchShapesA)):
    if searchShapesA[i] == None:
      continue

    # 表面材質が同じかチェック.
    if isSameSurface(searchShapesA[i].surface, masterSurface.surface):
      convCou += 1

      # searchShapesA[i]の表面材質を、masterSurfaceに置き換え.
      searchShapesA[i].master_surface = masterSurface
      searchShapesA[i] = None

# 独立した表面材質をマスターサーフェス化.
# また、同一のものはまとめる.
for i in range(len(searchShapesA)):
  if searchShapesA[i] == None:
    continue

  # searchShapesA[i]をマスターサーフェスにする.
  convSurfaceToMasterSurface(searchShapesA[i], newCou)

  masterSurface = searchShapesA[i].master_surface
  if masterSurface == None:
    continue

  newCou += 1

  for j in range(i + 1, len(searchShapesA)):
    if searchShapesA[j] == None:
      continue

    # 表面材質が同じかチェック.
    if isSameSurface(searchShapesA[j].surface, masterSurface.surface):
      convCou += 1

      # searchShapesA[j]の表面材質を、masterSurfaceに置き換え.
      searchShapesA[j].master_surface = masterSurface
      searchShapesA[j] = None

print "新しく追加したマスターサーフェス数 : " + str(newCou)
print "マスターサーフェスに置き換えた独立した材質数 : " + str(convCou)

# 形状作成終了.
scene.end_creating()

Shade3D ver.19の段階では、材質が同一かどうかの比較メソッドや
独立した材質をマスターサーフェス化し材質設定をそのまま複製するメソッドが存在しないため、
表面材質のパラメータを1つ1つチェックしています。

Translate »