Spaces:
Runtime error
Runtime error
| # Copyright (C) 2023, Princeton University. | |
| # This source code is licensed under the BSD 3-Clause license found in the LICENSE file in the root directory of this source tree. | |
| # Authors: Beining Han | |
| # Acknowledgement: This file draws inspiration from https://www.youtube.com/watch?v=61Sk8j1Ml9c by BradleyAnimation | |
| import bpy | |
| import numpy as np | |
| from numpy.random import normal, randint, uniform | |
| import infinigen | |
| from infinigen.assets.materials import simple_brownish, simple_greenery, simple_whitish | |
| from infinigen.core import surface | |
| from infinigen.core.nodes import node_utils | |
| from infinigen.core.nodes.node_wrangler import Nodes, NodeWrangler | |
| from infinigen.core.placement.factory import AssetFactory | |
| from infinigen.core.tagging import tag_nodegroup, tag_object | |
| from infinigen.core.util.math import FixedSeed | |
| def nodegroup_pedal_stem_head_geometry(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketVectorTranslation", "Translation", (0.0, 0.0, 1.0)), | |
| ("NodeSocketFloatDistance", "Radius", 0.04), | |
| ], | |
| ) | |
| uv_sphere_1 = nw.new_node( | |
| Nodes.MeshUVSphere, | |
| input_kwargs={"Segments": 64, "Radius": group_input.outputs["Radius"]}, | |
| ) | |
| transform_1 = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": uv_sphere_1, | |
| "Translation": group_input.outputs["Translation"], | |
| }, | |
| ) | |
| set_material = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": transform_1, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_brownish.shader_simple_brown | |
| ), | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": set_material} | |
| ) | |
| def nodegroup_pedal_stem_end_geometry(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, expose_input=[("NodeSocketGeometry", "Points", None)] | |
| ) | |
| endpoint_selection = nw.new_node( | |
| "GeometryNodeCurveEndpointSelection", input_kwargs={"End Size": 0} | |
| ) | |
| uv_sphere = nw.new_node( | |
| Nodes.MeshUVSphere, input_kwargs={"Segments": 64, "Radius": 0.04} | |
| ) | |
| vector = nw.new_node(Nodes.Vector) | |
| vector.vector = (uniform(0.45, 0.7), uniform(0.45, 0.7), uniform(2, 3)) | |
| transform = nw.new_node( | |
| Nodes.Transform, input_kwargs={"Geometry": uv_sphere, "Scale": vector} | |
| ) | |
| cone = nw.new_node( | |
| "GeometryNodeMeshCone", input_kwargs={"Radius Bottom": 0.0040, "Depth": 0.0040} | |
| ) | |
| normal = nw.new_node(Nodes.InputNormal) | |
| align_euler_to_vector_1 = nw.new_node( | |
| Nodes.AlignEulerToVector, input_kwargs={"Vector": normal}, attrs={"axis": "Z"} | |
| ) | |
| instance_on_points_1 = nw.new_node( | |
| Nodes.InstanceOnPoints, | |
| input_kwargs={ | |
| "Points": transform, | |
| "Instance": cone.outputs["Mesh"], | |
| "Rotation": align_euler_to_vector_1, | |
| }, | |
| ) | |
| join_geometry = nw.new_node( | |
| Nodes.JoinGeometry, input_kwargs={"Geometry": [instance_on_points_1, transform]} | |
| ) | |
| set_material = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": join_geometry, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_brownish.shader_simple_brown | |
| ), | |
| }, | |
| ) | |
| geometry_to_instance = nw.new_node( | |
| "GeometryNodeGeometryToInstance", input_kwargs={"Geometry": set_material} | |
| ) | |
| curve_tangent = nw.new_node(Nodes.CurveTangent) | |
| align_euler_to_vector = nw.new_node( | |
| Nodes.AlignEulerToVector, | |
| input_kwargs={"Vector": curve_tangent}, | |
| attrs={"axis": "Z"}, | |
| ) | |
| instance_on_points = nw.new_node( | |
| Nodes.InstanceOnPoints, | |
| input_kwargs={ | |
| "Points": group_input.outputs["Points"], | |
| "Selection": endpoint_selection, | |
| "Instance": geometry_to_instance, | |
| "Rotation": align_euler_to_vector, | |
| }, | |
| ) | |
| realize_instances = nw.new_node( | |
| Nodes.RealizeInstances, input_kwargs={"Geometry": instance_on_points} | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": realize_instances} | |
| ) | |
| def nodegroup_pedal_stem_branch_shape(nw: NodeWrangler): | |
| # Code generated using version 2.6.4 of the node_transpiler | |
| pedal_stem_branches_num = nw.new_node( | |
| Nodes.Integer, label="pedal_stem_branches_num" | |
| ) | |
| pedal_stem_branches_num.integer = 40 | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, expose_input=[("NodeSocketFloatDistance", "Radius", 0.0100)] | |
| ) | |
| curve_circle_1 = nw.new_node( | |
| Nodes.CurveCircle, | |
| input_kwargs={ | |
| "Resolution": pedal_stem_branches_num, | |
| "Radius": group_input.outputs["Radius"], | |
| }, | |
| ) | |
| pedal_stem_branch_length = nw.new_node( | |
| Nodes.Value, label="pedal_stem_branch_length" | |
| ) | |
| pedal_stem_branch_length.outputs[0].default_value = 0.5000 | |
| combine_xyz_1 = nw.new_node( | |
| Nodes.CombineXYZ, input_kwargs={"X": pedal_stem_branch_length} | |
| ) | |
| curve_line_1 = nw.new_node(Nodes.CurveLine, input_kwargs={"End": combine_xyz_1}) | |
| resample_curve = nw.new_node( | |
| Nodes.ResampleCurve, input_kwargs={"Curve": curve_line_1, "Count": 40} | |
| ) | |
| spline_parameter = nw.new_node(Nodes.SplineParameter) | |
| float_curve = nw.new_node( | |
| Nodes.FloatCurve, input_kwargs={"Value": spline_parameter.outputs["Factor"]} | |
| ) | |
| node_utils.assign_curve( | |
| float_curve.mapping.curves[0], | |
| [ | |
| (0.0000, 0.0000), | |
| (0.2, 0.08 * np.random.normal(1.0, 0.15)), | |
| (0.4, 0.22 * np.random.normal(1.0, 0.2)), | |
| (0.6, 0.45 * np.random.normal(1.0, 0.2)), | |
| (0.8, 0.7 * np.random.normal(1.0, 0.1)), | |
| (1.0000, 1.0000), | |
| ], | |
| ) | |
| multiply = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: float_curve, 1: uniform(0.15, 0.4)}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply}) | |
| set_position = nw.new_node( | |
| Nodes.SetPosition, | |
| input_kwargs={"Geometry": resample_curve, "Offset": combine_xyz}, | |
| ) | |
| normal = nw.new_node(Nodes.InputNormal) | |
| align_euler_to_vector = nw.new_node( | |
| Nodes.AlignEulerToVector, input_kwargs={"Vector": normal} | |
| ) | |
| instance_on_points = nw.new_node( | |
| Nodes.InstanceOnPoints, | |
| input_kwargs={ | |
| "Points": curve_circle_1.outputs["Curve"], | |
| "Instance": set_position, | |
| "Rotation": align_euler_to_vector, | |
| }, | |
| ) | |
| random_value_1 = nw.new_node( | |
| Nodes.RandomValue, input_kwargs={2: -0.2000, 3: 0.2000, "Seed": 2} | |
| ) | |
| random_value_2 = nw.new_node( | |
| Nodes.RandomValue, input_kwargs={2: -0.2000, 3: 0.2000, "Seed": 1} | |
| ) | |
| random_value = nw.new_node(Nodes.RandomValue, input_kwargs={2: -0.2000, 3: 0.2000}) | |
| combine_xyz_2 = nw.new_node( | |
| Nodes.CombineXYZ, | |
| input_kwargs={ | |
| "X": random_value_1.outputs[1], | |
| "Y": random_value_2.outputs[1], | |
| "Z": random_value.outputs[1], | |
| }, | |
| ) | |
| rotate_instances = nw.new_node( | |
| Nodes.RotateInstances, | |
| input_kwargs={"Instances": instance_on_points, "Rotation": combine_xyz_2}, | |
| ) | |
| random_value_3 = nw.new_node(Nodes.RandomValue, input_kwargs={2: 0.8000}) | |
| scale_instances = nw.new_node( | |
| Nodes.ScaleInstances, | |
| input_kwargs={ | |
| "Instances": rotate_instances, | |
| "Scale": random_value_3.outputs[1], | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Instances": scale_instances}, | |
| attrs={"is_active_output": True}, | |
| ) | |
| def nodegroup_pedal_stem_branch_contour(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, expose_input=[("NodeSocketGeometry", "Geometry", None)] | |
| ) | |
| realize_instances = nw.new_node( | |
| Nodes.RealizeInstances, | |
| input_kwargs={"Geometry": group_input.outputs["Geometry"]}, | |
| ) | |
| pedal_stem_branch_rsample = nw.new_node( | |
| Nodes.Value, label="pedal_stem_branch_rsample" | |
| ) | |
| pedal_stem_branch_rsample.outputs[0].default_value = 10.0 | |
| resample_curve = nw.new_node( | |
| Nodes.ResampleCurve, | |
| input_kwargs={"Curve": realize_instances, "Count": pedal_stem_branch_rsample}, | |
| ) | |
| index = nw.new_node(Nodes.Index) | |
| capture_attribute = nw.new_node( | |
| Nodes.CaptureAttribute, | |
| input_kwargs={"Geometry": resample_curve, 5: index}, | |
| attrs={"domain": "CURVE", "data_type": "INT"}, | |
| ) | |
| spline_parameter = nw.new_node(Nodes.SplineParameter) | |
| float_curve = nw.new_node( | |
| Nodes.FloatCurve, input_kwargs={"Value": spline_parameter.outputs["Factor"]} | |
| ) | |
| # generate pedal branch contour | |
| dist = uniform(-0.05, -0.25) | |
| node_utils.assign_curve( | |
| float_curve.mapping.curves[0], | |
| [ | |
| (0.0, 0.0), | |
| (0.2, 0.2 + (dist + normal(0, 0.05)) / 2.0), | |
| (0.4, 0.4 + (dist + normal(0, 0.05))), | |
| (0.6, 0.6 + (dist + normal(0, 0.05)) / 1.2), | |
| (0.8, 0.8 + (dist + normal(0, 0.05)) / 2.4), | |
| (1.0, 0.95 + normal(0, 0.05)), | |
| ], | |
| ) | |
| random_value = nw.new_node( | |
| Nodes.RandomValue, | |
| input_kwargs={2: 0.05, 3: 0.35, "ID": capture_attribute.outputs[5]}, | |
| ) | |
| multiply = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: float_curve, 1: random_value.outputs[1]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={"Z": multiply}) | |
| set_position = nw.new_node( | |
| Nodes.SetPosition, | |
| input_kwargs={ | |
| "Geometry": capture_attribute.outputs["Geometry"], | |
| "Offset": combine_xyz, | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": set_position} | |
| ) | |
| def nodegroup_pedal_stem_branch_geometry(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketGeometry", "Curve", None), | |
| ("NodeSocketVectorTranslation", "Translation", (0.0, 0.0, 1.0)), | |
| ], | |
| ) | |
| set_curve_radius_1 = nw.new_node( | |
| Nodes.SetCurveRadius, | |
| input_kwargs={"Curve": group_input.outputs["Curve"], "Radius": 1.0}, | |
| ) | |
| curve_circle_2 = nw.new_node( | |
| Nodes.CurveCircle, | |
| input_kwargs={"Radius": uniform(0.001, 0.0025), "Resolution": 4}, | |
| ) | |
| curve_to_mesh_1 = nw.new_node( | |
| Nodes.CurveToMesh, | |
| input_kwargs={ | |
| "Curve": set_curve_radius_1, | |
| "Profile Curve": curve_circle_2.outputs["Curve"], | |
| "Fill Caps": True, | |
| }, | |
| ) | |
| transform_2 = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={ | |
| "Geometry": curve_to_mesh_1, | |
| "Translation": group_input.outputs["Translation"], | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": transform_2} | |
| ) | |
| def nodegroup_pedal_stem_geometry(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketVectorTranslation", "End", (0.0, 0.0, 1.0)), | |
| ("NodeSocketVectorTranslation", "Middle", (0.0, 0.0, 0.5)), | |
| ("NodeSocketFloatDistance", "Radius", 0.05), | |
| ], | |
| ) | |
| quadratic_bezier = nw.new_node( | |
| Nodes.QuadraticBezier, | |
| input_kwargs={ | |
| "Start": (0.0, 0.0, 0.0), | |
| "Middle": group_input.outputs["Middle"], | |
| "End": group_input.outputs["End"], | |
| }, | |
| ) | |
| set_curve_radius = nw.new_node( | |
| Nodes.SetCurveRadius, | |
| input_kwargs={ | |
| "Curve": quadratic_bezier, | |
| "Radius": group_input.outputs["Radius"], | |
| }, | |
| ) | |
| curve_circle = nw.new_node( | |
| Nodes.CurveCircle, input_kwargs={"Radius": 0.2, "Resolution": 8} | |
| ) | |
| curve_to_mesh = nw.new_node( | |
| Nodes.CurveToMesh, | |
| input_kwargs={ | |
| "Curve": set_curve_radius, | |
| "Profile Curve": curve_circle.outputs["Curve"], | |
| "Fill Caps": True, | |
| }, | |
| ) | |
| set_material_2 = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": curve_to_mesh, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_whitish.shader_simple_white | |
| ), | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Geometry": set_material_2, "Curve": quadratic_bezier}, | |
| ) | |
| def nodegroup_pedal_selection(nw: NodeWrangler, params): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| random_value = nw.new_node(Nodes.RandomValue, input_kwargs={5: 1}) | |
| greater_than = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: params["random_dropout"], 1: random_value.outputs[1]}, | |
| attrs={"operation": "GREATER_THAN"}, | |
| ) | |
| index_1 = nw.new_node(Nodes.Index) | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, expose_input=[("NodeSocketFloat", "num_segments", 0.5)] | |
| ) | |
| divide = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: index_1, 1: group_input.outputs["num_segments"]}, | |
| attrs={"operation": "DIVIDE"}, | |
| ) | |
| less_than = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: divide, 1: params["row_less_than"]}, | |
| attrs={"operation": "LESS_THAN"}, | |
| ) | |
| greater_than_1 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: divide, 1: params["row_great_than"]}, | |
| attrs={"operation": "GREATER_THAN"}, | |
| ) | |
| op_and = nw.new_node( | |
| Nodes.BooleanMath, input_kwargs={0: less_than, 1: greater_than_1} | |
| ) | |
| modulo = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: index_1, 1: group_input.outputs["num_segments"]}, | |
| attrs={"operation": "MODULO"}, | |
| ) | |
| less_than_1 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: modulo, 1: params["col_less_than"]}, | |
| attrs={"operation": "LESS_THAN"}, | |
| ) | |
| greater_than_2 = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: modulo, 1: params["col_great_than"]}, | |
| attrs={"operation": "GREATER_THAN"}, | |
| ) | |
| op_and_1 = nw.new_node( | |
| Nodes.BooleanMath, input_kwargs={0: less_than_1, 1: greater_than_2} | |
| ) | |
| nand = nw.new_node( | |
| Nodes.BooleanMath, | |
| input_kwargs={0: op_and, 1: op_and_1}, | |
| attrs={"operation": "NAND"}, | |
| ) | |
| op_and_2 = nw.new_node(Nodes.BooleanMath, input_kwargs={0: greater_than, 1: nand}) | |
| group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={"Boolean": op_and_2}) | |
| def nodegroup_stem_geometry(nw: NodeWrangler, params): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketGeometry", "Curve", None), | |
| ] | |
| ) | |
| spline_parameter = nw.new_node(Nodes.SplineParameter) | |
| value = nw.new_node(Nodes.Value) | |
| value.outputs[0].default_value = params["stem_map_range"] | |
| map_range = nw.new_node( | |
| Nodes.MapRange, | |
| input_kwargs={"Value": spline_parameter.outputs["Factor"], 3: 0.4, 4: value}, | |
| ) | |
| set_curve_radius_2 = nw.new_node( | |
| Nodes.SetCurveRadius, | |
| input_kwargs={ | |
| "Curve": group_input.outputs["Curve"], | |
| "Radius": map_range.outputs["Result"], | |
| }, | |
| ) | |
| stem_radius = nw.new_node(Nodes.Value, label="stem_radius") | |
| stem_radius.outputs[0].default_value = params["stem_radius"] | |
| curve_circle_3 = nw.new_node( | |
| Nodes.CurveCircle, input_kwargs={"Radius": stem_radius} | |
| ) | |
| curve_to_mesh_2 = nw.new_node( | |
| Nodes.CurveToMesh, | |
| input_kwargs={ | |
| "Curve": set_curve_radius_2, | |
| "Profile Curve": curve_circle_3.outputs["Curve"], | |
| "Fill Caps": True, | |
| }, | |
| ) | |
| set_material = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": curve_to_mesh_2, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_greenery.shader_simple_greenery | |
| ), | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Mesh": tag_nodegroup(nw, set_material, "stem")}, | |
| ) | |
| def nodegroup_pedal_stem(nw: NodeWrangler, params): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| pedal_stem_top_point = nw.new_node(Nodes.Vector, label="pedal_stem_top_point") | |
| pedal_stem_top_point.vector = (0.0, 0.0, 1.0) | |
| pedal_stem_mid_point = nw.new_node(Nodes.Vector, label="pedal_stem_mid_point") | |
| pedal_stem_mid_point.vector = ( | |
| params["pedal_stem_mid_point_x"], | |
| params["pedal_stem_mid_point_y"], | |
| 0.5 | |
| ) | |
| pedal_stem_radius = nw.new_node(Nodes.Value, label="pedal_stem_radius") | |
| pedal_stem_radius.outputs[0].default_value = params["pedal_stem_radius"] | |
| pedal_stem_geometry = nw.new_node( | |
| nodegroup_pedal_stem_geometry().name, | |
| input_kwargs={ | |
| "End": pedal_stem_top_point, | |
| "Middle": pedal_stem_mid_point, | |
| "Radius": pedal_stem_radius, | |
| }, | |
| ) | |
| pedal_stem_top_radius = nw.new_node(Nodes.Value, label="pedal_stem_top_radius") | |
| pedal_stem_top_radius.outputs[0].default_value = params["pedal_stem_top_radius"] | |
| pedal_stem_branch_shape = nw.new_node( | |
| nodegroup_pedal_stem_branch_shape().name, | |
| input_kwargs={"Radius": pedal_stem_top_radius}, | |
| ) | |
| pedal_stem_branch_geometry = nw.new_node( | |
| nodegroup_pedal_stem_branch_geometry().name, | |
| input_kwargs={ | |
| "Curve": pedal_stem_branch_shape, | |
| "Translation": pedal_stem_top_point, | |
| }, | |
| ) | |
| set_material_3 = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": pedal_stem_branch_geometry, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_whitish.shader_simple_white | |
| ), | |
| }, | |
| ) | |
| resample_curve = nw.new_node( | |
| Nodes.ResampleCurve, | |
| input_kwargs={"Curve": pedal_stem_geometry.outputs["Curve"]}, | |
| ) | |
| pedal_stem_end_geometry = nw.new_node( | |
| nodegroup_pedal_stem_end_geometry().name, | |
| input_kwargs={"Points": resample_curve}, | |
| ) | |
| pedal_stem_head_geometry = nw.new_node( | |
| nodegroup_pedal_stem_head_geometry().name, | |
| input_kwargs={ | |
| "Translation": pedal_stem_top_point, | |
| "Radius": pedal_stem_top_radius, | |
| }, | |
| ) | |
| join_geometry = nw.new_node( | |
| Nodes.JoinGeometry, | |
| input_kwargs={ | |
| "Geometry": [ | |
| pedal_stem_geometry.outputs["Geometry"], | |
| set_material_3, | |
| pedal_stem_end_geometry, | |
| pedal_stem_head_geometry, | |
| ] | |
| }, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": join_geometry} | |
| ) | |
| def nodegroup_flower_geometry(nw: NodeWrangler, params): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| num_core_segments = nw.new_node( | |
| Nodes.Integer, label="num_core_segments", attrs={"integer": 10} | |
| ) | |
| num_core_segments.integer = params["flower_num_core_segments"] | |
| num_core_rings = nw.new_node( | |
| Nodes.Integer, label="num_core_rings", attrs={"integer": 10} | |
| ) | |
| num_core_rings.integer = params["flower_num_core_rings"] | |
| uv_sphere_2 = nw.new_node( | |
| Nodes.MeshUVSphere, | |
| input_kwargs={ | |
| "Segments": num_core_segments, | |
| "Rings": num_core_rings, | |
| "Radius": params["flower_radius"], | |
| }, | |
| ) | |
| flower_core_shape = nw.new_node(Nodes.Vector, label="flower_core_shape") | |
| flower_core_shape.vector = (params["flower_core_shape_x"], params["flower_core_shape_y"], params["flower_core_shape_z"]) | |
| transform = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={"Geometry": uv_sphere_2, "Scale": flower_core_shape}, | |
| ) | |
| selection_params = { | |
| "random_dropout": params["random_dropout"], | |
| "row_less_than": int(params["row_less_than"] * num_core_rings.integer), | |
| "row_great_than": int(params["row_great_than"] * num_core_rings.integer), | |
| "col_less_than": int(params["col_less_than"] * num_core_segments.integer), | |
| "col_great_than": int(params["col_less_than"] * num_core_segments.integer), | |
| } | |
| pedal_selection = nw.new_node( | |
| nodegroup_pedal_selection(params=selection_params).name, | |
| input_kwargs={"num_segments": num_core_segments}, | |
| ) | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, expose_input=[("NodeSocketGeometry", "Instance", None)] | |
| ) | |
| normal_1 = nw.new_node(Nodes.InputNormal) | |
| align_euler_to_vector_1 = nw.new_node( | |
| Nodes.AlignEulerToVector, input_kwargs={"Vector": normal_1}, attrs={"axis": "Z"} | |
| ) | |
| random_value_1 = nw.new_node(Nodes.RandomValue, input_kwargs={2: 0.4, 3: 0.7}) | |
| multiply = nw.new_node( | |
| Nodes.Math, | |
| input_kwargs={0: random_value_1.outputs[1]}, | |
| attrs={"operation": "MULTIPLY"}, | |
| ) | |
| instance_on_points_1 = nw.new_node( | |
| Nodes.InstanceOnPoints, | |
| input_kwargs={ | |
| "Points": transform, | |
| "Selection": pedal_selection, | |
| "Instance": group_input.outputs["Instance"], | |
| "Rotation": align_euler_to_vector_1, | |
| "Scale": multiply, | |
| }, | |
| ) | |
| realize_instances_1 = nw.new_node( | |
| Nodes.RealizeInstances, input_kwargs={"Geometry": instance_on_points_1} | |
| ) | |
| set_material = nw.new_node( | |
| Nodes.SetMaterial, | |
| input_kwargs={ | |
| "Geometry": transform, | |
| "Material": surface.shaderfunc_to_material( | |
| simple_whitish.shader_simple_white | |
| ), | |
| }, | |
| ) | |
| join_geometry_1 = nw.new_node( | |
| Nodes.JoinGeometry, | |
| input_kwargs={"Geometry": [realize_instances_1, set_material]}, | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, | |
| input_kwargs={"Geometry": tag_nodegroup(nw, join_geometry_1, "flower")}, | |
| ) | |
| def nodegroup_flower_on_stem(nw: NodeWrangler): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| group_input = nw.new_node( | |
| Nodes.GroupInput, | |
| expose_input=[ | |
| ("NodeSocketGeometry", "Points", None), | |
| ("NodeSocketGeometry", "Instance", None), | |
| ], | |
| ) | |
| endpoint_selection = nw.new_node( | |
| "GeometryNodeCurveEndpointSelection", input_kwargs={"Start Size": 0} | |
| ) | |
| curve_tangent = nw.new_node(Nodes.CurveTangent) | |
| align_euler_to_vector_2 = nw.new_node( | |
| Nodes.AlignEulerToVector, | |
| input_kwargs={"Vector": curve_tangent}, | |
| attrs={"axis": "Z"}, | |
| ) | |
| instance_on_points_2 = nw.new_node( | |
| Nodes.InstanceOnPoints, | |
| input_kwargs={ | |
| "Points": group_input.outputs["Points"], | |
| "Selection": endpoint_selection, | |
| "Instance": group_input.outputs["Instance"], | |
| "Rotation": align_euler_to_vector_2, | |
| }, | |
| ) | |
| realize_instances_2 = nw.new_node( | |
| Nodes.RealizeInstances, input_kwargs={"Geometry": instance_on_points_2} | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Instances": realize_instances_2} | |
| ) | |
| def geometry_dandelion_nodes(nw: NodeWrangler, **kwargs): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| quadratic_bezier_1 = nw.new_node( | |
| Nodes.QuadraticBezier, | |
| input_kwargs={ | |
| "Start": (0.0, 0.0, 0.0), | |
| "Middle": (kwargs["bezier_middle_x"], kwargs["bezier_middle_y"], 0.5), | |
| "End": (kwargs["bezier_end_x"], kwargs["bezier_end_y"], 1.0), | |
| }, | |
| ) | |
| resample_curve = nw.new_node( | |
| Nodes.ResampleCurve, input_kwargs={"Curve": quadratic_bezier_1} | |
| ) | |
| pedal_stem = nw.new_node( | |
| nodegroup_pedal_stem(kwargs).name, | |
| input_kwargs={}, | |
| ) | |
| geometry_to_instance = nw.new_node( | |
| "GeometryNodeGeometryToInstance", input_kwargs={"Geometry": pedal_stem} | |
| ) | |
| flower_geometry = nw.new_node( | |
| nodegroup_flower_geometry(kwargs).name, | |
| input_kwargs={"Instance": geometry_to_instance}, | |
| ) | |
| geometry_to_instance_1 = nw.new_node( | |
| "GeometryNodeGeometryToInstance", input_kwargs={"Geometry": flower_geometry} | |
| ) | |
| value_2 = nw.new_node(Nodes.Value) | |
| value_2.outputs[0].default_value = kwargs["transform_scale"] | |
| transform_3 = nw.new_node( | |
| Nodes.Transform, | |
| input_kwargs={"Geometry": geometry_to_instance_1, "Scale": value_2}, | |
| ) | |
| flower_on_stem = nw.new_node( | |
| nodegroup_flower_on_stem().name, | |
| input_kwargs={"Points": resample_curve, "Instance": transform_3}, | |
| ) | |
| stem_geometry = nw.new_node( | |
| nodegroup_stem_geometry(kwargs).name, | |
| input_kwargs={ | |
| "Curve": quadratic_bezier_1, | |
| } | |
| ) | |
| join_geometry_2 = nw.new_node( | |
| Nodes.JoinGeometry, input_kwargs={"Geometry": [flower_on_stem, stem_geometry]} | |
| ) | |
| realize_instances = nw.new_node( | |
| Nodes.RealizeInstances, input_kwargs={"Geometry": join_geometry_2} | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": realize_instances} | |
| ) | |
| def geometry_dandelion_seed_nodes(nw: NodeWrangler, **kwargs): | |
| # Code generated using version 2.4.3 of the node_transpiler | |
| pedal_stem = nw.new_node(nodegroup_pedal_stem().name) | |
| geometry_to_instance = nw.new_node( | |
| "GeometryNodeGeometryToInstance", input_kwargs={"Geometry": pedal_stem} | |
| ) | |
| group_output = nw.new_node( | |
| Nodes.GroupOutput, input_kwargs={"Geometry": geometry_to_instance} | |
| ) | |
| flower_modes_dict = { | |
| 0: "full_flower", | |
| 1: "no_flower", | |
| 2: "sparse_flower", | |
| } | |
| class DandelionFactory(AssetFactory): | |
| def __init__(self, factory_seed, coarse=False): | |
| super(DandelionFactory, self).__init__(factory_seed, coarse=coarse) | |
| self.get_params_dict() | |
| with FixedSeed(factory_seed): | |
| self.sample_parameters() | |
| def get_params_dict(self): | |
| # list all the parameters (key:name, value: [type, range]) used in this generator | |
| self.params_dict = { | |
| "flower_mode": ["discrete", (0, 1, 2)], | |
| "random_dropout": ["continuous", (0.2, 0.6)], | |
| "row_less_than": ["continuous", (0.0, 1.0)], | |
| "col_less_than": ["continuous", (0.0, 1.0)], | |
| "row_great_than": ["continuous", (0.0, 1.0)], | |
| "col_great_than": ["continuous", (0.0, 1.0)], | |
| "bezier_middle_x": ["continuous", (-0.6, 0.6)], | |
| "bezier_middle_y": ["continuous", (-0.6, 0.6)], | |
| "bezier_end_x": ["continuous", (-0.6, 0.6)], | |
| "bezier_end_y": ["continuous", (-0.6, 0.6)], | |
| "flower_num_core_segments": ["discrete", (8, 15, 20, 25)], | |
| "flower_num_core_rings": ["discrete", (8, 15, 20)], | |
| "transform_scale": ["continuous", (-0.7, -0.1)], | |
| "stem_map_range": ["continuous", (0.1, 0.6)], | |
| "stem_radius": ["continuous", (0.01, 0.03)], | |
| } | |
| def sample_parameters(self): | |
| # sample all the parameters | |
| flower_mode = flower_modes_dict[randint(0, 2)] | |
| if flower_mode == "full_flower": | |
| random_dropout = 1.0 | |
| row_less_than = 0.0 | |
| row_great_than = 0.0 | |
| col_less_than = 0.0 | |
| col_great_than = 0.0 | |
| elif flower_mode == "no_flower": | |
| random_dropout = 0.0 | |
| row_less_than = 1.0 | |
| row_great_than = 0.0 | |
| col_less_than = 1.0 | |
| col_great_than = 0.0 | |
| elif flower_mode == "sparse_flower": | |
| random_dropout = uniform(0.2, 0.6) | |
| row_less_than = 0.0 | |
| row_great_than = 0.0 | |
| col_less_than = 0.0 | |
| col_great_than = 0.0 | |
| else: | |
| raise ValueError("Invalid flower mode") | |
| self.params = { | |
| "flower_mode": flower_mode, | |
| "random_dropout": random_dropout, | |
| "row_less_than": row_less_than, | |
| "row_great_than": row_great_than, | |
| "col_less_than": col_less_than, | |
| "col_great_than": col_great_than, | |
| "bezier_middle_x": normal(0.0, 0.1), | |
| "bezier_middle_y": normal(0.0, 0.1), | |
| "bezier_end_x": normal(0.0, 0.1), | |
| "bezier_end_y": normal(0.0, 0.1), | |
| "pedal_stem_mid_point_x": normal(0.0, 0.05), | |
| "pedal_stem_mid_point_y": normal(0.0, 0.05), | |
| "pedal_stem_radius": uniform(0.02, 0.045), | |
| "pedal_stem_top_radius": uniform(0.005, 0.008), | |
| "flower_num_core_segments": randint(8, 25), | |
| "flower_num_core_rings": randint(8, 20), | |
| "flower_radius": uniform(0.02, 0.05), | |
| "flower_core_shape_x": uniform(0.8, 1.2), | |
| "flower_core_shape_y": uniform(0.8, 1.2), | |
| "flower_core_shape_z": uniform(0.5, 0.8), | |
| "transform_scale": uniform(-0.5, -0.15), | |
| "stem_map_range": uniform(0.2, 0.4), | |
| "stem_radius": uniform(0.01, 0.024), | |
| } | |
| def fix_unused_params(self, params): | |
| return params | |
| def update_params(self, params): | |
| # update the parameters in the node graph | |
| flower_mode = flower_modes_dict[params["flower_mode"]] | |
| if flower_mode == "full_flower": | |
| random_dropout = uniform(0.7, 1.0) | |
| row_less_than = 0.0 | |
| row_great_than = 0.0 | |
| col_less_than = 0.0 | |
| col_great_than = 0.0 | |
| elif flower_mode == "no_flower": | |
| random_dropout = 0.0 | |
| row_less_than = 1.0 | |
| row_great_than = 0.0 | |
| col_less_than = 1.0 | |
| col_great_than = 0.0 | |
| elif flower_mode == "sparse_flower": | |
| random_dropout = params["random_dropout"] | |
| row_less_than = params["row_less_than"] | |
| row_great_than = params["row_great_than"] | |
| col_less_than = params["col_less_than"] | |
| col_great_than = params["col_great_than"] | |
| else: | |
| raise ValueError("Invalid flower mode") | |
| params = { | |
| "flower_mode": flower_mode, | |
| "random_dropout": random_dropout, | |
| "row_less_than": row_less_than, | |
| "row_great_than": row_great_than, | |
| "col_less_than": col_less_than, | |
| "col_great_than": col_great_than, | |
| "bezier_middle_x": params["bezier_middle_x"], | |
| "bezier_middle_y": params["bezier_middle_y"], | |
| "bezier_end_x": params["bezier_end_x"], | |
| "bezier_end_y": params["bezier_end_y"], | |
| "flower_num_core_segments": int(params["flower_num_core_segments"]), | |
| "flower_num_core_rings": int(params["flower_num_core_rings"]), | |
| "flower_radius": uniform(0.02, 0.05), | |
| "flower_core_shape_x": uniform(0.8, 1.2), | |
| "flower_core_shape_y": uniform(0.8, 1.2), | |
| "flower_core_shape_z": uniform(0.5, 0.8), | |
| "pedal_stem_mid_point_x": normal(0.0, 0.05), | |
| "pedal_stem_mid_point_y": normal(0.0, 0.05), | |
| "pedal_stem_radius": uniform(0.02, 0.045), | |
| "pedal_stem_top_radius": uniform(0.005, 0.008), | |
| "transform_scale": params["transform_scale"], | |
| "stem_map_range": params["stem_map_range"], | |
| "stem_radius": params["stem_radius"], | |
| } | |
| self.params.update(params) | |
| def create_asset(self, **params): | |
| bpy.ops.mesh.primitive_plane_add( | |
| size=1, | |
| enter_editmode=False, | |
| align="WORLD", | |
| location=(0, 0, 0), | |
| scale=(1, 1, 1), | |
| ) | |
| obj = bpy.context.active_object | |
| surface.add_geomod( | |
| obj, | |
| geometry_dandelion_nodes, | |
| apply=True, | |
| attributes=[], | |
| input_kwargs=self.params, | |
| ) | |
| tag_object(obj, "dandelion") | |
| return obj | |
| class DandelionSeedFactory(AssetFactory): | |
| def __init__(self, factory_seed, coarse=False): | |
| super(DandelionSeedFactory, self).__init__(factory_seed, coarse=coarse) | |
| def create_asset(self, **params): | |
| bpy.ops.mesh.primitive_plane_add( | |
| size=1, | |
| enter_editmode=False, | |
| align="WORLD", | |
| location=(0, 0, 0), | |
| scale=(1, 1, 1), | |
| ) | |
| obj = bpy.context.active_object | |
| surface.add_geomod( | |
| obj, | |
| geometry_dandelion_seed_nodes, | |
| apply=True, | |
| attributes=[], | |
| input_kwargs=params, | |
| ) | |
| tag_object(obj, "seed") | |
| return obj | |
| if __name__ == "__main__": | |
| f = DandelionSeedFactory(0) | |
| obj = f.create_asset() | |