Source code for blenderproc.python.modules.constructor.RockEssentialsGroundConstructor

import os

import bpy

from blenderproc.python.modules.loader.LoaderInterface import LoaderInterface
from blenderproc.python.modules.utility.Config import Config
from blenderproc.python.types.MaterialUtility import Material
from blenderproc.python.types.MeshObjectUtility import MeshObject, create_primitive


[docs]class RockEssentialsGroundConstructor(LoaderInterface): """ Constructs a ground plane with a material using RE PBR Rock Shader. Example 1: Construct a scaled ground plane with 30 subdivision cuts, custom name and subdiv level value for rendering using PBR Rock Shader from the specified .blend file. .. code-block:: yaml { "module": "constructor.RockEssentialsGroundConstructor", "config": { "tiles": [ { "shader_path": "<args:0>/Rock Essentials/Individual Rocks/Volcanic/Rocks_Volcanic_Small.blend", "plane_scale": [50, 50, 1], "subdivision_cuts": 30, "subdivision_render_levels": 2, "tile_name": "Gr_Plane_1" } ] } } **Configuration**: .. list-table:: :widths: 25 100 10 :header-rows: 1 * - Parameter - Description - Type * - tiles - Ground tiles to create, each cell contains a separate tile configuration. - list **Ground plane properties**: .. list-table:: :widths: 25 100 10 :header-rows: 1 * - Parameter - Description - Type * - shader_path - Path to a .blend file that containing PBR Rock Shader in //NodeTree// section. - string * - plane_scale - Scale of a ground plane. Default: [10, 10, 1]. - mathutils.Vector/list * - subdivision_cuts - Amount of cuts along each plane axis. Default: 50. - int * - subdivision_render_levels - Render level for a plane's subdivision modifier. Default: 3. - int * - tile_name - Name of the ground tile. Set one if you plan to use this module multiple times in one config. Default: 'RE_ground_plane'. - string """ def __init__(self, config): LoaderInterface.__init__(self, config)
[docs] def run(self): """ Constructs a ground plane. 1. Get configuration parameters. 2. Load shader. 3. Construct ground plane and it's material node tree. """ tiles = self.config.get_list("tiles") for tile in tiles: if tile: ground_config = Config(tile) self._load_shader(ground_config) self._construct_ground_plane(ground_config)
[docs] def _load_shader(self, ground_config): """ Loads PBR Rock Shader :param ground_config: Config object that contains user-defined settings for ground plane. Type: Config. """ shader_path = ground_config.get_string("shader_path") bpy.ops.wm.append(filepath=os.path.join(shader_path, "/NodeTree", "", "PBR Rock Shader"), filename="PBR Rock Shader", directory=os.path.join(shader_path+"/NodeTree"))
[docs] def _construct_ground_plane(self, ground_config): """ Constructs a ground plane. :param ground_config: Config object that contains user-defined settings for ground plane. Type: Config. """ # get scale\'size' of a plane to be created 10x10 if not defined plane_scale = ground_config.get_vector3d("plane_scale", [1, 1, 1]) # get the amount of subdiv cuts, 50 (50x50=250 segments) if not defined subdivision_cuts = ground_config.get_int("subdivision_cuts", 50) # get the amount of subdiv render levels, 2 if not defined subdivision_render_levels = ground_config.get_int("subdivision_render_levels", 3) # get name, 'RE_ground_plane' if not defined tile_name = ground_config.get_string("tile_name", "RE_ground_plane") # create new plane, set its size plane_obj = create_primitive("PLANE") plane_obj.set_name(tile_name) plane_obj.set_scale(plane_scale) # create new material mat_obj = plane_obj.new_material("re_ground_mat") # delete Principled BSDF node mat_obj.remove_node(mat_obj.get_the_one_node_with_type("BsdfPrincipled")) # create PBR Rock Shader, connect its output 'Shader' to the Material Output nodes input 'Surface' group_pbr = mat_obj.new_node("ShaderNodeGroup") group_pbr.node_tree = bpy.data.node_groups['PBR Rock Shader'] output_node = mat_obj.get_the_one_node_with_type('OutputMaterial') mat_obj.link(group_pbr.outputs['Shader'], output_node.inputs['Surface']) # create Image Texture nodes for color, roughness, reflection, and normal maps self._create_node(mat_obj, 'color', 'Color') self._create_node(mat_obj, 'roughness', 'Roughness') self._create_node(mat_obj, 'reflection', 'Reflection') self._create_node(mat_obj, 'normal', 'Normal') # create subsurface and displacement modifiers bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.subdivide(number_cuts=subdivision_cuts) bpy.ops.object.modifier_add(type="DISPLACE") bpy.ops.object.modifier_add(type="SUBSURF") # create new texture texture_name = tile_name + "_texture" bpy.data.textures.new(name=texture_name, type="IMAGE") # set new texture as a displacement texture, set UV texture coordinates plane_obj.blender_obj.modifiers['Displace'].texture = bpy.data.textures[texture_name] plane_obj.blender_obj.modifiers['Displace'].texture_coords = 'UV' bpy.ops.object.editmode_toggle() # scale, set render levels for subdivision, strength of displacement and set passive rigidbody state bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) bpy.context.object.modifiers["Subdivision"].render_levels = subdivision_render_levels plane_obj.set_cp("physics", False) self._set_properties([plane_obj])
[docs] def _create_node(self, mat_obj: Material, map_type: str, in_point: str): """ Handles the creation a ShaderNodeTexImage node, setting maps and creating links. :param mat_obj: The material object. :param map_type: Type of image/map that will be assigned to this node. :param in_point: Name of an input point in PBR Rock Shader node to use. """ new_node = mat_obj.new_node('ShaderNodeTexImage') # set output point of the node to connect output_socket = new_node.outputs['Color'] new_node.label = map_type # special case for a normal map since the link between TextureNode and PBR RS is broken with Normal Map node if map_type == 'normal': # create new node group_norm_map = mat_obj.new_node('ShaderNodeNormalMap') # connect color output/input mat_obj.link(new_node.outputs['Color'], group_norm_map.inputs['Color']) # redefine main output point to connect output_socket = group_norm_map.outputs['Normal'] # select main input point of the PBR Rock Shader group_input_socket = mat_obj.nodes.get("Group").inputs[in_point] mat_obj.link(output_socket, group_input_socket)