diff --git a/.gitignore b/.gitignore index d7c639f9b..8b3a142d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -Python-3.10.2 -Python-3.10.2.tgz +Python-* +Python-*.tgz blender blender.tar.xz Blender.app diff --git a/docs/GeneratingIndividualAssets.md b/docs/GeneratingIndividualAssets.md index 774f6a838..0fe8b5275 100644 --- a/docs/GeneratingIndividualAssets.md +++ b/docs/GeneratingIndividualAssets.md @@ -13,9 +13,9 @@ Shown are three examples of using our `generate_individual_assets.py` script to ```bash cd worldgen mkdir outputs -$BLENDER --background --python tools/generate_individual_assets.py -- -f CoralFactory -n 8 --save_blend -$BLENDER --background --python tools/generate_individual_assets.py -- -f seashells -n 1 --save_blend -$BLENDER --background --python tools/generate_individual_assets.py -- -f chunkyrock -n 1 --save_blend +python tools/generate_individual_assets.py -- -f CoralFactory -n 8 --save_blend +python tools/generate_individual_assets.py -- -f seashells -n 1 --save_blend +python tools/generate_individual_assets.py -- -f chunkyrock -n 1 --save_blend ```

@@ -26,7 +26,7 @@ $BLENDER --background --python tools/generate_individual_assets.py -- -f chunkyr Running the above commands will save images and .blend files into your `outputs` folder. -Please run `$BLENDER --background --python tools/generate_individual_assets.py -- --help` for a full list of commandline arguments. +Please run `python tools/generate_individual_assets.py -- --help` for a full list of commandline arguments. The most commonly used arguments are: - `-f` to specify the name(s) of assets or materials to generate. `-f NAME` can specify to generate three different types of objects: diff --git a/docs/GroundTruthAnnotations.md b/docs/GroundTruthAnnotations.md index f5f6a1494..2837c4ad4 100644 --- a/docs/GroundTruthAnnotations.md +++ b/docs/GroundTruthAnnotations.md @@ -70,7 +70,7 @@ Continuing the [Hello-World](/README.md#generate-a-scene-step-by-step) example, 4. Export the geometry from blender to disk ``` -$BLENDER -noaudio --background --python generate.py -- --seed 0 --task mesh_save -g desert simple --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/saved_mesh +$python generate.py -- --seed 0 --task mesh_save -g desert simple --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/saved_mesh ``` 5. Generate dense annotations ``` diff --git a/docs/HelloWorld.md b/docs/HelloWorld.md index 2d4caaba4..f04b24f39 100644 --- a/docs/HelloWorld.md +++ b/docs/HelloWorld.md @@ -21,16 +21,16 @@ cd worldgen mkdir outputs # Generate a scene layout -$BLENDER -noaudio --background --python generate.py -- --seed 0 --task coarse -g desert.gin simple.gin --output_folder outputs/helloworld/coarse +python generate.py -- --seed 0 --task coarse -g desert.gin simple.gin --output_folder outputs/helloworld/coarse # Populate unique assets -$BLENDER -noaudio --background --python generate.py -- --seed 0 --task populate fine_terrain -g desert.gin simple.gin --input_folder outputs/helloworld/coarse --output_folder outputs/helloworld/fine +python generate.py -- --seed 0 --task populate fine_terrain -g desert.gin simple.gin --input_folder outputs/helloworld/coarse --output_folder outputs/helloworld/fine # Render RGB images -$BLENDER -noaudio --background --python generate.py -- --seed 0 --task render -g desert.gin simple.gin --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames +python generate.py -- --seed 0 --task render -g desert.gin simple.gin --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames # Render again for accurate ground-truth -$BLENDER -noaudio --background --python generate.py -- --seed 0 --task render -g desert.gin simple.gin --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames -p render.render_image_func=@flat/render_image +python generate.py -- --seed 0 --task render -g desert.gin simple.gin --input_folder outputs/helloworld/fine --output_folder outputs/helloworld/frames -p render.render_image_func=@flat/render_image ``` Output logs should indicate what the code is working on. Use `--debug` for even more detail. After each command completes you can inspect it's `--output_folder` for results, including running `$BLENDER outputs/helloworld/coarse/scene.blend` or similar to view blender files. We hide many meshes by default for viewport stability; to view them, click "Render" or use the UI to unhide them. diff --git a/install.sh b/install.sh index 012f1e3c1..e7e95ce58 100755 --- a/install.sh +++ b/install.sh @@ -1,89 +1,15 @@ #!/bin/bash -if ! command -v wget &> /dev/null -then - echo "wget could not be found, please 'sudo apt-get install wget' or 'brew install wget'" - exit -fi - -OS=$(uname -s) -ARCH=$(uname -m) - -if [ "${OS}" = "Linux" ]; then - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-linux-x64.tar.xz' - BLENDER_WGET_FILE='blender.tar.xz' - - BLENDER_UNTAR_DIR='blender-3.3.1-linux-x64' - BLENDER_DIR='blender' - BLENDER_PYTHON="${BLENDER_DIR}/3.3/python/bin/python3.10" - BLENDER_INCLUDE="${BLENDER_DIR}/3.3/python/include/python3.10" - BLENDER_PACKAGES="${BLENDER_DIR}/3.3/python/lib/python3.10/site-packages" - BLENDER_ADDONS="${BLENDER_DIR}/3.3/scripts/addons" - BLENDER_EXE="${BLENDER_DIR}/blender" - - NURBS_SCRIPT="setup_linux.py" -elif [ "${OS}" = "Darwin" ]; then - if [ "${ARCH}" = "arm64" ]; then - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-arm64.dmg' - NURBS_SCRIPT="setup_macos_as.py" - else - BLENDER_WGET_LINK='https://download.blender.org/release/Blender3.3/blender-3.3.1-macos-x64.dmg' - NURBS_SCRIPT="setup_macos.py" - fi - if [ "${ARCH}" = "arm64" ]; then - HOMEBREW_PREFIX="/opt/homebrew/" - else - HOMEBREW_PREFIX="/usr/local" - fi - BLENDER_WGET_FILE='blender.dmg' - - BLENDER_VOLM='/Volumes/Blender' - BLENDER_DIR='./Blender.app' - BLENDER_PYTHON="${BLENDER_DIR}/Contents/Resources/3.3/python/bin/python3.10" - BLENDER_INCLUDE="${BLENDER_DIR}/Contents/Resources/3.3/python/include/python3.10" - BLENDER_PACKAGES="${BLENDER_DIR}/Contents/Resources/3.3/python/lib/python3.10/site-packages" - BLENDER_ADDONS="${BLENDER_DIR}/Contents/Resources/3.3/scripts/addons" - BLENDER_EXE="${BLENDER_DIR}/Contents/MacOS/Blender" - - export CC="${HOMEBREW_PREFIX}/opt/llvm/bin/clang" - export CPATH="${HOMEBREW_PREFIX}/include:${CPATH}" -else - echo "Unsupported OS" - exit -1 -fi REQUIREMENTS_PATH='./requirements.txt' -PYTHON_WGET_LINK='https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tgz' -PYTHON_WGET_FILE='Python-3.10.2.tgz' -PYTHON_DIR='Python-3.10.2' +PYTHON_WGET_LINK='https://www.python.org/ftp/python/3.10.9/Python-3.10.9.tgz' +PYTHON_WGET_FILE='Python-3.10.9.tgz' +PYTHON_DIR='Python-3.10.9' git submodule init git submodule update -if [ ! -d "${BLENDER_DIR}" ]; then - # Download Blender - wget -O "${BLENDER_WGET_FILE}" "${BLENDER_WGET_LINK}" - - # Unzip Blender - if [ "${OS}" = "Darwin" ]; then - hdiutil attach "${BLENDER_WGET_FILE}" - cp -r "${BLENDER_VOLM}/Blender.app" "${BLENDER_DIR}" - hdiutil detach "${BLENDER_VOLM}" - else - tar -xf "${BLENDER_WGET_FILE}" - mv "${BLENDER_UNTAR_DIR}" "${BLENDER_DIR}" - fi - - rm "${BLENDER_WGET_FILE}" -fi - -# Install llvm for MacOS -if [ "${OS}" = "Darwin" ]; then - brew install llvm open-mpi libomp glm glew -fi - # Install Conda dependencies pip install -r "${REQUIREMENTS_PATH}" -pip install fake-bpy-module-latest if [ ! -d "${PYTHON_DIR}" ]; then # Install Python include file @@ -91,26 +17,36 @@ if [ ! -d "${PYTHON_DIR}" ]; then tar -xf "${PYTHON_WGET_FILE}" rm "${PYTHON_WGET_FILE}" fi -cp -r "${PYTHON_DIR}/Include/"* "${BLENDER_INCLUDE}" -# Install Blender dependencies -"${BLENDER_PYTHON}" -m ensurepip -CFLAGS="-I$(realpath ${BLENDER_INCLUDE}) ${CFLAGS}" "${BLENDER_PYTHON}" -m pip install -r "${REQUIREMENTS_PATH}" +# Install llvm for MacOS +if [ "${OS}" = "Darwin" ]; then + arch -arm64 brew install llvm open-mpi libomp glm glew +fi + +bash worldgen/tools/install/install_bnurbs.sh # Build terrain -rm -rf ${BLENDER_PACKAGES}/terrain-* rm -rf *.egg-info rm -rf __pycache__ rm -rf ./worldgen/terrain/build cd ./worldgen/terrain -if [ -f "/usr/local/cuda/bin/nvcc" ]; then - USE_CUDA=1 bash install_terrain.sh +bash install_terrain.sh +python setup.py build_ext --inplace --force +cd - + +# Compile process_mesh (i.e. OpenGL-based ground truth) +cd ./process_mesh +/usr/bin/cmake -S . -Bbuild -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_BUILD_TYPE=Release +/usr/bin/cmake --build build --target all +./build/process_mesh -in x -out x --height 100 --width 10 +if [ $? -eq 174 ]; then + echo "OpenGL/EGL ground truth is working." else - USE_CUDA=0 bash install_terrain.sh + echo "WARNING: OpenGL/EGL is not supported on this machine. If you are running from a cluster head-node, this is likely not an issue." fi -"../../${BLENDER_PYTHON}" setup.py build_ext --inplace --force cd - +<<<<<<< HEAD # Build NURBS cd ./worldgen/assets/creatures/geometry/cpp_utils @@ -127,4 +63,6 @@ fi # Build Flip Fluids addon if [ "$1" = "flip_fluids" ] || [ "$2" = "flip_fluids" ]; then bash ./worldgen/tools/install/compile_flip_fluids.sh -fi \ No newline at end of file +fi +======= +>>>>>>> 84118268d (Initial buggy 3.5 fixes) diff --git a/requirements.txt b/requirements.txt index 36a8e0b4d..b938ca04d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +bpy==3.6.0 gin-config>=0.5.0 tqdm opencv-python<=4.8.0.74 diff --git a/worldgen/assets/boulder.py b/worldgen/assets/boulder.py index d12ebd0a5..de682ba41 100644 --- a/worldgen/assets/boulder.py +++ b/worldgen/assets/boulder.py @@ -126,7 +126,7 @@ def geo_extrusion(nw: NodeWrangler, extrude_scale=1): tops.append(top) geometry = nw.new_node(Nodes.StoreNamedAttribute, - [geometry, 'top', None, reduce(lambda *xs: nw.boolean_math('OR', *xs), tops)]) + input_kwargs={'Geometry': geometry, 'Name': 'top', 'Value': reduce(lambda *xs: nw.boolean_math('OR', *xs), tops)}) nw.new_node(Nodes.GroupOutput, input_kwargs={"Geometry": geometry}) def create_asset(self, i, placeholder, face_size=0.01, distance=0, **params): diff --git a/worldgen/assets/corals/star.py b/worldgen/assets/corals/star.py index 4e8cc86ad..b5badb6bc 100644 --- a/worldgen/assets/corals/star.py +++ b/worldgen/assets/corals/star.py @@ -53,8 +53,8 @@ def geo_separate_faces(nw: NodeWrangler): scale = nw.uniform(.9, 1.2) geometry = nw.new_node(Nodes.ScaleElements, [geometry, None, scale]) geometry = nw.new_node(Nodes.StoreNamedAttribute, - [geometry, 'custom_normal', nw.new_node(Nodes.InputNormal)], - attrs={'data_type': 'FLOAT_VECTOR'}) + input_kwargs={'Geometry': geometry, 'Name': 'custom_normal', 'Value': nw.new_node(Nodes.InputNormal)}, + attrs={'data_type': 'FLOAT_VECTOR'}) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) @staticmethod @@ -65,7 +65,8 @@ def geo_flower(nw: NodeWrangler, size, resolution, anchor): normal = nw.new_node(Nodes.NamedAttribute, ['custom_normal'], attrs={'data_type': 'FLOAT_VECTOR'}) geometry = nw.new_node(Nodes.SetPosition, [geometry, None, None, nw.scale(offset, normal)]) outer = nw.boolean_math('AND', nw.compare('GREATER_THAN', t, .4), nw.compare('LESS_THAN', t, .6)) - geometry = nw.new_node(Nodes.StoreNamedAttribute, [geometry, 'outermost', None, outer]) + geometry = nw.new_node(Nodes.StoreNamedAttribute, + input_kwargs={'Geometry': geometry, 'Name': 'outermost', 'Value': outer}) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) def create_asset(self, face_size=0.01, **params): diff --git a/worldgen/assets/creatures/generate.py b/worldgen/assets/creatures/generate.py index a6adc7b7e..6c21d061c 100644 --- a/worldgen/assets/creatures/generate.py +++ b/worldgen/assets/creatures/generate.py @@ -194,6 +194,8 @@ def rig(): if adaptive_resolution and smooth_attrs: for attr in joined.data.attributes.keys(): + if butil.blender_internal_attr(attr): + continue logger.debug(f'Smoothing attr {attr}') surface.smooth_attribute(joined, attr, iters=10) diff --git a/worldgen/assets/creatures/hair.py b/worldgen/assets/creatures/hair.py index bb60626c2..b32a9633f 100644 --- a/worldgen/assets/creatures/hair.py +++ b/worldgen/assets/creatures/hair.py @@ -111,11 +111,15 @@ def nodegroup_decode_noise(nw: NodeWrangler): map_range_1 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': noise_texture.outputs["Fac"], 3: separate_xyz.outputs["X"], 4: separate_xyz.outputs["Y"]}) - transfer_attribute = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': group_input.outputs["Source"], 2: map_range_1.outputs["Result"], 'Source Position': group_input.outputs["Source Position"]}) - + transfer_attribute = nw.new_node(Nodes.SampleNearestSurface, + input_kwargs={ + 'Mesh': group_input.outputs["Source"], + 'Value': map_range_1.outputs["Result"], + 'Sample Position': group_input.outputs["Source Position"] + }) + group_output = nw.new_node(Nodes.GroupOutput, - input_kwargs={'Attribute': transfer_attribute.outputs[1]}) + input_kwargs={'Attribute': (transfer_attribute, 'Value')}) @node_utils.to_nodegroup('nodegroup_hair_grooming', singleton=True, type='GeometryNodeTree') def nodegroup_hair_grooming(nw: NodeWrangler): @@ -186,7 +190,7 @@ def nodegroup_hair_grooming(nw: NodeWrangler): input_kwargs={'Value': spline_parameter.outputs["Factor"], 3: group_input.outputs["Root Radius"], 4: 0.0}) set_curve_radius = nw.new_node(Nodes.SetCurveRadius, - input_kwargs={'Curve': snaprootstosurface, 'Radius': map_range.outputs["Result"]}) + input_kwargs={'Curves': snaprootstosurface, 'Radius': map_range.outputs["Result"]}) group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': set_curve_radius}) @@ -222,10 +226,14 @@ def geo_transfer_hair_attributes(nw, obj, attrs): named_attr = nw.new_node(Nodes.NamedAttribute, attrs={'data_type': obj_attr.data_type}, input_kwargs={'Name': attr_name}) - transfer = nw.new_node(Nodes.TransferAttribute, + transfer = nw.new_node(Nodes.SampleNearestSurface, attrs={'data_type': obj_attr.data_type}, - input_kwargs={'Source': object_info.outputs['Geometry'], "Attribute": named_attr, 'Source Position': hairposition}) - attrs_out[attr_name] = (transfer, 'Attribute') + input_kwargs={ + 'Mesh': object_info.outputs['Geometry'], + "Value": named_attr, + 'Sample Position': hairposition + }) + attrs_out[attr_name] = (transfer, 'Value') nw.new_node(Nodes.GroupOutput, input_kwargs={ 'Geometry': group_input.outputs['Geometry'], **attrs_out}) @@ -329,7 +337,7 @@ def nodegroup_transfer_uvs_to_curves_vec3(nw: NodeWrangler): input_kwargs={ 'Geometry': group_input.outputs["Geometry"], 'Name': group_input.outputs['to_attr'], - 2: transfer_attribute.outputs["Attribute"]}, + 'Value': transfer_attribute.outputs["Attribute"]}, attrs={'data_type': 'FLOAT_VECTOR', 'domain': 'CURVE'}) group_output = nw.new_node(Nodes.GroupOutput, diff --git a/worldgen/assets/creatures/nodegroups/hair.py b/worldgen/assets/creatures/nodegroups/hair.py index c09e713a2..d33b94e75 100644 --- a/worldgen/assets/creatures/nodegroups/hair.py +++ b/worldgen/assets/creatures/nodegroups/hair.py @@ -24,8 +24,8 @@ def nodegroup_comb_direction(nw: NodeWrangler): normal = nw.new_node(Nodes.InputNormal) - surface_normal = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': group_input.outputs["Surface"], 1: normal, 'Source Position': group_input.outputs["Root Positiion"]}, + surface_normal = nw.new_node(Nodes.SampleNearestSurface, + input_kwargs={'Mesh': group_input.outputs["Surface"], 'Value': normal, 'Sample Position': group_input.outputs["Root Positiion"]}, label='Surface Normal', attrs={'data_type': 'FLOAT_VECTOR'}) @@ -45,17 +45,16 @@ def nodegroup_comb_direction(nw: NodeWrangler): input_kwargs={0: subtract.outputs["Vector"]}, attrs={'operation': 'NORMALIZE'}) - skeleton_tangent = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': group_input.outputs["Surface"], 1: normalize.outputs["Vector"], 'Source Position': group_input.outputs["Root Positiion"]}, - label='Skeleton Tangent', + skeleton_tangent = nw.new_node(Nodes.SampleNearestSurface, + input_kwargs={'Mesh': group_input.outputs["Surface"], 'Value': normalize.outputs["Vector"], 'Sample Position': group_input.outputs["Root Positiion"]}, attrs={'data_type': 'FLOAT_VECTOR'}) cross_product = nw.new_node(Nodes.VectorMath, - input_kwargs={0: surface_normal.outputs["Attribute"], 1: skeleton_tangent.outputs["Attribute"]}, + input_kwargs={0: surface_normal, 1: skeleton_tangent}, attrs={'operation': 'CROSS_PRODUCT'}) cross_product_1 = nw.new_node(Nodes.VectorMath, - input_kwargs={0: surface_normal.outputs["Attribute"], 1: cross_product.outputs["Vector"]}, + input_kwargs={0: surface_normal, 1: cross_product.outputs["Vector"]}, attrs={'operation': 'CROSS_PRODUCT'}) normalize_1 = nw.new_node(Nodes.VectorMath, @@ -63,7 +62,11 @@ def nodegroup_comb_direction(nw: NodeWrangler): attrs={'operation': 'NORMALIZE'}) group_output = nw.new_node(Nodes.GroupOutput, - input_kwargs={'Combing Direction': normalize_1.outputs["Vector"], 'Surface Normal': surface_normal.outputs["Attribute"], 'Skeleton Tangent': skeleton_tangent.outputs["Attribute"]}) + input_kwargs={ + 'Combing Direction': normalize_1.outputs["Vector"], + 'Surface Normal': surface_normal.outputs["Attribute"], + 'Skeleton Tangent': skeleton_tangent + }) @node_utils.to_nodegroup('nodegroup_hair_position', singleton=True, type='GeometryNodeTree') def nodegroup_hair_position(nw: NodeWrangler): @@ -82,20 +85,23 @@ def nodegroup_hair_position(nw: NodeWrangler): input_kwargs={0: index, 1: spline_length.outputs["Point Count"]}, attrs={'operation': 'SNAP'}) - hair_root_position = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': group_input.outputs["Curves"], 1: position, 'Index': snap}, + hair_root_position = nw.new_node(Nodes.SampleIndex, + input_kwargs={'Geometry': group_input.outputs["Curves"], 'Value': position, 'Index': snap}, label='Hair Root Position', - attrs={'data_type': 'FLOAT_VECTOR', 'mapping': 'INDEX'}) + attrs={'data_type': 'FLOAT_VECTOR'}) position_1 = nw.new_node(Nodes.InputPosition) relative_position = nw.new_node(Nodes.VectorMath, - input_kwargs={0: position_1, 1: hair_root_position.outputs["Attribute"]}, + input_kwargs={0: position_1, 1: hair_root_position}, label='Relative Position', attrs={'operation': 'SUBTRACT'}) - + group_output = nw.new_node(Nodes.GroupOutput, - input_kwargs={'Root Position': hair_root_position.outputs["Attribute"], 'Relative Position': relative_position.outputs["Vector"]}) + input_kwargs={ + 'Root Position': hair_root_position, + 'Relative Position': relative_position.outputs["Vector"] + }) @node_utils.to_nodegroup('nodegroup_comb_hairs', singleton=True, type='GeometryNodeTree') def nodegroup_comb_hairs(nw: NodeWrangler): diff --git a/worldgen/assets/creatures/parts/leg.py b/worldgen/assets/creatures/parts/leg.py index 0da8a4797..4df930ff0 100644 --- a/worldgen/assets/creatures/parts/leg.py +++ b/worldgen/assets/creatures/parts/leg.py @@ -230,7 +230,7 @@ def nodegroup_insect_leg(nw: NodeWrangler): input_kwargs={'Skin Mesh': simple_tube_v2.outputs["Geometry"], 'Skeleton Curve': simple_tube_v2.outputs["Skeleton Curve"], 'Coord 0': (0.0, 0.0, 0.0), 'Coord 1': (0.01, 0.0, 0.0), 'Coord 2': (0.35, 0.0, 0.0), 'StartRad, EndRad, Fullness': combine_xyz, 'ProfileHeight, StartTilt, EndTilt': (0.73, 0.0, 0.0)}) trim_curve = nw.new_node(Nodes.TrimCurve, - input_kwargs={'Curve': simple_tube_v2.outputs["Skeleton Curve"], 1: 0.4892, 2: 0.725}) + input_kwargs={'Curve': simple_tube_v2.outputs["Skeleton Curve"], 'Start': 0.4892, 'End': 0.725}) resample_curve = nw.new_node(Nodes.ResampleCurve, input_kwargs={'Curve': trim_curve, 'Count': 4}) diff --git a/worldgen/assets/creatures/parts/ridged_fin.py b/worldgen/assets/creatures/parts/ridged_fin.py index 34664cb88..7d5b4c70b 100644 --- a/worldgen/assets/creatures/parts/ridged_fin.py +++ b/worldgen/assets/creatures/parts/ridged_fin.py @@ -413,7 +413,11 @@ def nodegroup_fish_fin(nw: NodeWrangler): attrs={'use_clamp': True}) store_cloth_pin = nw.new_node(Nodes.StoreNamedAttribute, - input_kwargs={'Geometry': transform_2, 'Name': 'cloth_pin_rigidity', 3: add_final_rigidity}, + input_kwargs={ + 'Geometry': transform_2, + 'Name': 'cloth_pin_rigidity', + 'Value': add_final_rigidity + }, label='store_cloth_pin') group_output = nw.new_node(Nodes.GroupOutput, diff --git a/worldgen/assets/creatures/parts/wings.py b/worldgen/assets/creatures/parts/wings.py index 432e02d18..8d1bafa0c 100644 --- a/worldgen/assets/creatures/parts/wings.py +++ b/worldgen/assets/creatures/parts/wings.py @@ -72,7 +72,7 @@ def nodegroup_feather(nw: NodeWrangler): input_kwargs={'Curve': curve_line, 'Cuts': 4}) trim_curve = nw.new_node(Nodes.TrimCurve, - input_kwargs={'Curve': subdivide_curve_1, 2: 0.8742}) + input_kwargs={'Curve': subdivide_curve_1, 'End': 0.8742}) map_range_1 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': spline_parameter.outputs["Factor"], 3: 0.15, 4: 0.05}) @@ -198,12 +198,12 @@ def nodegroup_bird_wing(nw: NodeWrangler): map_range_1 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': index, 1: attribute_statistic.outputs["Min"], 2: attribute_statistic.outputs["Max"]}) - transfer_attribute = nw.new_node(Nodes.TransferAttribute, + transfer_attribute = nw.new_node(Nodes.SampleNearestSurface, input_kwargs={'Source': curve_to_mesh, 2: map_range_1.outputs["Result"]}, attrs={'mapping': 'NEAREST'}) float_curve = nw.new_node(Nodes.FloatCurve, - input_kwargs={'Factor': group_input.outputs["Wing Shape Sculpting"], 'Value': transfer_attribute.outputs[1]}) + input_kwargs={'Factor': group_input.outputs["Wing Shape Sculpting"], 'Value': (transfer_attribute, 'Value')}) node_utils.assign_curve(float_curve.mapping.curves[0], [(0.0, 0.0), (0.5164, 0.245), (0.7564, 0.625), (1.0, 1.0)]) map_range_2 = nw.new_node(Nodes.MapRange, @@ -343,7 +343,7 @@ def nodegroup_flying_feather(nw: NodeWrangler): input_kwargs={'Curve': set_position, 'Cuts': 4}) trim_curve = nw.new_node(Nodes.TrimCurve, - input_kwargs={'Curve': subdivide_curve_1, 2: 0.8742}) + input_kwargs={'Curve': subdivide_curve_1, 'End': 0.8742}) spline_parameter = nw.new_node(Nodes.SplineParameter) @@ -549,9 +549,8 @@ def nodegroup_flying_bird_wing(nw: NodeWrangler): input_kwargs={'Value': index, 1: attribute_statistic.outputs["Min"], 2: attribute_statistic.outputs["Max"]}) - transfer_attribute = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': curve_to_mesh, 2: map_range_1.outputs["Result"]}, - attrs={'mapping': 'NEAREST'}) + transfer_attribute = nw.new_node(Nodes.SampleNearestSurface, + input_kwargs={'Source': curve_to_mesh, 'Value': map_range_1.outputs["Result"]}) map_range_2 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs["Extension"], 3: 115.6500, 4: 0.0000}) @@ -581,7 +580,7 @@ def nodegroup_flying_bird_wing(nw: NodeWrangler): vector_curves = nw.new_node(Nodes.VectorCurve, input_kwargs={'Fac': group_input.outputs["Wing Shape Sculpting"], - 'Vector': transfer_attribute.outputs[1]}) + 'Vector': (transfer_attribute, 'Value')}) node_utils.assign_curve(vector_curves.mapping.curves[0], [(-1.0000, -0.0000), (0.0218, 0.4), (0.20, 0.45), (0.5, 0.5), (0.65000, 0.6), (0.80, 0.7), (1.0000, 0.78 + N(0., 0.02))], diff --git a/worldgen/assets/deformed_trees/base.py b/worldgen/assets/deformed_trees/base.py index 3249eac74..756a0b8b4 100644 --- a/worldgen/assets/deformed_trees/base.py +++ b/worldgen/assets/deformed_trees/base.py @@ -41,7 +41,8 @@ def build_tree(self, face_size, **params): def geo_xyz(nw: NodeWrangler): geometry = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Geometry', None)]) for name, component in zip('xyz', nw.separate(nw.new_node(Nodes.InputPosition))): - geometry = nw.new_node(Nodes.StoreNamedAttribute, [geometry, name, None, component]) + geometry = nw.new_node(Nodes.StoreNamedAttribute, + input_kwargs={'Geometry':geometry, 'Name': name, 'Value': component}) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) @staticmethod diff --git a/worldgen/assets/flower.py b/worldgen/assets/flower.py index b9e08c66b..28a4ec8f0 100644 --- a/worldgen/assets/flower.py +++ b/worldgen/assets/flower.py @@ -75,7 +75,7 @@ def nodegroup_follow_curve(nw): attrs={'operation': 'MULTIPLY'}) sample_curve = nw.new_node(Nodes.SampleCurve, - input_kwargs={'Curve': group_input.outputs["Curve"], 'Length': multiply}) + input_kwargs={'Curves': group_input.outputs["Curve"], 'Length': multiply}) cross_product = nw.new_node(Nodes.VectorMath, input_kwargs={0: sample_curve.outputs["Tangent"], 1: sample_curve.outputs["Normal"]}, diff --git a/worldgen/assets/grassland/flowerplant.py b/worldgen/assets/grassland/flowerplant.py index db2be984a..cec7e49bb 100644 --- a/worldgen/assets/grassland/flowerplant.py +++ b/worldgen/assets/grassland/flowerplant.py @@ -605,7 +605,8 @@ def create_asset(self, **params): with butil.SelectObjects(obj): bpy.ops.object.material_slot_remove() bpy.ops.object.shade_flat() - bpy.ops.object.modifier_apply(modifier=mod.name) + + butil.apply_modifiers(obj) tag_object(obj, 'flowerplant') return obj diff --git a/worldgen/assets/leaves/leaf_v2.py b/worldgen/assets/leaves/leaf_v2.py index ab43bed39..d9cd9b5c7 100644 --- a/worldgen/assets/leaves/leaf_v2.py +++ b/worldgen/assets/leaves/leaf_v2.py @@ -5,6 +5,7 @@ import colorsys +import logging import numpy as np from numpy.random import uniform, normal @@ -907,6 +908,9 @@ def geo_leaf_v2(nw, **kwargs): set_position = nw.new_node(Nodes.SetPosition, input_kwargs={'Geometry': leafgen.outputs["Mesh"], 'Offset': combine_xyz}) + logging.warning(f'Disabling set_position to avoid LeafV2 segfault') + set_position = leafgen.outputs["Mesh"] + applywave = nw.new_node(nodegroup_apply_wave(y_wave_control_points=kwargs['y_wave_control_points'], x_wave_control_points=kwargs['x_wave_control_points']).name, input_kwargs={'Geometry': set_position, 'Wave Scale X': 0.15, 'Wave Scale Y': 1.5, 'X Modulated': leafgen.outputs["X Modulated"]}) diff --git a/worldgen/assets/monocot/growth.py b/worldgen/assets/monocot/growth.py index b37ac7844..40a027050 100644 --- a/worldgen/assets/monocot/growth.py +++ b/worldgen/assets/monocot/growth.py @@ -130,7 +130,8 @@ def geo_flower(nw: NodeWrangler, leaves): 'Scale': scale }) geometry = nw.new_node(Nodes.RealizeInstances, [instances]) - geometry = nw.new_node(Nodes.StoreNamedAttribute, [geometry, 'z_rotation', None, z_rotation]) + geometry = nw.new_node(Nodes.StoreNamedAttribute, + input_kwargs={'Geometry': geometry, 'Name':'z_rotation', 'Value': z_rotation}) geometry = nw.new_node(Nodes.JoinGeometry, [[stem, geometry]]) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) diff --git a/worldgen/assets/mushroom/cap.py b/worldgen/assets/mushroom/cap.py index 63fe6489a..94dfc9d39 100644 --- a/worldgen/assets/mushroom/cap.py +++ b/worldgen/assets/mushroom/cap.py @@ -176,7 +176,11 @@ def geo_xyz(nw: NodeWrangler): component = nw.math('ABSOLUTE', component) m = nw.new_node(Nodes.AttributeStatistic, [geometry, None, component]).outputs['Max'] geometry = nw.new_node(Nodes.StoreNamedAttribute, - [geometry, name, None, nw.scalar_divide(component, m)]) + input_kwargs={ + 'Geometry': geometry, + 'Name': name, + 'Value': nw.scalar_divide(component, m) + }) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) @staticmethod @@ -186,7 +190,8 @@ def geo_morel(nw: NodeWrangler): 'Scale': uniform(15, 20), 'Randomness': uniform(.5, 1) }, attrs={'feature': 'DISTANCE_TO_EDGE'}), .05) - geometry = nw.new_node(Nodes.StoreNamedAttribute, [geometry, 'morel', None, selection]) + geometry = nw.new_node(Nodes.StoreNamedAttribute, + input_kwargs={'Geometry':geometry, 'Name':'morel', 'Value': selection}) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) def apply_cut(self, obj): diff --git a/worldgen/assets/small_plants/fern.py b/worldgen/assets/small_plants/fern.py index 43eb7d4f4..4f0bdbe45 100644 --- a/worldgen/assets/small_plants/fern.py +++ b/worldgen/assets/small_plants/fern.py @@ -95,18 +95,18 @@ def nodegroup_pinnae_level1_xaxis_rotation(nw: NodeWrangler): group_input = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketFloat', 'From Max', 1.0000), - ('NodeSocketFloat', 'Value', 1.0000), - ('NodeSocketFloat', 'Value', 1.0000)]) + ('NodeSocketFloat', 'Value1', 1.0000), + ('NodeSocketFloat', 'Value2', 1.0000)]) map_range_1 = nw.new_node(Nodes.MapRange, - input_kwargs={'Value': group_input.outputs["Value"], 2: group_input.outputs["From Max"]}, + input_kwargs={'Value': group_input.outputs["Value1"], 2: group_input.outputs["From Max"]}, attrs={'clamp': False}) float_curve = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': map_range_1.outputs["Result"]}) node_utils.assign_curve(float_curve.mapping.curves[0], [(0.0000, 0.0000), (0.2000, 0.2563), (0.4843, 0.4089), (0.7882, 0.3441), (1.0000, 0.0000)]) - map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[2], 3: -1.5000, 4: 0.0000}) + map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value2'], 3: -1.5000, 4: 0.0000}) multiply = nw.new_node(Nodes.Math, input_kwargs={0: float_curve, 1: map_range.outputs["Result"]}, @@ -121,13 +121,13 @@ def nodegroup_pinnae_level1_stein(nw: NodeWrangler): group_input = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Mesh', None), - ('NodeSocketFloat', 'Value', 0.5), - ('NodeSocketFloat', 'Value', 0.5)]) + ('NodeSocketFloat', 'Value1', 0.5), + ('NodeSocketFloat', 'Value2', 0.5)]) mesh_to_curve = nw.new_node(Nodes.MeshToCurve, input_kwargs={'Mesh': group_input.outputs["Mesh"]}) - multiply = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: 0.01}, + multiply = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value2'], 1: 0.01}, attrs={'operation': 'MULTIPLY'}) set_curve_radius = nw.new_node(Nodes.SetCurveRadius, input_kwargs={'Curve': mesh_to_curve, 'Radius': multiply}) - multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value"], 1: 15.0}, + multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value1"], 1: 15.0}, attrs={'operation': 'MULTIPLY'}) curve_circle = nw.new_node(Nodes.CurveCircle, input_kwargs={'Radius': multiply_1, 'Resolution': 10}) curve_to_mesh = nw.new_node(Nodes.CurveToMesh, @@ -141,16 +141,16 @@ def nodegroup_pinnae_level1_scale(nw: NodeWrangler, pinnae_contour): # Code generated using version 2.4.3 of the node_transpiler group_input = nw.new_node(Nodes.GroupInput, - expose_input=[('NodeSocketFloat', 'Value', 1.0), - ('NodeSocketFloat', 'Value', 1.0)]) + expose_input=[('NodeSocketFloat', 'Value1', 1.0), + ('NodeSocketFloat', 'Value2', 1.0)]) - pinnae_contour_float_curve = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': group_input.outputs["Value"]}, + pinnae_contour_float_curve = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': group_input.outputs["Value1"]}, label='PinnaeContourFloatCurve') node_utils.assign_curve(pinnae_contour_float_curve.mapping.curves[0], [(0.0, pinnae_contour[0]), (0.2, pinnae_contour[1]), (0.4, pinnae_contour[2]), (0.55, pinnae_contour[3]), (0.7, pinnae_contour[4]), (0.8, pinnae_contour[5]), (0.9, pinnae_contour[6]), (1.0, pinnae_contour[7])]) - map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[1], 3: 1.0, 4: 3.0}) + map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value2'], 3: 1.0, 4: 3.0}) multiply = nw.new_node(Nodes.Math, input_kwargs={0: pinnae_contour_float_curve, 1: map_range.outputs["Result"]}, attrs={'operation': 'MULTIPLY'}) @@ -162,10 +162,10 @@ def nodegroup_pinnae_level1_instance_rotation(nw: NodeWrangler): # Code generated using version 2.4.3 of the node_transpiler group_input = nw.new_node(Nodes.GroupInput, - expose_input=[('NodeSocketFloat', 'Value', 0.5), - ('NodeSocketFloat', 'Value', 1.0)]) - map_range_8 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[1], 3: 2, 4: 3.1}) - add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value"], 1: map_range_8.outputs["Result"]}) + expose_input=[('NodeSocketFloat', 'Value1', 0.5), + ('NodeSocketFloat', 'Value2', 1.0)]) + map_range_8 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value2'], 3: 2, 4: 3.1}) + add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value1"], 1: map_range_8.outputs["Result"]}) combine_xyz = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': add}) group_output = nw.new_node(Nodes.GroupOutput, input_kwargs={'Vector': combine_xyz}) @@ -177,16 +177,16 @@ def nodegroup_pinnae_level1_rotation(nw: NodeWrangler, gravity_rotation=1): position = nw.new_node(Nodes.InputPosition) group_input = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Geometry', None), - ('NodeSocketFloat', 'Value', 1.0), - ('NodeSocketFloat', 'Value', 0.5)]) + ('NodeSocketFloat', 'Value1', 1.0), + ('NodeSocketFloat', 'Value2', 0.5)]) bounding_box = nw.new_node(Nodes.BoundingBox, input_kwargs={'Geometry': group_input.outputs["Geometry"]}) multiply = nw.new_node(Nodes.VectorMath, input_kwargs={0: bounding_box.outputs["Max"], 1: (0.0, 0.0, 1.0)}, attrs={'operation': 'MULTIPLY'}) - add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: 0.0}) + add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value2'], 1: 0.0}) pinnae_index = nw.new_node(Nodes.Index, label='PinnaeIndex') pinnaelevel1xaxisrotation = nw.new_node(nodegroup_pinnae_level1_xaxis_rotation().name, input_kwargs={'From Max': add, 1: pinnae_index, - 2: group_input.outputs["Value"]}) + 2: group_input.outputs["Value1"]}) vector_rotate = nw.new_node(Nodes.VectorRotate, input_kwargs={'Vector': position, 'Center': (0, 0, 0), 'Angle': pinnaelevel1xaxisrotation}, @@ -218,12 +218,12 @@ def nodegroup_pinnae_level1_instance_position(nw: NodeWrangler, pinnae_contour): # Code generated using version 2.4.3 of the node_transpiler group_input = nw.new_node(Nodes.GroupInput, - expose_input=[('NodeSocketFloat', 'Value', 1.0), + expose_input=[('NodeSocketFloat', 'Value1', 1.0), ('NodeSocketFloat', 'From Max', 1.0), - ('NodeSocketFloat', 'Value', 1.0)]) + ('NodeSocketFloat', 'Value2', 1.0)]) map_range_3 = nw.new_node(Nodes.MapRange, - input_kwargs={'Value': group_input.outputs["Value"], 2: group_input.outputs["From Max"], + input_kwargs={'Value': group_input.outputs["Value1"], 2: group_input.outputs["From Max"], 3: 1.0, 4: 0.0}) float_curve_2 = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': map_range_3.outputs["Result"]}) @@ -233,7 +233,7 @@ def nodegroup_pinnae_level1_instance_position(nw: NodeWrangler, pinnae_contour): (0.9, pinnae_contour[6]), (1.0, pinnae_contour[7])]) accumulate_field_1 = nw.new_node(Nodes.AccumulateField, input_kwargs={1: float_curve_2}) # pinnae scale w.r.t fern age - map_range_5 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[2], 3: 0.3, 4: 4.5}) + map_range_5 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value2'], 3: 0.3, 4: 4.5}) multiply = nw.new_node(Nodes.Math, input_kwargs={0: accumulate_field_1.outputs[4], 1: map_range_5.outputs["Result"]}, attrs={'operation': 'MULTIPLY'}) @@ -249,11 +249,11 @@ def nodegroup_pinnae_level2_rotation(nw: NodeWrangler, z_axis_rotate, y_axis_rot position_1 = nw.new_node(Nodes.InputPosition) group_input = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Geometry', None), - ('NodeSocketFloat', 'Value', 1.0), - ('NodeSocketFloat', 'Value', 0.5), - ('NodeSocketFloat', 'Value', 0.5)]) - add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: 0.0}) - add_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[3], 1: 0.0}) + ('NodeSocketFloat', 'Value1', 1.0), + ('NodeSocketFloat', 'Value2', 0.5), + ('NodeSocketFloat', 'Value3', 0.5)]) + add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value2'], 1: 0.0}) + add_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value3'], 1: 0.0}) map_range_2 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': add, 'From Max': add_1}) float_curve_1 = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': map_range_2.outputs["Result"]}) node_utils.assign_curve(float_curve_1.mapping.curves[0], @@ -262,7 +262,7 @@ def nodegroup_pinnae_level2_rotation(nw: NodeWrangler, z_axis_rotate, y_axis_rot add_2 = nw.new_node(Nodes.Math, input_kwargs={0: float_curve_1, 1: -0.25}) # pinna z-axis curvature w.r.t the fern age - map_range_7 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[1], 3: 1.2, 4: 0.0}) + map_range_7 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value1'], 3: 1.2, 4: 0.0}) multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: add_2, 1: map_range_7.outputs["Result"]}, attrs={'operation': 'MULTIPLY'}) @@ -296,11 +296,11 @@ def nodegroup_pinnae_level2_set_point(nw: NodeWrangler, pinna_contour): # Code generated using version 2.4.3 of the node_transpiler group_input = nw.new_node(Nodes.GroupInput, - expose_input=[('NodeSocketFloat', 'Value', 1.0), + expose_input=[('NodeSocketFloat', 'Value1', 1.0), ('NodeSocketFloat', 'From Max', 1.0), - ('NodeSocketFloat', 'Value', 1.0)]) + ('NodeSocketFloat', 'Value2', 1.0)]) map_range_4 = nw.new_node(Nodes.MapRange, - input_kwargs={'Value': group_input.outputs["Value"], 2: group_input.outputs["From Max"], + input_kwargs={'Value': group_input.outputs["Value1"], 2: group_input.outputs["From Max"], 3: 1.0, 4: 0.0}) float_curve = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': map_range_4.outputs["Result"]}) node_utils.assign_curve(float_curve.mapping.curves[0], [(0.0, pinna_contour[0]), (0.38, pinna_contour[1]), @@ -309,7 +309,7 @@ def nodegroup_pinnae_level2_set_point(nw: NodeWrangler, pinna_contour): accumulate_field_2 = nw.new_node(Nodes.AccumulateField, input_kwargs={1: float_curve}) # pinna scale w.r.t fern age - map_range_6 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[2], 3: 0.5, 4: 2.0}) + map_range_6 = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value2'], 3: 0.5, 4: 2.0}) multiply = nw.new_node(Nodes.Math, input_kwargs={0: accumulate_field_2.outputs[4], 1: map_range_6.outputs["Result"]}, attrs={'operation': 'MULTIPLY'}) @@ -324,9 +324,9 @@ def nodegroup_pinnae_level2_instance_on_points(nw: NodeWrangler, leaf, pinna_con group_input = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Points', None), - ('NodeSocketFloat', 'Value', 1.0), - ('NodeSocketFloat', 'Value', 0.5), - ('NodeSocketFloat', 'Value', 1.0)]) + ('NodeSocketFloat', 'Value1', 1.0), + ('NodeSocketFloat', 'Value2', 0.5), + ('NodeSocketFloat', 'Value3', 1.0)]) index = nw.new_node(Nodes.Index) object_info_2 = nw.new_node(Nodes.ObjectInfo, input_kwargs={'Object': leaf}) transform = nw.new_node(Nodes.Transform, @@ -334,14 +334,14 @@ def nodegroup_pinnae_level2_instance_on_points(nw: NodeWrangler, leaf, pinna_con transform_2 = nw.new_node(Nodes.Transform, input_kwargs={'Geometry': object_info_2.outputs["Geometry"], 'Scale': (1.2, 1.0, 1.0)}) join_geometry = nw.new_node(Nodes.JoinGeometry, input_kwargs={'Geometry': [transform, transform_2]}) - add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: -0.3}) + add = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value2'], 1: -0.3}) combine_xyz_3 = nw.new_node(Nodes.CombineXYZ, input_kwargs={'X': 1.57, 'Z': add}) - float_curve_6 = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': group_input.outputs["Value"]}) + float_curve_6 = nw.new_node(Nodes.FloatCurve, input_kwargs={'Value': group_input.outputs["Value1"]}) node_utils.assign_curve(float_curve_6.mapping.curves[0], [(0.0, pinna_contour[0]), (0.38, pinna_contour[1]), (0.55, pinna_contour[2]), (0.75, pinna_contour[3]), (0.9, pinna_contour[4]), (1.0, pinna_contour[5])]) # pinna leaf size w.r.t the fern age - map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs[3], 3: 6, 4: 8}) + map_range = nw.new_node(Nodes.MapRange, input_kwargs={'Value': group_input.outputs['Value3'], 3: 6, 4: 8}) multiply = nw.new_node(Nodes.VectorMath, input_kwargs={0: float_curve_6, 1: map_range.outputs["Result"]}, attrs={'operation': 'MULTIPLY'}) instance_on_points_2 = nw.new_node(Nodes.InstanceOnPoints, @@ -356,15 +356,15 @@ def nodegroup_pinnae_level2_stein(nw: NodeWrangler): # Code generated using version 2.4.3 of the node_transpiler group_input = nw.new_node(Nodes.GroupInput, - expose_input=[('NodeSocketFloat', 'Value', 0.5), - ('NodeSocketFloat', 'Value', 0.5), + expose_input=[('NodeSocketFloat', 'Value1', 0.5), + ('NodeSocketFloat', 'Value2', 0.5), ('NodeSocketGeometry', 'Mesh', None)]) mesh_to_curve_1 = nw.new_node(Nodes.MeshToCurve, input_kwargs={'Mesh': group_input.outputs["Mesh"]}) - multiply = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value"], 1: 0.1}, + multiply = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs["Value1"], 1: 0.1}, attrs={'operation': 'MULTIPLY'}) set_curve_radius_1 = nw.new_node(Nodes.SetCurveRadius, input_kwargs={'Curve': mesh_to_curve_1, 'Radius': multiply}) - multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs[2], 1: 0.5}, + multiply_1 = nw.new_node(Nodes.Math, input_kwargs={0: group_input.outputs['Value2'], 1: 0.5}, attrs={'operation': 'MULTIPLY'}) curve_circle_1 = nw.new_node(Nodes.CurveCircle, input_kwargs={'Radius': multiply_1, 'Resolution': 10}) curve_to_mesh_1 = nw.new_node(Nodes.CurveToMesh, diff --git a/worldgen/assets/trees/utils/geometrynodes.py b/worldgen/assets/trees/utils/geometrynodes.py index e22567786..47c543d21 100644 --- a/worldgen/assets/trees/utils/geometrynodes.py +++ b/worldgen/assets/trees/utils/geometrynodes.py @@ -58,9 +58,9 @@ def coll_distribute(nw, merge_dist=None): position = nw.new_node(Nodes.InputPosition) - transfer_attribute = nw.new_node(Nodes.TransferAttribute, - input_kwargs={'Source': mesh_to_points, 1: position}, - attrs={'data_type': 'FLOAT_VECTOR', 'mapping': 'NEAREST'}) + transfer_attribute = nw.new_node(Nodes.SampleNearestSurface, + input_kwargs={'Mesh': mesh_to_points, 'Value': position}, + attrs={'data_type': 'FLOAT_VECTOR'}) set_position = nw.new_node(Nodes.SetPosition, input_kwargs={'Geometry': curve_to_points.outputs["Points"], 'Position': transfer_attribute.outputs["Attribute"]}) diff --git a/worldgen/assets/utils/decorate.py b/worldgen/assets/utils/decorate.py index 2d8c372be..e5f974c67 100644 --- a/worldgen/assets/utils/decorate.py +++ b/worldgen/assets/utils/decorate.py @@ -173,8 +173,10 @@ def write_attribute(obj, fn, name, domain="POINT"): def geo_attribute(nw: NodeWrangler): geometry = nw.new_node(Nodes.GroupInput, expose_input=[('NodeSocketGeometry', 'Geometry', None)]) attr = surface.eval_argument(nw, fn, position=nw.new_node(Nodes.InputPosition)) - geometry = nw.new_node(Nodes.StoreNamedAttribute, [geometry, name], input_kwargs={'Value': attr}, - attrs={'domain': domain}) + geometry = nw.new_node( + Nodes.StoreNamedAttribute, + input_kwargs={'Geometry': geometry, 'Name': name, 'Value': attr}, + attrs={'domain': domain}) nw.new_node(Nodes.GroupOutput, input_kwargs={'Geometry': geometry}) surface.add_geomod(obj, geo_attribute, apply=True) diff --git a/worldgen/assets/utils/shortest_path.py b/worldgen/assets/utils/shortest_path.py index 4a9637777..520789fe5 100644 --- a/worldgen/assets/utils/shortest_path.py +++ b/worldgen/assets/utils/shortest_path.py @@ -36,8 +36,10 @@ def geo_shortest_path(nw: NodeWrangler, end_index, weight, trim_threshold=.1, of curve = nw.new_node(Nodes.EdgePathToCurve, [geometry, None, nw.new_node(Nodes.ShortestEdgePath, [ nw.compare('EQUAL', nw.new_node(Nodes.Index), 0), distance]).outputs[0]]) - curve = nw.new_node(Nodes.StoreNamedAttribute, [curve, 'tangent', nw.new_node(Nodes.CurveTangent)], - attrs={'data_type': 'FLOAT_VECTOR'}) + curve = nw.new_node( + Nodes.StoreNamedAttribute, + input_kwargs={'Geometry':curve, 'Name': 'tangent', 'Value': nw.new_node(Nodes.CurveTangent)}, + attrs={'data_type': 'FLOAT_VECTOR'}) geometry = nw.new_node(Nodes.MergeByDistance, [nw.curve2mesh(curve)]) geometry = nw.new_node(Nodes.SetPosition, [geometry, None, None, diff --git a/worldgen/generate.py b/worldgen/generate.py index bdaa5fa30..9295c3da1 100644 --- a/worldgen/generate.py +++ b/worldgen/generate.py @@ -416,7 +416,9 @@ def main(): parser.add_argument('-d', '--debug', action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO) parser.add_argument( '-v', '--verbose', action="store_const", dest="loglevel", const=logging.INFO) - args = parser.parse_args(sys.argv[sys.argv.index("--") + 1:]) + # handle case where running with blender --python -- + argvs = sys.argv[sys.argv.index('--')+1:] if '--' in sys.argv else sys.argv[1:] + args = parser.parse_args(argvs) extras = '[%(filename)s:%(lineno)d] ' if args.loglevel == logging.DEBUG else '' logging.basicConfig( diff --git a/worldgen/nodes/compatibility.py b/worldgen/nodes/compatibility.py new file mode 100644 index 000000000..374ecb44a --- /dev/null +++ b/worldgen/nodes/compatibility.py @@ -0,0 +1,63 @@ +import logging +from collections import OrderedDict + +from nodes.node_info import Nodes + +logger = logging.getLogger('node_wrangler') + +def map_dict_keys(d, m): + for m_from, m_to in m.items(): + if m_from not in d: + continue + if m_to in d: + raise ValueError(f'{m_from} would map to {m_to} but {d} already contains that key') + d[m_to] = d.pop(m_from) + return d + +def make_virtual_mixrgb(nw, orig_type, input_args, attrs, input_kwargs): + attrs['data_type'] = 'RGBA' + + key_mapping = OrderedDict({'Fac': 'Factor', 'Color1': 'A', 'Color2': 'B'}) + map_dict_keys(input_kwargs, key_mapping) + + # any previous uses of input_args are no longer valid, since the node has lots of hidden type-based sockets now + # we will convert any input_args present into input_kwargs instead + for k, a in zip(key_mapping.values(), input_args): + if k in input_kwargs: + raise ValueError(f'In {make_virtual_mixrgb}, encountered {orig_type} with conflicting {len(input_args)=} and {input_kwargs.keys()}') + input_kwargs[k] = a + input_args = [] + + return nw.new_node(node_type=Nodes.Mix, input_args=input_args, + attrs=attrs, input_kwargs=input_kwargs, compat_mode=False) + +def make_virtual_transfer_attribute(nw, orig_type, input_args, attrs, input_kwargs): + if attrs is None: + raise ValueError(f'{attrs=} in make_virtual_transfer_attribute, cannot infer correct node type mapping') + + if attrs['mode'] == 'NEAREST_FACE_INTERPOLATED': + mapped_type = Nodes.SampleNearestSurface + elif attrs['mode'] == 'NEAREST': + mapped_type = Nodes.SampleNearest + elif attrs['mode'] == 'INDEX': + mapped_type = Nodes.SampleIndex + else: + assert False + + logger.warning(f'Converting request for Nodes.TransferAttribute to {mapped_type}' + f'to ensure compatibility with bl3.3 code, but this is unsafe. Please update to avoid {Nodes.TransferAttribute}') + + map_dict_keys(input_kwargs, {'Source': 'Geometry', 'Mesh': 'Geometry'}) + return nw.new_node(node_type=mapped_type, input_args=input_args, + attrs=attrs, input_kwargs=input_kwargs, compat_mode=False) + +def compat_args_sample_curve(nw, orig_type, input_args, attrs, input_kwargs): + map_dict_keys(input_kwargs, {'Curve': 'Curves'}) + return nw.new_node(node_type=orig_type, input_args=input_args, + attrs=attrs, input_kwargs=input_kwargs, compat_mode=False) + +COMPATIBILITY_MAPPINGS = { + Nodes.MixRGB: make_virtual_mixrgb, + Nodes.TransferAttribute: make_virtual_transfer_attribute, + Nodes.SampleCurve: compat_args_sample_curve +} \ No newline at end of file diff --git a/worldgen/nodes/node_info.py b/worldgen/nodes/node_info.py index 39c075347..9acf49d92 100644 --- a/worldgen/nodes/node_info.py +++ b/worldgen/nodes/node_info.py @@ -22,9 +22,14 @@ class Nodes: Attribute = "ShaderNodeAttribute" CaptureAttribute = "GeometryNodeCaptureAttribute" AttributeStatistic = 'GeometryNodeAttributeStatistic' - TransferAttribute = "GeometryNodeAttributeTransfer" + TransferAttribute = "GeometryNodeAttributeTransfer" # removed in b3.4, still supported via compatibility.py DomainSize = 'GeometryNodeAttributeDomainSize' StoreNamedAttribute = "GeometryNodeStoreNamedAttribute" + NamedAttribute = 'GeometryNodeInputNamedAttribute' + SampleIndex = "GeometryNodeSampleIndex" + SampleNearest = "GeometryNodeSampleNearest" + SampleNearestSurface = "GeometryNodeSampleNearestSurface" + # Color Menu ColorRamp = "ShaderNodeValToRGB" @@ -38,6 +43,25 @@ class Nodes: CombineRGB = 'ShaderNodeCombineRGB' CombineColor = 'ShaderNodeCombineColor' + #bl3.5 additions + SeparateComponents = 'GeometryNodeSeparateComponents' + SetID = 'GeometryNodeSetID' + InterpolateCurves = 'GeometryNodeInterpolateCurves' + SampleUVSurface = 'GeometryNodeSampleUVSurface' + MeshIsland = 'GeometryNodeInputMeshIsland' + IsViewport = 'GeometryNodeIsViewport' + ImageInfo = 'GeometryNodeImageInfo' + CurveofPoint = 'GeometryNodeCurveOfPoint' + CurvesInfo = 'ShaderNodeHairInfo' + Radius = 'GeometryNodeInputRadius' + EvaluateonDomain = 'GeometryNodeFieldOnDomain' + BlurAttribute = 'GeometryNodeBlurAttribute' + EndpointSelection = 'GeometryNodeCurveEndpointSelection' + PointsofCurve = 'GeometryNodePointsOfCurve' + SetSplineResolution = 'GeometryNodeSetSplineResolution' + OffsetPointinCurve = 'GeometryNodeOffsetPointInCurve' + SplineResolution = 'GeometryNodeInputSplineResolution' + # Curve CurveToMesh = "GeometryNodeCurveToMesh" CurveToPoints = "GeometryNodeCurveToPoints" @@ -102,7 +126,6 @@ class Nodes: Integer = 'FunctionNodeInputInt' LightPath = 'ShaderNodeLightPath' ShortestEdgePath = 'GeometryNodeInputShortestEdgePaths' - NamedAttribute = 'GeometryNodeInputNamedAttribute' # Instances RealizeInstances = "GeometryNodeRealizeInstances" @@ -282,7 +305,7 @@ class Nodes: Nodes.RandomValue: ['data_type'], Nodes.Switch: ['input_type'], - Nodes.TransferAttribute: ['data_type', 'mapping'], + Nodes.TransferAttribute: ['data_type', 'mapping'], Nodes.SeparateGeometry: ['domain'], Nodes.MergeByDistance: ['mode'], @@ -366,7 +389,7 @@ class Nodes: bpy.types.CompositorNodeGroup: Nodes.GroupOutput, } -DATATYPE_DIMS = {'FLOAT': 1, 'INT': 1, 'FLOAT_VECTOR': 3, 'FLOAT_COLOR': 4, 'BOOLEAN': 1, } +DATATYPE_DIMS = {'FLOAT': 1, 'INT': 1, 'FLOAT_VECTOR': 3, 'FLOAT2': 2, 'FLOAT_COLOR': 4, 'BOOLEAN': 1, } DATATYPE_FIELDS = { 'FLOAT': 'value', 'INT': 'value', diff --git a/worldgen/nodes/node_wrangler.py b/worldgen/nodes/node_wrangler.py index 18a76279f..3331d75db 100644 --- a/worldgen/nodes/node_wrangler.py +++ b/worldgen/nodes/node_wrangler.py @@ -22,6 +22,7 @@ from util.random import random_vector3 from nodes.node_info import Nodes, NODE_ATTRS_AVAILABLE from nodes import node_info +from nodes.compatibility import COMPATIBILITY_MAPPINGS logger = logging.getLogger(__name__) @@ -155,13 +156,24 @@ def new_value(self, v, label=None): node.outputs[0].default_value = v return node - def new_node(self, node_type, input_args=None, attrs=None, input_kwargs=None, label=None, - expose_input=None): + def new_node( + self, node_type, + input_args=None, attrs=None, input_kwargs=None, label=None, + expose_input=None, compat_mode=True + ): if input_args is None: input_args = [] if input_kwargs is None: input_kwargs = {} + if attrs is None: + attrs = {} + + compat_map = COMPATIBILITY_MAPPINGS.get(node_type) + if compat_mode and compat_map is not None: + logger.debug(f'Using {compat_map.__name__=} for {node_type=}') + return compat_map(self, node_type, input_args, attrs, input_kwargs) + node = self._make_node(node_type) if label is not None: @@ -212,6 +224,10 @@ def new_node(self, node_type, input_args=None, attrs=None, input_kwargs=None, la self.connect_input(input_socket, input_item) if expose_input is not None: + names = [v[1] for v in expose_input] + uniq, counts = np.unique(names, return_counts=True) + if (counts > 1).any(): + raise ValueError(f'expose_input with {names} features duplicate entries. in bl3.5 this is invalid.') for inp in expose_input: nodeclass, name, val = inp self.expose_input(name, val=val, dtype=nodeclass) diff --git a/worldgen/nodes/nodegroups/transfer_attributes.py b/worldgen/nodes/nodegroups/transfer_attributes.py index 205d2a495..3a34a32a5 100644 --- a/worldgen/nodes/nodegroups/transfer_attributes.py +++ b/worldgen/nodes/nodegroups/transfer_attributes.py @@ -52,7 +52,7 @@ def transfer_all(source, target, attributes=None, uvs=False): assert target.type == 'MESH' if attributes is None: - attributes = [a.name for a in source.data.attributes if a.data_type in node_info.DATATYPE_DIMS] + attributes = [a.name for a in source.data.attributes if not butil.blender_internal_attr(a)] if len(source.data.uv_layers) == 0: uvs = False @@ -98,14 +98,15 @@ def transfer_att_node(nw, source, target, attribute_to_transfer_list=[]): group_output_sockets = {'Geometry': object_info.outputs["Geometry"]} for att_name, att_type in attribute_to_transfer_list: - transfer_attribute = nw.new_node(Nodes.TransferAttribute, - attrs={'data_type': att_type}, - input_kwargs={ - 'Source': group_input.outputs["Geometry"], - 'Attribute': group_input.outputs[att_name], - 'Source Position': position - }) - - group_output_sockets[att_name] = (transfer_attribute, 'Attribute') + transfer_attribute = nw.new_node( + Nodes.SampleNearestSurface, + attrs={'data_type': att_type}, + input_kwargs={ + 'Mesh': group_input.outputs["Geometry"], + 'Value': group_input.outputs[att_name], + 'Sample Position': position + }) + + group_output_sockets[att_name] = (transfer_attribute, 'Value') group_output = nw.new_node(Nodes.GroupOutput, input_kwargs=group_output_sockets) diff --git a/worldgen/surfaces/templates/bark.py b/worldgen/surfaces/templates/bark.py index 2f8a03d0e..d4f3e3584 100644 --- a/worldgen/surfaces/templates/bark.py +++ b/worldgen/surfaces/templates/bark.py @@ -57,7 +57,7 @@ def shader_bark(nw, rand=False, **input_kwargs): input_kwargs={'Fac': colorramp_1.outputs["Color"], 'Color1': colorramp.outputs["Color"], 'Color2': (0.0897, 0.052, 0.0149, 1.0)}) if rand: for i in range(3): - mix_1.inputs["Color2"].default_value[i] = (colorramp.color_ramp.elements[0].color[i] + colorramp.color_ramp.elements[1].color[i]) / 2 + mix_1.inputs[7].default_value[i] = (colorramp.color_ramp.elements[0].color[i] + colorramp.color_ramp.elements[1].color[i]) / 2 colorramp_2 = nw.new_node(Nodes.ColorRamp, input_kwargs={'Fac': noise_texture.outputs["Fac"]}) diff --git a/worldgen/surfaces/templates/face_size_visualizer.py b/worldgen/surfaces/templates/face_size_visualizer.py index 417963a33..1a947051d 100644 --- a/worldgen/surfaces/templates/face_size_visualizer.py +++ b/worldgen/surfaces/templates/face_size_visualizer.py @@ -34,7 +34,7 @@ def geo_face_colors(nw: NodeWrangler): attrs={'data_type': 'FLOAT_VECTOR'}) store_named_attribute = nw.new_node(Nodes.StoreNamedAttribute, - input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Name': 'col', 2: random_value.outputs["Value"]}, + input_kwargs={'Geometry': group_input.outputs["Geometry"], 'Name': 'col', "Value": random_value.outputs["Value"]}, attrs={'data_type': 'FLOAT_VECTOR', 'domain': 'FACE'}) group_output = nw.new_node(Nodes.GroupOutput, diff --git a/worldgen/surfaces/templates/fish_eye_shader.py b/worldgen/surfaces/templates/fish_eye_shader.py index bab9fa770..c529ddb5e 100644 --- a/worldgen/surfaces/templates/fish_eye_shader.py +++ b/worldgen/surfaces/templates/fish_eye_shader.py @@ -190,7 +190,7 @@ def shader_eyeball_fish(nw: NodeWrangler): mix_6 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': colorramp_3.outputs["Color"], 'Color1': (0.7384, 0.5239, 0.2703, 1.0000), 'Color2': colorramp_4.outputs["Color"]}) - sample_color(mix_6.inputs["Color1"].default_value) + sample_color(mix_6.inputs[6].default_value) mix_7 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': colorramp_1.outputs["Color"], 'Color1': mix_6, 'Color2': (0.0000, 0.0000, 0.0000, 1.0000)}) diff --git a/worldgen/surfaces/templates/fishbody.py b/worldgen/surfaces/templates/fishbody.py index 7a761d262..c83050805 100644 --- a/worldgen/surfaces/templates/fishbody.py +++ b/worldgen/surfaces/templates/fishbody.py @@ -567,7 +567,7 @@ def shader_fish_body_regular(nw: NodeWrangler, rand=True, **input_kwargs): mix_12 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': colorramp_15.outputs["Color"], 'Color1': (0.0119, 0.0078, 0.0086, 1.0), 'Color2': mix_4}) if rand: - sample_color(mix_12.inputs['Color1'].default_value, keep_sum=True) + sample_color(mix_12.inputs[6].default_value, keep_sum=True) principled_bsdf_1 = nw.new_node(Nodes.PrincipledBSDF, input_kwargs={'Base Color': mix_12, 'Subsurface Radius': (0.36, 0.46, 0.6), 'Subsurface Color': (1.0, 0.9405, 0.7747, 1.0), 'Metallic': 0.8, 'Specular': .9, 'Roughness': 0.3, 'IOR': 1.69}, diff --git a/worldgen/surfaces/templates/mountain.py b/worldgen/surfaces/templates/mountain.py index cbfd7f5ec..0b53f71f6 100644 --- a/worldgen/surfaces/templates/mountain.py +++ b/worldgen/surfaces/templates/mountain.py @@ -262,8 +262,7 @@ def shader_MOUNTAIN( # ambient occlusion amb_occl = nw.new_node('ShaderNodeAmbientOcclusion', []) - ramp = nw.new_node('ShaderNodeMixRGB', [amb_occl, None, ramp]) - ramp.inputs[1].default_value = (0.0, 0.0, 0.0, 1.0) + ramp = nw.new_node('ShaderNodeMixRGB', [amb_occl, (0.0, 0.0, 0.0, 1.0), ramp]) else: if color is None: diff --git a/worldgen/surfaces/templates/spot_sparse_attr.py b/worldgen/surfaces/templates/spot_sparse_attr.py index a44a86c14..5f981bce6 100644 --- a/worldgen/surfaces/templates/spot_sparse_attr.py +++ b/worldgen/surfaces/templates/spot_sparse_attr.py @@ -56,7 +56,7 @@ def shader_spots_sparse_attr(nw: NodeWrangler, rand=True, **input_kwargs): 'Color2': colorramp_3.outputs["Color"] }) if rand: - mix.inputs['Color1'].default_value = getcolor() + mix.inputs[6].default_value = getcolor() principled_bsdf = nw.new_node(Nodes.PrincipledBSDF, input_kwargs={'Base Color': mix, 'Specular': 0.0, 'Roughness': colorramp.outputs["Color"]}) diff --git a/worldgen/surfaces/templates/three_color_spots.py b/worldgen/surfaces/templates/three_color_spots.py index 69090df88..c1037d376 100644 --- a/worldgen/surfaces/templates/three_color_spots.py +++ b/worldgen/surfaces/templates/three_color_spots.py @@ -160,11 +160,11 @@ def shader_spot(nw, rand=True, **input_kwargs): color1 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': mix_1, 'Color1': (1.0, 0.0223, 0.0, 1.0), 'Color2': rgb}) - sample_color(color1.inputs['Color1'].default_value) + sample_color(color1.inputs[6].default_value) color2 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': mix_4, 'Color1': (0.0021, 0.0021, 0.0144, 1.0), 'Color2': rgb}) - sample_color(color2.inputs['Color1'].default_value) + sample_color(color2.inputs[6].default_value) mix_6 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': math, 'Color1': color1, 'Color2': color2}) diff --git a/worldgen/surfaces/templates/two_color_spots.py b/worldgen/surfaces/templates/two_color_spots.py index 73aecf34e..b9efa6362 100644 --- a/worldgen/surfaces/templates/two_color_spots.py +++ b/worldgen/surfaces/templates/two_color_spots.py @@ -21,8 +21,8 @@ def shader_two_color_spots(nw, rand=True, **input_kwargs): mix_2 = nw.new_node(Nodes.MixRGB, input_kwargs={'Fac': attribute.outputs["Fac"], 'Color1': (1.0, 0.2397, 0.0028, 1.0), 'Color2': (0.4915, 0.4636, 0.3855, 1.0)}) if rand: - sample_color(mix_2.inputs["Color1"].default_value) - sample_color(mix_2.inputs["Color2"].default_value) + sample_color(mix_2.inputs[6].default_value) + sample_color(mix_2.inputs[7].default_value) principled_bsdf = nw.new_node(Nodes.PrincipledBSDF, input_kwargs={'Base Color': mix_2}, diff --git a/worldgen/terrain/utils/mesh.py b/worldgen/terrain/utils/mesh.py index 33aea4001..170df196f 100644 --- a/worldgen/terrain/utils/mesh.py +++ b/worldgen/terrain/utils/mesh.py @@ -25,9 +25,11 @@ class NormalMode: AngleWeighted = "angle_weighted" -def object_to_vertex_attributes(obj, specified=None): +def object_to_vertex_attributes(obj, specified=None, skip_internal=True): vertex_attributes = {} for attr in obj.data.attributes.keys(): + if skip_internal and butil.blender_internal_attr(attr): + continue if ((specified is None) or (specified is not None and attr in specified)) and obj.data.attributes[attr].domain == "POINT": type_key = obj.data.attributes[attr].data_type tmp = np.zeros(len(obj.data.vertices) * ATTRTYPE_DIMS[type_key], dtype=np.float32) diff --git a/worldgen/tools/job_funcs.py b/worldgen/tools/job_funcs.py index fbcfd6c5b..a3911d16c 100644 --- a/worldgen/tools/job_funcs.py +++ b/worldgen/tools/job_funcs.py @@ -44,11 +44,10 @@ def get_cmd( cmd = '' if process_niceness is not None: cmd += f'nice -n {process_niceness} ' - cmd += f'{BLENDER_PATH} --background -y -noaudio --python {driver_script} ' - + cmd += f'python {driver_script} -- '' if blender_thread_limit is not None: cmd += f'--threads {blender_thread_limit} ' - + cmd += '-- ' if input_folder is not None: diff --git a/worldgen/tools/util/submitit_emulator.py b/worldgen/tools/util/submitit_emulator.py index d5153aa9a..11ddf6513 100644 --- a/worldgen/tools/util/submitit_emulator.py +++ b/worldgen/tools/util/submitit_emulator.py @@ -249,7 +249,7 @@ def get_all_processes(): if test == 'render': - random_command = "../blender/blender --background -noaudio --python generate.py -- --seed 56823 --task coarse -p main.output_folder=outputs/test2 move_camera.stereo_baseline=0.15 LOG_DIR=logs" + random_command = "python generate.py -- --seed 56823 --task coarse -p main.output_folder=outputs/test2 move_camera.stereo_baseline=0.15 LOG_DIR=logs" executor = ScheduledLocalExecutor(folder="test_log") executor.update_parameters(gpus=1) diff --git a/worldgen/util/blender.py b/worldgen/util/blender.py index aefc212da..7b1bb504b 100644 --- a/worldgen/util/blender.py +++ b/worldgen/util/blender.py @@ -557,6 +557,10 @@ def join_objects(objs, check_attributes=False): bpy.ops.object.join() return bpy.context.active_object +def clear_mesh(obj): + with ViewportMode(obj, mode='EDIT'): + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.delete(type='VERT') def apply_modifiers(obj, mod=None, quiet=True): if mod is None: @@ -569,7 +573,15 @@ def apply_modifiers(obj, mod=None, quiet=True): con = Suppress() if quiet else nullcontext() with SelectObjects(obj), con: for m in mod: - bpy.ops.object.modifier_apply(modifier=m.name) + try: + bpy.ops.object.modifier_apply(modifier=m.name) + except RuntimeError as e: + if m.type == 'NODES': + logging.warn(f'apply_modifers on {obj.name=} {m.name=} raised {e}, ignoring and returning empty mesh for pre-3.5 compatibility reasons') + bpy.ops.object.modifier_remove(modifier=m.name) + clear_mesh(obj) + else: + raise e def recalc_normals(obj, inside=False): @@ -694,6 +706,15 @@ def object_to_trimesh(obj): mesh.vertex_attributes.update(vertex_attributes) return mesh +def blender_internal_attr(a): + if hasattr(a, 'name'): + a = a.name + if a.startswith('.'): + return True + if a in ['material_index', 'uv_map', 'UVMap']: + return True + return False + def merge_by_distance(obj, face_size): with SelectObjects(obj), ViewportMode(obj, mode='EDIT'), Suppress(): bpy.ops.mesh.select_all(action='SELECT')