# -*- coding: utf-8 -*- # Copyright (C) 2023 Ilia Kurochkin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. ''' DESCRIPTION. Basic mesh processing for asset pipeline. ''' __version__ = '0.1' import logging import bpy logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) def shell_remesher(lowpoly_obj, mod_name='shell_mod', tree_name='shell_tree'): ''' Conctruct geometry nodes modifier. ''' modifier = lowpoly_obj.modifiers.new(mod_name, type='NODES') tree = bpy.data.node_groups.new(name=tree_name, type='GeometryNodeTree') modifier.node_group = tree group_input = tree.nodes.new(type='NodeGroupInput') collection_info = tree.nodes.new(type='GeometryNodeCollectionInfo') collection_info.location = (300, 0) collection_info.transform_space = 'RELATIVE' tree.inputs.new('NodeSocketCollection', 'Collection') tree.links.new(group_input.outputs['Collection'], collection_info.inputs['Collection']) realize_instances = tree.nodes.new(type='GeometryNodeRealizeInstances') realize_instances.location = (600, 0) tree.links.new(collection_info.outputs[0], realize_instances.inputs['Geometry']) mesh_to_volume = tree.nodes.new(type='GeometryNodeMeshToVolume') mesh_to_volume.location = (900, 0) mesh_to_volume.resolution_mode = 'VOXEL_SIZE' mesh_to_volume.inputs['Density'].default_value = 10.0 mesh_to_volume.inputs['Voxel Size'].default_value = 0.005 mesh_to_volume.inputs['Exterior Band Width'].default_value = 0.005 tree.links.new(realize_instances.outputs['Geometry'], mesh_to_volume.inputs['Mesh']) volume_to_mesh = tree.nodes.new(type='GeometryNodeVolumeToMesh') volume_to_mesh.location = (1200, 0) tree.links.new(mesh_to_volume.outputs['Volume'], volume_to_mesh.inputs['Volume']) extrude_mesh = tree.nodes.new(type='GeometryNodeExtrudeMesh') extrude_mesh.location = (1500, 0) extrude_mesh.inputs['Offset Scale'].default_value = 0.001 extrude_mesh.inputs['Individual'].default_value = False tree.links.new(volume_to_mesh.outputs['Mesh'], extrude_mesh.inputs['Mesh']) # 1 pass mesh_to_volume = tree.nodes.new(type='GeometryNodeMeshToVolume') mesh_to_volume.location = (1800, 0) mesh_to_volume.resolution_mode = 'VOXEL_SIZE' mesh_to_volume.inputs['Density'].default_value = 1.0 mesh_to_volume.inputs['Voxel Size'].default_value = 0.003 mesh_to_volume.inputs['Exterior Band Width'].default_value = 0.003 tree.links.new(extrude_mesh.outputs['Mesh'], mesh_to_volume.inputs['Mesh']) volume_to_mesh = tree.nodes.new(type='GeometryNodeVolumeToMesh') volume_to_mesh.location = (2100, 0) tree.links.new(mesh_to_volume.outputs['Volume'], volume_to_mesh.inputs['Volume']) set_position_01 = tree.nodes.new(type='GeometryNodeSetPosition') set_position_01.location = (2400, -300) tree.links.new(volume_to_mesh.outputs['Mesh'], set_position_01.inputs['Geometry']) # 2 pass mesh_to_volume = tree.nodes.new(type='GeometryNodeMeshToVolume') mesh_to_volume.location = (2700, 0) mesh_to_volume.resolution_mode = 'VOXEL_SIZE' mesh_to_volume.inputs['Density'].default_value = 1.0 mesh_to_volume.inputs['Voxel Size'].default_value = 0.001 mesh_to_volume.inputs['Exterior Band Width'].default_value = 0.001 tree.links.new(set_position_01.outputs['Geometry'], mesh_to_volume.inputs['Mesh']) volume_to_mesh = tree.nodes.new(type='GeometryNodeVolumeToMesh') volume_to_mesh.location = (3000, 0) tree.links.new(mesh_to_volume.outputs['Volume'], volume_to_mesh.inputs['Volume']) set_position_02 = tree.nodes.new(type='GeometryNodeSetPosition') set_position_02.location = (3300, -300) tree.links.new(volume_to_mesh.outputs['Mesh'], set_position_02.inputs['Geometry']) # 3 pass mesh_to_volume = tree.nodes.new(type='GeometryNodeMeshToVolume') mesh_to_volume.location = (3600, 0) mesh_to_volume.resolution_mode = 'VOXEL_SIZE' mesh_to_volume.inputs['Density'].default_value = 1.0 mesh_to_volume.inputs['Voxel Size'].default_value = 0.0005 mesh_to_volume.inputs['Exterior Band Width'].default_value = 0.0001 tree.links.new(set_position_02.outputs['Geometry'], mesh_to_volume.inputs['Mesh']) volume_to_mesh = tree.nodes.new(type='GeometryNodeVolumeToMesh') volume_to_mesh.location = (3900, 0) tree.links.new(mesh_to_volume.outputs['Volume'], volume_to_mesh.inputs['Volume']) set_position_03 = tree.nodes.new(type='GeometryNodeSetPosition') set_position_03.location = (4200, -300) tree.links.new(volume_to_mesh.outputs['Mesh'], set_position_03.inputs['Geometry']) group_output = tree.nodes.new(type='NodeGroupOutput') group_output.location = (4500, 0) tree.outputs.new('NodeSocketGeometry', 'Geometry') tree.links.new(set_position_03.outputs['Geometry'], group_output.inputs['Geometry']) geometry_proximity = tree.nodes.new(type='GeometryNodeProximity') geometry_proximity.location = (1200, -1000) tree.links.new(realize_instances.outputs['Geometry'], geometry_proximity.inputs['Target']) tree.links.new(geometry_proximity.outputs['Position'], set_position_01.inputs['Position']) tree.links.new(geometry_proximity.outputs['Position'], set_position_02.inputs['Position']) tree.links.new(geometry_proximity.outputs['Position'], set_position_03.inputs['Position']) return modifier