Regression: Array Caps broken on empty mesh in 3.5. #107353

Closed
opened 2023-04-26 00:50:24 +02:00 by Will · 14 comments

Blender Version
Broken: 3.5.0
Worked: 3.4

Caused by 8b2556e8d8

Short description of error

In (all?) previous versions of Blender, an Array modifier with a Start Cap or End Cap would show its cap regardless of the geometry (or lack thereof) in the base mesh:

EmptyArrayCap_336.png

In Blender 3.5.0, the Cap is not shown if the base mesh is empty:

EmptyArrayCap_350.png

Exact steps for others to reproduce the error

  1. Download the attached Blender file.
  2. Open it in an affected version of Blender.
**Blender Version** Broken: 3.5.0 Worked: 3.4 Caused by 8b2556e8d895c54012526b3eaa66eaf96cb7721c **Short description of error** In (all?) previous versions of Blender, an Array modifier with a Start Cap or End Cap would show its cap regardless of the geometry (or lack thereof) in the base mesh: ![EmptyArrayCap_336.png](/attachments/b4714942-9b6a-415a-83cf-c542e6b8722d) In Blender 3.5.0, the Cap is not shown if the base mesh is empty: ![EmptyArrayCap_350.png](/attachments/4d9e1fcf-3e79-4ff7-807a-ada187452f4f) **Exact steps for others to reproduce the error** 1. Download the attached Blender file. 2. Open it in an affected version of Blender.
Will added the
Priority
Normal
Type
Report
Status
Needs Triage
labels 2023-04-26 00:50:25 +02:00
Richard Antalik added
Module
Modeling
Status
Confirmed
Interest
Modifiers
and removed
Status
Needs Triage
labels 2023-04-26 02:17:03 +02:00

Will bisect tomorrow,

Git log showed 918cf6cd77 as something vaguely related.

Will bisect tomorrow, Git log showed 918cf6cd777a697f1c15043ecb5ec5b8f91765d5 as something vaguely related.
Richard Antalik changed title from Array Caps broken on empty mesh in 3.5. to Regression:Array Caps broken on empty mesh in 3.5. 2023-04-26 02:24:09 +02:00
Richard Antalik added
Priority
High
and removed
Priority
Normal
labels 2023-04-26 02:24:17 +02:00
Iliya Katushenock changed title from Regression:Array Caps broken on empty mesh in 3.5. to Regression: Array Caps broken on empty mesh in 3.5. 2023-04-26 07:20:32 +02:00
Member

bisecting...

bisecting...
Member

Caused by 8b2556e8d8

From the commit message it is not entirely clear under which circumstances the crash would happen (@mont29 : could you clarify? -- it certainly did not always happen).

And while somewhat intentional, it is also not clear if we want to support caps on empty meshes in the future then?

@WCN : maybe it helps to elaborate on the usecase a bit?

(will still leave it at High prio since technically, this is a recent regression)

Caused by 8b2556e8d895c54012526b3eaa66eaf96cb7721c From the commit message it is not entirely clear under which circumstances the crash would happen (@mont29 : could you clarify? -- it certainly did not always happen). And while somewhat intentional, it is also not clear if we want to support caps on empty meshes in the future then? @WCN : maybe it helps to elaborate on the usecase a bit? (will still leave it at High prio since technically, this is a recent regression)
Author

@WCN : maybe it helps to elaborate on the usecase a bit?

Prior to the introduction of Geometry Nodes, there was no official way to copy evaluated geometry from one object to another.

As such, I used an Array modifier on an empty mesh with a Cap for that purpose.

This was extremely useful for two reasons:

  • It allows a procedural (post-modifier-stack) base geometry to be used in multiple places in different ways. For example, you could have a solid character model that has armature animations, and then using an empty-mesh Array Cap plus a positive Displace modifier, you can create a separate dynamic, automatically updating halo around the post-deformation character model. Or you could have an object representing a 3D printing design with lots of modifier-defined geometry, and using an empty-mesh Array Cap plus negative Displace modifier and Remesh, you can automatically generate an empty cavity inside the model to save material. The possibilities were legitimately endless.

  • It allows the explicit segmentation of the dependency graph at the point of the Array modifier. For example, suppose you have a complex organic base sculpt that must be broken up into a lot of hard-surface sections (like the limbs of a robot or doll). Each one of those section must be generated using a Boolean Intersect of their region with the base sculpt, and each section must also have half a dozen additional Boolean Union and Difference operations performed on it in order to shape the cut surface. On top of that, you also need to create several modified dynamic copies of the base sculpt (like above) in order to generate supporting internal and external geometry. So in all you start off with one base model, and then using empty-mesh Array Caps, you create dozens of procedural copies, one for each section, a couple others for supporting geometry, and maybe even a whole separate version where you apply some modifiers to the base sculpt before splitting it into sections. And lastly, you also want to take the final evaluated geometry of the sections, after all the expensive Boolean modifiers have been calculated, and you want to parent them to an armature in order to do some articulated animation. — Using Array Caps on empty meshes to create dynamic copies of evaluated geometry not only allows all this to be done in a procedural way, but does so with explicit depsgraph stop points— without re-computing hundreds of Boolean modifiers for every frame of the final animation (or every edit made to just one component).

I am aware that this was not exactly the intended use of the Array modifier. But it is still within the documented/expected and established behaviour.

Many projects that I made using this technique simply would not have been possible otherwise; The scene complexity and computational complexity would have both quickly grown quadratically to unmanageable levels if I had to create full copies of every object and keep them in a single modifier stack, and the workflow complexity would have been prohibitively more cumbersome if I had had to apply all the modifiers (and lost the ability to organically sculpt the base mesh) at every step in order to keep the depsgraph simple. Using Array Caps on empty meshes to create realized instances of modified geometry allowed me to keep the scene and computational complexity mostly linear, while also keeping a highly efficient procedural workflow.

I currently have many project files— Most of my project files from the last several years, I'd say, including some that are still ongoing— That make use of this technique in one way or another. I've been meaning to switch to a Geometry Nodes-based replacement in future use, but this change still breaks the existing files.


FWIW, Personally I can't specifically remember ever running into a crash as a result of an Array modifier on an empty mesh, despite using them a lot. Without the cause of the crash being documented, I also have questions about whether commit 8b2556e8d8 was tested thoroughly enough to actually fix it— For example, supposing it was caused by zero bounding box size or something like that, what happens now if you have a single vertex?

Personal opinion: Unreported (and currently unreproducible) crash in extreme corner case is not worth breaking existing files/behaviour.

> @WCN : maybe it helps to elaborate on the usecase a bit? Prior to the introduction of Geometry Nodes, there was no official way to copy evaluated geometry from one object to another. As such, I used an Array modifier on an empty mesh with a Cap for that purpose. This was extremely useful for two reasons: - It allows a procedural (post-modifier-stack) base geometry to be used in multiple places in different ways. For example, you could have a solid character model that has armature animations, and then using an empty-mesh Array Cap plus a positive Displace modifier, you can create a separate dynamic, automatically updating halo around the post-deformation character model. Or you could have an object representing a 3D printing design with lots of modifier-defined geometry, and using an empty-mesh Array Cap plus negative Displace modifier and Remesh, you can automatically generate an empty cavity inside the model to save material. The possibilities were legitimately endless. - It allows the explicit segmentation of the dependency graph at the point of the Array modifier. For example, suppose you have a complex organic base sculpt that must be broken up into a lot of hard-surface sections (like the limbs of a robot or doll). Each one of those section must be generated using a Boolean Intersect of their region with the base sculpt, and each section must also have half a dozen additional Boolean Union and Difference operations performed on it in order to shape the cut surface. On top of that, you also need to create several modified dynamic copies of the base sculpt (like above) in order to generate supporting internal and external geometry. So in all you start off with one base model, and then using empty-mesh Array Caps, you create dozens of procedural copies, one for each section, a couple others for supporting geometry, and maybe even a whole separate version where you apply some modifiers to the base sculpt before splitting it into sections. And lastly, you *also* want to take the final evaluated geometry of the sections, after all the expensive Boolean modifiers have been calculated, and you want to parent them to an armature in order to do some articulated animation. — Using Array Caps on empty meshes to create dynamic copies of evaluated geometry not only allows all this to be done in a procedural way, but does so with explicit depsgraph stop points— without re-computing hundreds of Boolean modifiers for every frame of the final animation (or every edit made to just one component). I am aware that this was not exactly the *intended use* of the Array modifier. But it is still within the *documented/expected and established behaviour*. Many projects that I made using this technique simply would not have been possible otherwise; The scene complexity and computational complexity would have both quickly grown quadratically to unmanageable levels if I had to create full copies of every object and keep them in a single modifier stack, and the workflow complexity would have been prohibitively more cumbersome if I had had to apply all the modifiers (and lost the ability to organically sculpt the base mesh) at every step in order to keep the depsgraph simple. Using Array Caps on empty meshes to create realized instances of modified geometry allowed me to keep the scene and computational complexity mostly linear, while also keeping a highly efficient procedural workflow. I currently have many project files— *Most* of my project files from the last several years, I'd say, including some that are still ongoing— That make use of this technique in one way or another. I've been meaning to switch to a Geometry Nodes-based replacement in future use, but this change still breaks the existing files. --- FWIW, Personally I can't specifically remember ever running into a crash as a result of an Array modifier on an empty mesh, despite using them a lot. Without the cause of the crash being documented, I also have questions about whether commit 8b2556e8d8 was tested thoroughly enough to actually fix it— For example, supposing it was caused by zero bounding box size or something like that, what happens now if you have a single vertex? Personal opinion: Unreported (and currently unreproducible) crash in extreme corner case is not worth breaking existing files/behaviour.
Member

Interesting! Thx for the insights, that is actually quite useful to know -- even if totally hidden and somewhat obscure (I recall situations prior to GN where I wished this was possible and didnt know it was :/).

Of course, geonodes makes life nice here (cant think of another solution -- except for the one below), but still would be good to know the motivation behind culprit commit.

If the current situation stays, one way would be to place a single vertex for all of the objects using this workflow (as you already noticed). OTOH, there now seems to be something wrong with that even (normals somehow evaluate as smooth in that scenario, caused by 5876573e14 @HooglyBoogly ) so the whole workflow seems to be kinda broken now (you'd have to place a whole face now and hide it or something...).

Looks like this with a single vert atm.:
image

Interesting! Thx for the insights, that is actually quite useful to know -- even if totally hidden and somewhat obscure (I recall situations prior to GN where I wished this was possible and didnt know it was :/). Of course, geonodes makes life nice here (cant think of another solution -- except for the one below), but still would be good to know the motivation behind culprit commit. If the current situation stays, one way would be to place a single vertex for all of the objects using this workflow (as you already noticed). OTOH, there now seems to be something wrong with that even (normals somehow evaluate as smooth in that scenario, caused by 5876573e14f434a4cd8ae79c69afbe383111ced9 @HooglyBoogly ) so the whole workflow seems to be kinda broken now (you'd have to place a whole face now and hide it or something...). Looks like this with a single vert atm.: ![image](/attachments/e3a12624-adbb-4601-8e1b-05f23b06f3e9)
275 KiB

@lichtwerk Normals (the auto-smoothing used) are object data. The geometry nodes here just take the less complicated route (waiting for the data to get into the mesh).
Also, yes, I used a empty array many times to copy geometry.
And I'm also not sure what could cause the crash.
The functionality itself can be strange (should the caps be array elements, so array shouldn't be empty?).
But given the plans to replace all modifiers with node groups (I don't know if it will be in this decade XD ), it will happen at some point anyway.

@lichtwerk Normals (the auto-smoothing used) are object data. The geometry nodes here just take the less complicated route (waiting for the data to get into the mesh). Also, yes, I used a empty array many times to copy geometry. And I'm also not sure what could cause the crash. The functionality itself can be strange (should the caps be array elements, so array shouldn't be empty?). But given the plans to replace all modifiers with node groups (I don't know if it will be in this decade XD ), it will happen at some point anyway.

I unfortunately cannot remember the details of the reproducible case, hit the crash in some production file from the studio (probably Heist ones) while working on something else as far as I can remember. But in general lots of code in modifiers/mesh area will not behave reliably with empty geometry. Just check BKE_mesh_minmax in case there is no vertices e.g. - it leaves the bbox to its 'initialized' max values. Empty geometry may also cause zero-size allocation of memory e.g., which is also not very safe process to say the least.

And this very specific usage is more of a 'use a bug as a feature' case to me, it has never been officially documented afaik, and it should not be. There is indeed way better ways to achieve this result now.

Am not opposed to bringing this behavior back into this modifier - but it has to be done properly then, most likely with a dedicated codepath (unless someone has time to carefully check the entire modifier code to iron it again zero-size arrays of data) . This support should also be properly documented and tested then.

I unfortunately cannot remember the details of the reproducible case, hit the crash in some production file from the studio (probably Heist ones) while working on something else as far as I can remember. But in general lots of code in modifiers/mesh area will not behave reliably with empty geometry. Just check `BKE_mesh_minmax` in case there is no vertices e.g. - it leaves the bbox to its 'initialized' max values. Empty geometry may also cause zero-size allocation of memory e.g., which is also not very safe process to say the least. And this very specific usage is more of a 'use a bug as a feature' case to me, it has never been officially documented afaik, and it should not be. There is indeed way better ways to achieve this result now. Am not opposed to bringing this behavior back into this modifier - but it has to be done properly then, most likely with a dedicated codepath (unless someone has time to carefully check the entire modifier code to iron it again zero-size arrays of data) . This support should also be properly documented and tested then.
Author

And this very specific usage is more of a 'use a bug as a feature' case to me, it has never been officially documented afaik, and it should not be.

Personally my instinct is that this behaviour falls under the existing documented behaviour, and disabling it isn't disabling an undocumented quirk so much as creating a new undocumented exception to the overall rule— I.E. The expected behaviour is that the caps are introduced into the generated geometry, and the specific content (or lack of content) in the datablock should not directly affect that.

> And this very specific usage is more of a 'use a bug as a feature' case to me, it has never been officially documented afaik, and it should not be. Personally my instinct is that this behaviour falls under the existing documented behaviour, and disabling it isn't disabling an undocumented quirk so much as creating a new undocumented exception to the overall rule— I.E. The expected behaviour is that the caps are introduced into the generated geometry, and the specific content (or lack of content) in the datablock should not directly affect that.

@ideasman42 Hey, how shall we proceed with this report?

@ideasman42 Hey, how shall we proceed with this report?

From what I can grasp this was never intended to be removed, but more a by-product of an unrelated fix.

In this case, how hard would be to bring the old functionality back?

From what I can grasp this was never intended to be removed, but more a by-product of an unrelated fix. In this case, how hard would be to bring the old functionality back?

@dfelinto as I explained in my comment, this is doable, but does require some work to be done properly and ensure the code is now safe. In general case, Mesh code is not safe regarding empty geometry.

So my view on this is that the best solution would likely be to add a dedicated code path to this modifier, when the actual source geometry is empty, buts caps are valid, that only stitches these caps together.

@dfelinto as I explained in my comment, this is doable, but does require some work to be done properly and ensure the code is now safe. In general case, Mesh code is _not_ safe regarding empty geometry. So my view on this is that the best solution would likely be to add a dedicated code path to this modifier, when the actual source geometry is empty, buts caps are valid, that only stitches these caps together.

I would also add that I personally do not see interest in investing time in adding back that behavior in the correct way, there are way more suited tools for this feature these days (geometry nodes...), rather than (ab)using a tool that was never designed for this specific usage in the first place.

That being said, if the module think it should be restored, I can have a look at it.

I would also add that I personally do not see interest in investing time in adding back that behavior in the correct way, there are way more suited tools for this feature these days (geometry nodes...), rather than (ab)using a tool that was never designed for this specific usage in the first place. That being said, if the module think it should be restored, I can have a look at it.
Blender Bot added
Status
Resolved
and removed
Status
Confirmed
labels 2023-09-28 15:34:48 +02:00

With great pleasure I saw that this ticket was closed with "Resolved". Thank you very much at this point for restoring this functionality.

I downloaded Blender v3.6.5 and realized, the code changes of the related fix Fix #107353 seems not to be included.

Can you please comment when the code changes of Fix #107353 will be included in a regular Blender release (hopefully a LTS release)?

By the way: Blender is just amazing. Thanks for all the work!

With great pleasure I saw that this ticket was closed with "Resolved". Thank you very much at this point for restoring this functionality. I downloaded Blender v3.6.5 and realized, the code changes of the related fix Fix #107353 seems not to be included. Can you please comment when the code changes of Fix #107353 will be included in a regular Blender release (hopefully a LTS release)? By the way: Blender is just amazing. Thanks for all the work!
Member

I have added the fix to #109399

I have added the fix to #109399
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
8 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#107353
No description provided.