Material reusability and fields #112547

Open
opened 2023-09-18 23:26:08 +02:00 by Hans Goudey · 4 comments
Member

Problem

Currently materials are hard to share between multiple use cases. Any high level input that connects the material to outside information cannot be controlled from outside the material. For example, images and attribute names cannot be changed without changing the material.

Any node input that can't vary per shader evaluation also currently isn't editable without changing the node directly. For example, the sky texture inputs can't be changed without changing the material directly.

So far, the answer to this lack of reusability has been simply duplicating the material. A combination of helper node groups, high level builtin nodes like various texture nodes and principled shaders have helped to make this work better. However, with material assets and increased use of attributes as shader inputs, this lack of re-usability is becoming a larger problem.

Pushing users away from reusing shaders causes performance problems too, particularly with shader compilation. Games spend a lot of effort reusing shaders with different inputs for this reason.

Solution

High Level Interface

image

Currently the property editor attempts to provide a high-level interface for editing a node tree. This exposes the value of every single node value to the user in a complex tree layout. That's flexible, yes, but most users don't want to edit every single value of the node tree, they want simple control of high-level input parameters.

image

We even present absurd menus like this to try to make editing nodes from the property editor viable.

image

Instead, the material properties should follow the lead of geometry nodes and give a single high-level overview of explicitly configured node inputs. This has a few ramifications:

  • Property editor node editing is removed: Code is simplified, maintenance reduced, we don't have to try to make editing a graph in a vertical interface work well.
  • Materials get group input nodes: Since only explicitly "exposed" inputs are presented to the property editor high-level interface, materials become more like node groups-- they have explicit input nodes. For existing materials, these could be added by versioning for all sockets.
  • High level material control is much more intuitive: Since material authors can create large material node graphs but more easily choose what complexity they expose to users, using materials can be more powerful and simple.
  • Material inputs are stored per-material, per geometry: Similar to geometry nodes, these inputs are stored together for each material. Not storing them on the material is essential to allow reuse.

Fields

image

Exposing properties as node sockets provides the flexibility to create a high-level interface. But since node evaluations are expected to happen for every shader evaluation, it also doesn't quite work. Shaders aren't able to use a different attribute or image texture depending on some value that varies per shader evaluation (e.g. a ray direction). Those things are expected to be constant.

Currently this isn't an issue because:

  1. Almost constant node inputs are just node properties, they aren't sockets.
    • This breaks reusability, since many of these like image textures are important inputs
  2. Other constant node inputs are strings, and there are no nodes to affect strings in shader nodes
    • This removes the ability to affect strings with nodes like switch nodes or string conversion nodes

We need the ability to distinguish between constant values and values that can vary per shader evaluation. Without the visual distinction, it would be too confusing to figure out which inputs can vary and which can't, and that status wouldn't propagate, which is an essential part of making the system usable.

The fields (manual) concept from geometry nodes is a solution to this problem. Every node input can be a socket. If the input can't change per-shader evaluation, it will only accept single values. If it can vary, the link will be dashed, and that is clear visually.

Socket Types

String, menu, and image sockets should be exposed in shader nodes. These sockets wouldn't support fields, so they couldn't vary per shader evaluation, but they can vary per object

In the future, object and collection sockets could be exposed to shader nodes as well. There's no reason a geometry-nodes-object-info-like node couldn't work in shader nodes at that point. But that should be investigated as a next step to avoid making this too complicated.

# Problem Currently materials are hard to share between multiple use cases. Any high level input that connects the material to outside information cannot be controlled from outside the material. For example, images and attribute names cannot be changed without changing the material. Any node input that can't vary per shader evaluation also currently isn't editable without changing the node directly. For example, the sky texture inputs can't be changed without changing the material directly. So far, the answer to this lack of reusability has been simply duplicating the material. A combination of helper node groups, high level builtin nodes like various texture nodes and principled shaders have helped to make this work better. However, with material assets and increased use of attributes as shader inputs, this lack of re-usability is becoming a larger problem. Pushing users away from reusing shaders causes performance problems too, particularly with shader compilation. Games spend a lot of effort reusing shaders with different inputs for this reason. # Solution ## High Level Interface ![image](/attachments/1697c1b3-42b1-40c3-b295-d69938defb19) Currently the property editor attempts to provide a high-level interface for editing a node tree. This exposes the value of **every single node value** to the user in a complex tree layout. That's flexible, yes, but most users don't want to edit every single value of the node tree, they want simple control of high-level input parameters. ![image](/attachments/52142055-e578-42b3-81fc-f9ae2de2b10a) We even present absurd menus like this to try to make editing nodes from the property editor viable. ![image](/attachments/1a3b6c48-f8ac-4e4e-ab7c-97c956d5f6b0) Instead, the material properties should follow the lead of geometry nodes and give a single high-level overview of explicitly configured node inputs. This has a few ramifications: - **Property editor node editing is removed**: Code is simplified, maintenance reduced, we don't have to try to make editing a graph in a vertical interface work well. - **Materials get group input nodes**: Since only explicitly "exposed" inputs are presented to the property editor high-level interface, materials become more like node groups-- they have explicit input nodes. For existing materials, these could be added by versioning for all sockets. - **High level material control is much more intuitive**: Since material authors can create large material node graphs but more easily choose what complexity they expose to users, using materials can be more powerful and simple. - **Material inputs are stored per-material, per geometry**: Similar to geometry nodes, these inputs are stored together for each material. Not storing them on the material is essential to allow reuse. ## Fields ![image](/attachments/fd73d09b-024b-4b80-ab14-c4df876b0bd6) Exposing properties as node sockets provides the flexibility to create a high-level interface. But since node evaluations are expected to happen for every shader evaluation, it also doesn't quite work. Shaders aren't able to use a different attribute or image texture depending on some value that varies per shader evaluation (e.g. a ray direction). Those things are expected to be constant. Currently this isn't an issue because: 1. Almost constant node inputs are just node properties, they aren't sockets. - This breaks reusability, since many of these like image textures are important inputs 2. Other constant node inputs are strings, and there are no nodes to affect strings in shader nodes - This removes the ability to affect strings with nodes like switch nodes or string conversion nodes **We need the ability to distinguish between constant values and values that can vary per shader evaluation.** Without the visual distinction, it would be too confusing to figure out which inputs can vary and which can't, and that status wouldn't propagate, which is an essential part of making the system usable. The **fields** ([manual](https://docs.blender.org/manual/en/latest/modeling/geometry_nodes/fields.html)) concept from geometry nodes is a solution to this problem. Every node input can be a socket. If the input can't change per-shader evaluation, it will only accept single values. If it can vary, the link will be dashed, and that is clear visually. ## Socket Types String, menu, and image sockets should be exposed in shader nodes. These sockets wouldn't support fields, so they couldn't vary per shader evaluation, but they can vary per object In the future, object and collection sockets could be exposed to shader nodes as well. There's no reason a geometry-nodes-object-info-like node couldn't work in shader nodes at that point. But that should be investigated as a next step to avoid making this too complicated.
Hans Goudey added the
Type
Design
label 2023-09-18 23:26:08 +02:00
Hans Goudey added this to the Render & Cycles project 2023-09-18 23:26:10 +02:00
Contributor

Very good design proposal.

For group inputs and exposing sockets in the material properties tab, a couple of things are required, if the goal is to make materials as assets more shareable, and reduce dependency on add-ons, or sometimes for it to even work.

Sockets supported in material properties aren't enough yet to make node group assets viable option. String is needed to specify Attribute from properties, but most important ones are Image sockets and one that doesn't exist yet, ColorRamps.

I have multiple little add-ons that I use, just because Image sockets aren't supported yet. For example, Anti-Tile imports a node group which has Image Texture node inside, and selected image gets appended in that node. I can't use this node group as asset, because then I would have to duplicate node group for each image, go into each node group and select images for entire PBR setup. Image socket would be enough to get rid of the script and simply drop the node group between Image Texture and Principled.

PBR materials are most widely-used and shared, especially for game assets, and for those, it's hard to imagine what Material Properties should look like without Image sockets, and especially without ColorRamps. If I have setup that has PBR basecolor, roughness, metallic and normal, only thing I can expose (besides coordinates) is normal strength. Controlling colorramps is necessary for materials. And not only for PBR. Black-and-white textures can somehow get by with Map Range, but when ColorRamp also controls basecolors, you need to dive really deep in the node setup sometimes. For example I use procedural sky, and only way to change its color is by either diving in multiple node groups and finding ramp, or by addon that exposes ramp in my properties.

Ramps exposed in properties would allow asset creators to expose color & contrast settings in properties, and hide more technical node setups from users. Similar to how Substance Painter exposes ramps to user, but interested users can see node setup behind it in Designer.

Very good design proposal. For group inputs and exposing sockets in the material properties tab, a couple of things are required, if the goal is to make materials as assets more shareable, and reduce dependency on add-ons, or sometimes for it to even work. Sockets supported in material properties aren't enough yet to make node group assets viable option. String is needed to specify Attribute from properties, but most important ones are Image sockets and one that doesn't exist yet, ColorRamps. I have multiple little add-ons that I use, just because Image sockets aren't supported yet. For example, Anti-Tile imports a node group which has Image Texture node inside, and selected image gets appended in that node. I can't use this node group as asset, because then I would have to duplicate node group for each image, go into each node group and select images for entire PBR setup. Image socket would be enough to get rid of the script and simply drop the node group between Image Texture and Principled. PBR materials are most widely-used and shared, especially for game assets, and for those, it's hard to imagine what Material Properties should look like without Image sockets, and especially without ColorRamps. If I have setup that has PBR basecolor, roughness, metallic and normal, only thing I can expose (besides coordinates) is normal strength. Controlling colorramps is necessary for materials. And not only for PBR. Black-and-white textures can somehow get by with Map Range, but when ColorRamp also controls basecolors, you need to dive really deep in the node setup sometimes. For example I use procedural sky, and only way to change its color is by either diving in multiple node groups and finding ramp, or by addon that exposes ramp in my properties. Ramps exposed in properties would allow asset creators to expose color & contrast settings in properties, and hide more technical node setups from users. Similar to how Substance Painter exposes ramps to user, but interested users can see node setup behind it in Designer.
Contributor

Great proposal, looking forward to how it develops!

I would like some clarifications, mainly on how Material and NodeTree interact here, but also integration with other systems.

  1. Property values are stored on the material datablock, I assume? This would make library overrides viable for overriding input values.

  2. Will materials still have a NodeTree "embedded" into them like it works now, or will it shift to the Geometry Nodes modifier approach where each modifier has a selector for which NodeTree to use in the modifier? The latter would mainly allow re-using a node group as a material more easily, but also requires more datablock management + merging "Material Output" with "Group Output" which sounds problematic.

  3. Would the "high level property interface" allow the user to select attributes directly as group input, or would it still be done with the "Attributes" node + string inputs? If so, I assume the socket would need to get the "Type" dropdown (Geometry/Object/Instancer/View Layer??).

    • Might be problematic when paired with the "Set Material" node, since you can't blindly pass data to a material's group inputs - so attribute names are probably necessary here.
  4. Materials get group input nodes: [...] For existing materials, these could be added by versioning for all sockets.

    How would it determine for which inputs to add sockets? "All unconnected inputs" sounds unreasonable for larger material trees.

  5. I assume Shader group inputs are not shown in the "high level property interface", since they would need a largely convoluted UI to allow editing them reasonably (which is exactly what you're trying to get rid of here)?

Great proposal, looking forward to how it develops! I would like some clarifications, mainly on how Material and NodeTree interact here, but also integration with other systems. 1. Property values are stored on the material datablock, I assume? This would make library overrides viable for overriding input values. 2. Will materials still have a NodeTree "embedded" into them like it works now, or will it shift to the Geometry Nodes modifier approach where each modifier has a selector for which NodeTree to use in the modifier? The latter would mainly allow re-using a node group as a material more easily, but also requires more datablock management + merging "Material Output" with "Group Output" which sounds problematic. 3. Would the "high level property interface" allow the user to select attributes directly as group input, or would it still be done with the "Attributes" node + string inputs? If so, I assume the socket would need to get the "Type" dropdown (Geometry/Object/Instancer/View Layer??). * Might be problematic when paired with the "Set Material" node, since you can't blindly pass data to a material's group inputs - so attribute names are probably necessary here. 4. > Materials get group input nodes: [...] For existing materials, these could be added by versioning for all sockets. How would it determine for which inputs to add sockets? "All unconnected inputs" sounds unreasonable for larger material trees. 5. I assume Shader group inputs are not shown in the "high level property interface", since they would need a largely convoluted UI to allow editing them reasonably (which is exactly what you're trying to get rid of here)?
Iliya Katushenock added the
Interest
Nodes & Physics
label 2023-09-19 06:10:17 +02:00
Author
Member

Great points!

String is needed to specify Attribute from properties, but most important ones are Image sockets and one that doesn't exist yet, ColorRamps.

I wouldn't include exposing color ramps as sockets in this design task, that opens too many other questions. But I think it would fit in here the same way as geometry nodes. I agree that string and image sockets are essential though.

Property values are stored on the material datablock, I assume? This would make library overrides viable for overriding input values.

It's essential that they're stored in the material slot to allow reuse. i.e. per material, per geometry. I added a note about that to the design.

Will materials still have a NodeTree "embedded" into them like it works now, or will it shift to the Geometry Nodes modifier approach

I was tempted to include removing the embedded node group in this design, since I think it would be much better, especially on a Blender data-base design level. It might be a good opportunity to do that, but it's probably better to discuss it elsewhere.

Would the "high level property interface" allow the user to select attributes directly as group input, or would it still be done with the "Attributes" node + string inputs?

I think, like geometry nodes, both could be possible. At first I'd just stick to using the attribute node though. We don't have enum sockets yet, but when we do, they could be used here.

How would it determine for which inputs to add sockets? "All unconnected inputs" sounds unreasonable for larger material trees.

Using panels would make this look more-or-less like the current setup. But that is a tricky point, I agree.

I assume Shader group inputs are not shown in the "high level property interface"

Right, just like geometry sockets in geometry nodes


I think the point you bring up about the "Set Material" node is a good one. It's not clear how you would set these inputs from geometry nodes. It could work to expose the inputs dynamically in the "Set Material" node, but that makes node reusability in geometry nodes tricky too, since the material can be defined by an input there too. It would be so powerful to send values from geometry nodes directly to shader node inputs though!

Great points! >String is needed to specify Attribute from properties, but most important ones are Image sockets and one that doesn't exist yet, ColorRamps. I wouldn't include exposing color ramps as sockets in this design task, that opens too many other questions. But I think it would fit in here the same way as geometry nodes. I agree that string and image sockets are essential though. > Property values are stored on the material datablock, I assume? This would make library overrides viable for overriding input values. It's essential that they're stored in the material slot to allow reuse. i.e. per material, per geometry. I added a note about that to the design. >Will materials still have a NodeTree "embedded" into them like it works now, or will it shift to the Geometry Nodes modifier approach I was tempted to include removing the embedded node group in this design, since I think it would be much better, especially on a Blender data-base design level. It might be a good opportunity to do that, but it's probably better to discuss it elsewhere. >Would the "high level property interface" allow the user to select attributes directly as group input, or would it still be done with the "Attributes" node + string inputs? I think, like geometry nodes, both could be possible. At first I'd just stick to using the attribute node though. We don't have enum sockets yet, but when we do, they could be used here. >How would it determine for which inputs to add sockets? "All unconnected inputs" sounds unreasonable for larger material trees. Using panels would make this look more-or-less like the current setup. But that is a tricky point, I agree. >I assume Shader group inputs are not shown in the "high level property interface" Right, just like geometry sockets in geometry nodes --- I think the point you bring up about the "Set Material" node is a good one. It's not clear how you would set these inputs from geometry nodes. It could work to expose the inputs dynamically in the "Set Material" node, but that makes node reusability in geometry nodes tricky too, since the material can be defined by an input there too. It would be so powerful to send values from geometry nodes directly to shader node inputs though!
Hans Goudey added the
Interest
Geometry Nodes
Interest
EEVEE & Viewport
labels 2023-09-19 13:54:19 +02:00

I'm very happy that this is being talked about. I started working with another DCC app in my current job and I found very convenient to be able to change the projection modes of a material on an object without affecting other objects using the same material. I think this would allow that, no?

I'm very happy that this is being talked about. I started working with another DCC app in my current job and I found very convenient to be able to change the projection modes of a material on an object without affecting other objects using the same material. I think this would allow that, no?
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 Assignees
4 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#112547
No description provided.