Page MenuHome

UDIM: Add support for packing inside .blend files
ClosedPublic

Authored by Jesse Yurkovich (deadpin) on Mar 21 2022, 5:44 AM.

Details

Summary

This completes support for tiled texture packing on the Blender / Cycles
side of things.

Most of these changes fall into one of three categories:

  • Updating image handling code to pack/unpack tiled and multi-view images[1]
  • Updating Cycles to handle tiled textures through BlenderImageLoader
  • Updating OSL to properly handle textures with multiple slots

For OSL, the texture slot to tile mapping strategy is lifted directly from the already
existing Cycles CPU implementation[2].

Beyond the unit tests, a good way to test this is to use the
"Monster - UDIM" demo from https://www.blender.org/download/demo-files/

Open the file, pack every texture, re-save the file elsewhere and
then re-open that new file. Everything should work when rendering with
Eevee and Cycles CPU / OSL / GPU. Additionally, try unpacking the files
to re-save them locally.


[1] This fixes the unreported bug that multi-view images are not
packable since 2.79.

[2] The existing implementation can be found in the following 2 locations:
https://developer.blender.org/diffusion/B/browse/master/intern/cycles/scene/shader_nodes.cpp$405
https://developer.blender.org/diffusion/B/browse/master/intern/cycles/kernel/svm/image.h$66

Diff Detail

Repository
rB Blender
Branch
udim-pack-part2 (branched from master)
Build Status
Buildable 21131
Build 21131: arc lint + arc unit

Event Timeline

Jesse Yurkovich (deadpin) requested review of this revision.Mar 21 2022, 5:44 AM
Jesse Yurkovich (deadpin) created this revision.

Looks great overall, I left some inline comments regarding potential issues and cleanups.

I think it's best if you merge D14327 first and then rebase this on top of the result.

intern/cycles/kernel/osl/services.cpp
1310

Can we avoid this duplication? Maybe a fallthrough (first the SVM_TILES case determines the ID, then falls through to SVM which does the lookup and this part)? Or maybe merge SVM and SVM_TILES together and just check svm_slots[0].z == -1 for the un-tiled case?

1322

This code seems to fall back to the first tile if the correct one is missing, is that intentional?

intern/cycles/kernel/osl/services.h
50

We probably still want to initialize svm_slots to some form of invalid value (e.g. make_int4(-1, -1, -1, -1)) since the code below accesses svm_slots[0] without boundary checking.

Also, I think we want to keep the option of passing in a single slot for simple cases, so maybe one constructor that takes an int svm_slot = 1 and initializes svm_slots from that, and one that directly takes a vector<int4>?

intern/cycles/scene/image.cpp
159
intern/cycles/scene/image.h
150

Nitpick: I'd prefer if this just returns the slots instead of filling the reference.

176

Hm, I'm not really a fan of creating handle outside and then repeatedly calling add_image. Maybe we could have an overload of add_image that accepts a vector<ImageLoader*> instead?

intern/cycles/scene/osl.cpp
1221–1225

Since the type is only determined by the tile count, it probably makes more sense to just check slots[0].z instead of adding another type.

1223–1225

Combining the comments above, this can be simplified.

intern/cycles/scene/osl.h
150

Maybe rename to parameter_texture_svm to make it clearer what the difference is?

source/blender/blenkernel/intern/image.cc
1262

Above, in the !ibuf case, ok gets set to false but the code now continues instead of exiting as before. I assume that's intentional. However, if ok == false, the RHS of && is skipped, so we never call image_memorypack_imbuf anyways. Probably just swap the order?

1267–1268
4864

Why this change?

source/blender/blenloader/intern/versioning_300.c
2435–2436
source/blender/makesdna/DNA_image_types.h
69

I think we also want to copy those in copy_image_packedfiles?

  • Rebase since part1 was checked in
  • For OSL use the missing texture color if tile isn't found instead of the color from first tile
  • Changed BKE_image_memorypack back to use break instead of continue
  • Refactored ImageHandle/ImageManager related code per feedback

Very much appreciate the review. Agree with the comments around ImageHandle/ImageManager so I've refactored those per your feedback. Also collapsed SVM_TILES back inside the SVM codepath.

intern/cycles/kernel/osl/services.cpp
1333–1336

Based on the code inside svm_image_texture, I've added a similar check against -1 here in order to return the missing texture color.

  • Fix the File->External pack/unpack operators
Jesse Yurkovich (deadpin) marked 13 inline comments as done.Apr 2 2022, 7:44 AM
Lukas Stockner (lukasstockner97) requested changes to this revision.Apr 3 2022, 1:42 AM

The code looks good now, thanks!

However, I just played around with the feature a bit and I think I found some issues:

  1. When I create a tiled image, add a few tiles, save the file, close Blender and then open the .blend file again, the tiles are empty.
  2. When I create a tiled image, add a few tiles, paint on them, save the file and close Blender, the "unsaved" dialog shows an error saying that the image can't be saved due to an invalid path
  3. When I do 2., cancel the closing and manually run Image->Pack, I can then save, close and reopen just fine, with the tiles still being there
  4. When I open the file from 3. and run File->External Data->Unpack Resources, only the first tile gets unpacked
  5. When I save, close and reopen after 4., the tiles are empty, even the first one that was unpacked.
This revision now requires changes to proceed.Apr 3 2022, 1:42 AM
  • Merge
  • Fix unpacking to different directory and ensure textures are packed if modified
  • Fix issues packing/unpacking modified tiles without a filename
  1. As mentioned, I'd like to address this one separately
  2. Should be addressed by actually allowing a memory pack to occur in this instance
  1. 5. I believe these are addressed now as I managed to find the exact sequence of steps necessary (auto-generated temporary file name didn't contain tile number) and then a subsequent empty tile situation if the unpack went to a different location than the originals after a reload.

LGTM now, the sequence above works now except for, as mentioned, the case where the tiled image is untouched after creating it.

However, modifying one tile is enough to pack all of them, and even if they are completely untouched, at least the tile layout is preserved, so no actual work will be lost.

To solve this, I think it makes a lot of sense to immediately tag the ImBuf as modified as soon as it gets filled, since we can't reproduce the data like we can for IMA_SRC_GENERATED - so, arguably, it's not even a trick but the right thing to do, since it genuinely contains unsaved data.

This revision is now accepted and ready to land.Apr 8 2022, 2:41 AM

Update: The issue where tiles lose their content if they weren't touched after generation should be covered by T97251.

June Liu (Tac) added a subscriber: June Liu (Tac).EditedMay 6 2022, 6:50 AM

Hello,sorry to disturb u. I am a new developer and I'm glad to see this UDIM pack fix. Could u please tell me how can I download your code and test it? Thank u very much.

  • Just updating to master - no changes beyond versioning shuffle
  • Versioning change now that 3.3 is here
Sergey Sharybin (sergey) requested changes to this revision.May 9 2022, 11:55 AM
Sergey Sharybin (sergey) added inline comments.
source/blender/blenkernel/intern/image.cc
1327–1328

I'd say the BKE_packedfile_new_from_memory should return a packed file in its consistent state. The means, that the view and tile_number are to be ensured to be valid in the BKE_packedfile_new_from_memory.

Note that there are more usages of BKE_packedfile_new_from_memory and those do not do anything with the view and tile_number are left unchanged.

source/blender/editors/space_image/image_ops.c
2313

Why tiled image can not be packed if it has filepath?

Why image_is_memory_packable checks are different from similar (inlined!) checks in image.cc w.r.t whether image can be packed or not?

source/blender/makesdna/DNA_image_types.h
68–69

There is no documentation what those are, whos responsibility it is to set to a proper values, and the initialization of these fields is used inconsistently.

This revision now requires changes to proceed.May 9 2022, 11:55 AM
  • Add some documentation

Left some inline comments to your feedback.

BTW, you had a previous review comment a long while back about #defining the 1001 number. That's on my list to do eventually…

source/blender/blenkernel/intern/image.cc
1327–1328

The 'view' and 'tile_number' fields are on ImagePackedFile, not PackedFile so setting them in that method isn't possible. I double-checked that these fields are set everywhere ImagePackedFile is created though.

source/blender/editors/space_image/image_ops.c
2313

Good question, but I can only infer the true intent of this function myself. It _seems_ like this function prefers to Save to Disk if possible rather than doing a memory pack for dirty images. It has a check against IMA_SRC_GENERATED which already made it different than other code, so I made an equivalent check for tiled textures which is what's there now.

The scenario that triggers this code path is: Create an image (tiled or normal), paint on it, Save the .blend, Quit --> Select "Save" for the modified images. If the images had a filepath, they would be saved to disk at this step. If not, they will be memory packed.

source/blender/blenkernel/intern/image.cc
1327–1328

Ah, indeed. Sorry, misread the code :(

source/blender/editors/space_image/image_ops.c
2313

Thanks for clarifying the scenario.

However, I am still confused why tiled images are handled differently here from "normal" images? Is it because it is not possible to have "normal" image without a file path, but it is possible to have tiled image without a file path? If the latter is correct it would save a lot of brain cycles if we put the information into a comment around the check.

source/blender/editors/space_image/image_ops.c
2313

Right, a "normal" image will transition from IMA_SRC_GENERATED to IMA_SRC_FILE once it's saved by the user (or was loaded from disk to begin with) which implies it has a file path at that point. Tiled images are immediately IMA_SRC_TILED upon creation so we can't use the source alone to determine if we should pack in this case or not.

Perhaps this function needs a better name. It's not strictly about determining if packing to memory is possible. It's more like bool image_can_pack_during_save_all(...) as that's all it's used for. Would that rename help (in addition to a comment maybe)?

source/blender/editors/space_image/image_ops.c
2313

Would that rename help (in addition to a comment maybe)?

Absolutely! :)

  • Better function name and comments
This revision is now accepted and ready to land.May 10 2022, 11:48 AM