I am trying to scatter a textured object with Geometry Nodes. After applying Geometry Nodes, my objects lose the texture coordinates.
Is there any way to get UV maps on these scattered objects?
Blender Stack Exchange is a question and answer site for people who use Blender to create 3D graphics, animations, or games. It only takes a minute to sign up.
Sign up to join this communityI am trying to scatter a textured object with Geometry Nodes. After applying Geometry Nodes, my objects lose the texture coordinates.
Is there any way to get UV maps on these scattered objects?
With Blender 3.1.2+ the bug has been fixed.
The UV maps created in your objects will be processed correctly in the shader if they were previously instantiated with Geometry Nodes.
However, as soon as you use the Realize Instances
node in the geometry nodes, you have to reattach the UV map with the Attribute
node in the shader.
This is what worked for me:
create a custom material on Instance, use Attribute for UV with a custom string 'UVOutput'
create a custom geonode on Instance, use its UV map as input and output to 'UVOutput' -- this is to convert uv data to attribute data format in Blender
Make sure UV input string is consistent as the UV setting of the Instance object (this gets confusing if you have multiple objects)
All is explained in the graph, hope this is helpful
Using a similar technique in principle to this:
Assign vertex group in Geometry Nodes (v3.3)
You can split edges, save your vertex positions, and then move them to their UV coordinates:
Then add a UV Project modifier:
Set the chosen camera to orthographic, projection scale to 1, position it at $(0.5, 0.5, 0)$ coordinates. Finally, add another geonodes setup restoring the positions and merging split edges:
It's worth to note if the original geometry had some split edges, this technique loses that information - I have an idea how one could restore that information, but it probably deserves a new question "How to split edges and then merge only those that were split?".
I found alternative dirty solution to create UV on realized instances. Its based on splitting object by normals what can be used as a seam. Hope its not magically working only for me :)
sources: https://www.youtube.com/watch?v=02XNGOVpSV4&t=445s&ab_channel=Entagma https://www.youtube.com/watch?v=wVhThuzRDIk&t=740s&ab_channel=JohnnyMatthews
I think I have a really good solution, expanding from @totegamma's response in this POST
import bpy
# Get the active object
obj = bpy.context.active_object
# Duplicate the object (USING COPY SO TO NOT AFFECT ORIGINAL MODEL)
duplicate_obj = obj.copy()
duplicate_obj.data = obj.data.copy()
bpy.context.collection.objects.link(duplicate_obj)
# Set the context
bpy.context.view_layer.objects.active = duplicate_obj
# Apply the modifier
with bpy.context.temp_override(object=duplicate_obj):
bpy.ops.object.modifier_apply(modifier=duplicate_obj.modifiers[0].name)
# Add UV Slot
bpy.ops.mesh.uv_texture_add()
# Pass Attributes to Layers (totegamma)
attrUV = duplicate_obj.data.attributes["UVMap"].data
targetObjUV = duplicate_obj.data.uv_layers[0].data
for i, elem in enumerate(targetObjUV):
elem.uv = attrUV[i].vector
If anyone needs clarification let me know, but this should:
*Apply FIRST modifier (you can edit "duplicate_obj.modifiers[0]" to be 1, 2, etc)
*Add UVMap Slot
*Copy UV data from attributes to the actual UV Map