Grease Pencil 3: Migration of the "Layer Adjustments/Modifiers"

The task

Currently in Grease Pencil (v2), there are a few options that allow users to modify layers in a procedural way:

These were implemented in their own custom system, which is not ideal (and lead to numerous bugs).
For Grease Pencil 3, the plan is to utilize the existing modifier system instead.

The plan

  • Make transform, tint, stroke thickness, and pass index cutom layer attributes. The parent and view layer name can be stored on the layers in their DNA (object pointers/strings can’t be custom attributes at the moment).
  • Expose these settings through RNA (as shown in the screengrab).
  • Create modifiers (could be geonodes trees too) that reads the attributes (by name) and use them for what is needed (e.g. transforming the points or setting the radii). They should only exist when the option is actually used by any layer.

Now there are multiple ways we could go about exposing the modifier. This is where I’d like feedback from other developers on.

Option 1

Don’t expose the modifiers to users at all. Instead these modifiers are “virtual” modifiers that are always at the top of the stack but hidden (similar to e.g. mesh shape keys, or object parenting) .

Option 2

Expose the modifiers in the modifier stack, but don’t allow them to be deleted by the user. Similar to e.g. the particle system, the modifiers wouldn’t show any options, instead they would link to the data properties for the layers.

Option 3

Expose the modifiers in the modifier stack. Allow the user to delete/create them as they would any other modifier. This might lead to some unexpected behavior if the attribute exists, but is not used by any modifier. For example, the drawing tool draws into “layer space” meaning it reads the layer transform and uses the inverse matrix to project the points into. If the transform is not actually used to transform points, then the strokes won’t appear in the right place.

Personally, I am leaning towards option 1 or 2. My reason being that these settings are for users that specifically don’t want to deal with modifiers. And users that do want to utilize modifiers can make their custom setup e.g. with geometry nodes and just not use these “quick” settings.


It feels like all 3 options leave this layer adjustment functionality/panel in a halfway transition between using but not fully embracing the geonodes/generic flexibility.
How about a different option. Make this entire layer adjust panel live inside of the modifier stack. The modifier panel UI needs to become context sensitive to what layer is selected/active of course. Then the “Tint Color” property could be stored/modified on just the active layer. The functionality of this modifier could be extended/reused by other users to expose more per-layer adjustments/modifiers/tools. It does imply a lot more work of course. Current options 1-3 are just flavors of how to deal with the current simplified approach. And like your wrote not everything the current panel does can be stored as attributes yet either.
This could also just be future work/plan for later.

As a technical artist, I’d lean towards option 3. I’d foresee somebody creates some fancy nodetree that does colorization. Then it could make a lot of sense that an artist would want to tweak a Color Tint after the modifier. Maybe it should be option 1 by default, with a per-object override/option to break out the virtual modifier into a real one for option 3.

I think not all these properties are the same?

The transform properties seem like they would be built-in attributes that anything handling the output of geometry nodes should be able to deal with. Similar to transform attributes on instances or curve radius attributes that can be handled by the renderer, or at least applied after geometry nodes evaluation in some way that the renderer can handle it.

Pass index is probably similar to transform in this way, in that a renderer that understands layers may support that directly and if not it becomes a pass index on object instances or something before the renderer uses it.

The tint seems different, like a modifier on a built-tin color attribute. To me that makes sense as a node or modifier, either as a property automatically applied before geometry nodes evaluation or not a property at all and just a modifier or node setup. Stroke thickness I guess is similar, but I couldn’t guess what it does exactly because it doesn’t seem to be a multiplier but has an absolute pixels unit?

Parenting I guess would be written into transform attributes before geometry nodes evaluation. Holding onto that throughout the geometry nodes evaluation seems conceptually not so simple.

To me there is an important distinction between what the built-in attributes are that geometry nodes understand and maintain, vs. some setting that modifies such built-in attributes.

1 Like

This discussion is I think similar to the dillema in EEVEE next about Bloom panel and auto-smooth for geometry nodes. Yes, its gonna be a painful step for some people in their workflows, but I think for the sake of unification it should be removed and fully converted into modifiers in versioning.

Options 1 and 2 hide information from user and ultimately become confusing. How does tint in the panel mix with other modifiers, or compositing effects? (similar questions about legacy EEVEE bloom, and auto-smooth and Set Shade Smooth nodes). Why is there a hidden modifier, when I can see all the rest of them?

As I said in the chat, I’ve had a case where student couldnt figure out why tint modifier wasnt working and it was because they had Tint in the panel (factor) set to 1, thinking it was modifier property. Its ultimately confusing, and anachronic. For modifier, node-based workflow I think they should either be removed, or turned into multipliers.

What I’m thinking is “Bevel Weight” and “Crease” attributes of mesh, which ultimately exist to give attribute to modifier. Same way I’m imagining layers can still have tint factor and line thickness (and some other attributes), but as multipliers for Tint and Line Thickness modifiers (and custom geonode modifiers). That way most modifiers might not need layer influence picker at all.

Agreed. It’s important that e.g. the selection code or the drawing tool can read this so that they can behave correctly.

This one is a bit weird. From what I understand it’s mainly used to assign values to layers which can be used in the grease pencil modifiers as filters. Essentially, it allows to create “layer filter groups” because multiple layers can have the same value.

Confusingly, I couldn’t find any code related to rendering for this.


I’d love to get rid of it, but users have already complained that this would be a regression to them. Some like to just tweak a few settings in the properties and not worry about adding modifiers at all. We could enforce this, but for me it wouldn’t be a hill to die on.

It is. The pixel part is some grease pencil weirdness. Radii used to be stored in “pixels” taken from the brush size directly and then (rather arbitrarily) converted to world space in the renderer itself.

TLDR: It’s a value that gets added to all radii.

Yes that seems like a good way to do it. Would that be a “virtual” modifier then?

For parenting, it seems like the logical choice.

If tint and stroke thickness are kept as native properties, I guess they would also be virtual modifiers. And in that case I think they would not be stored as attribute, but regular DNA properties. Since there is not much you can do with such properties once they are already applied?

I don’t feel strongly about tint and thickness being actual or virtual modifiers. I guess it’s a general UI challenge where someone might want to have a convenient way adding a modifier to just a single layer (or parent layer), not just for these particular properties. With many layers a single modifier stack could get difficult to navigate.

You could imagine each layer having their own modifier stack in addition to the overall stack, but that’s complex in its own ways.

To clarify, I wasn’t suggesting that they should be native properties, but that some users like to use them in that way.
I would still vote for tint and thickness just to be a built-in layer attribute that can be written from the data properties (for convenience) but is then applied using a modifier.
Other modifiers coming after that could still apply, say, an additional thickness factor on top of that.

Yes that’s exactly it. If we got rid of say the tint property in the layer properties, it would be possible to produce the same effect with geometry nodes, but it would be much much more complicated. Especially when you want to have the tint only affect a single layer…

Maybe! Although I think having built-in per-layer attributes that are used by the modifiers is already pretty good.

So to update:

  • The parent is stored as a property (on the layer DNA). It is used in a virtual modifier to write to the layer transform attribute.

  • Transform, tint, and thickness are built-in layer attributes. For convenience, they can be changed from the layer properties panel (the attributes are exposed through RNA). They are then applied using modifiers. I think this could be done similarly to the “Auto Smooth”.

  • Not sure what to do with “Pass Index”. I’m inclined to make it an attribute. This means it could be deprecated later, without having to fiddle with DNA.

@filedescriptor @brecht
i guess to ease the viewing of modifiers stuck , it must be an option to hide all modifiers that are not used by the active layer or its pass index, as button or sth like that, this is a solution to Tint modifier and a good way to discover and investigate which modifier is for a layer or a group of layers(pass index) for someone tries to read how things is working …