Author Topic: Shader: Glitter / Sequin (Pt.2)  (Read 1032 times)

2020-01-19, 08:53:25

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I have been exploring materials containing glitter / stochastic flakes recently and it has been a significant challenge for different reasons. Dubcat showed progress with a shader exhibiting glitter that was pretty compelling, but probably not similar to what could be achieved with stochastic flakes or similar shading effect.

I posted results for a semi-metallic material (see below) - my current best effort - that was meant to convey a glitter effect, but after extensive tests with various implementations of car paint shaders (i.e. Corona material library and Siger Studio), I am sort of curious whether it is actually technically possible to achieve a result comparable to V-Ray stochastic flakes with Corona Renderer?

Baroque

*semi-metallic wall covering processed from scan data



2020-01-20, 00:46:29
Reply #1

burnin

  • Active Users
  • **
  • Posts: 896
    • View Profile
Hm...
I wonder, when you write glitter (metallic flakes) or sequin alike, why does then your example appear to look like a textile mixed with a metal thread?
What are you really aiming at?
And please, rather provide a real world example with a link to a product...


« Last Edit: 2020-01-20, 00:50:14 by burnin »

2020-01-20, 01:06:58
Reply #2

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
The example I included is meant to represent a textile with a metal thread, exactly as you described. However, what is not apparent in the render is that as the camera rotates around the model, there is a glitter effect - there is a flake layer inside a layered material. The example is not meant to represent glitter, or sequin, etc. it is only meant to illustrate the fact that I have made an effort to implement a glitter effect and have not been able to achieve a completely desirable result.

I am aiming for the effect that can be observed in the stochastic flakes link from the original post, however, I have not managed to create something even close to that, and it may not be technically feasible to do inside Corona at this time - it is not a rendering feature that is currently available. It would be good to know (absolutely) whether it is currently possible to achieve an effect like that with Corona, because if not I could just be spinning my wheels...

That being said, there are technical artists, and more generally artists with more experience, that might be able to create something like that in Corona, and so I am not willing to write off that possibility right away simply because I, personally, wasn't able to do it yet.

2020-01-20, 19:11:44
Reply #3

burnin

  • Active Users
  • **
  • Posts: 896
    • View Profile
Like this?


Note: Noise size and contrast modified to emphasize the sparkle effect.
Flakes are achieved with similar technique as that which is described in papers. But instead of circular flakes, i'm using cell voronoi noise (C4D) which drives normal map in a bump channel of a metal layer for a carpaint layered material (below).


« Last Edit: 2020-01-20, 19:16:53 by burnin »

2020-01-20, 21:21:42
Reply #4

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
Right, this appears as a carpaint shader to my eye  which although it contains a shimmer effect, is not as pronounced as the glitter effect depicted in the stochastic flakes video from the original post.

I'm not sure if I really expect Corona Team members to say whether it is absolutely possible or not, at present, but I also didn't see anything about stochastic flakes on the dev log(?)

2020-01-20, 21:55:27
Reply #5

sprayer

  • Active Users
  • **
  • Posts: 715
    • View Profile


you mean like this?

2020-01-20, 22:32:21
Reply #6

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I must admit, that's pretty interesting. I wouldn't say it's exactly the same as the stochastic flakes implementation, but this is probably the best glitter I've seen in Corona. Nice work 👍
« Last Edit: 2020-01-21, 09:19:07 by cjwidd »

2020-01-20, 23:13:14
Reply #7

romullus

  • Global Moderator
  • Active Users
  • ****
  • Posts: 6268
  • Let's move this topic, shall we?
    • View Profile
    • My Models
I might be wrong, but i think stochastic flakes is a map, not a shader (don't have a V-Ray). Fundamentally there's nothing missing in Corona that would prevent you to replicate carpaint/glitter or whatever material. You might won't have as convenient control as procedural flakes map would give, but otherwise you should be totally fine.
I'm not Corona Team member. Everything i say, is my personal opinion only.
My Models | My Videos | My Pictures

2020-01-21, 00:11:18
Reply #8

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I'm inclined to agree with you, but I need to do more research into the SF implementation to know for sure. If that is the case, and it's just a map(?) - there is no shader magic happening behind it - that would be great news.


2020-01-21, 09:16:36
Reply #9

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I checked the example posted by sprayer more closely - previously I had looked at it on my phone - and looks like the reflection color is being mapped in addition to the bump?

2020-01-21, 11:43:47
Reply #10

niljut

  • Active Users
  • **
  • Posts: 7
    • View Profile
The OSL map Noise (Gabor) can be a pretty decent procedular map for stochastic flakes, I find. This is a quick test:


2020-01-21, 13:12:50
Reply #11

sprayer

  • Active Users
  • **
  • Posts: 715
    • View Profile
Yes, i put in refl color slot colors noise from photoshop. The others is the same as car paint shader for corona. Maru was made nice tutorial how to make normal maps flakes with corona scatter and you can color them for reflection and bake it as maps. Sadly i do not save the scene

2020-01-21, 20:53:09
Reply #12

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
Right, I've seen that post before - I think and example was posted, actually.

2020-01-21, 21:50:58
Reply #13

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
So one of the things that strikes me about flakes is that it is highly dependent on the lighting scenario, but also if you have filmic highlights or highlight compression enabled, you run the risk of totally flattening the effect. I'm sure this is obvious to everyone else, but it didn't occur to me until well into my tests.

2020-01-22, 00:55:55
Reply #14

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
@Niljut and @Sprayer, are you able to share the shaders you've prepared to the forum? I'd like to study the graph, please.

2020-01-22, 07:14:24
Reply #15

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
If you're on max 2019+ you can also try the glitter OSL shader that chaosgroup provides, google it.

2020-01-22, 07:57:04
Reply #16

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation

2020-01-22, 08:48:41
Reply #17

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
Bummer. It saved the day for me on a material that needed a glitter effect. Whatever you end up with, it should probably be a normal map, not bump, since the glitter particles have to have different orientation. Bump can't do this in the same way a normal map can.

2020-01-22, 10:02:33
Reply #18

niljut

  • Active Users
  • **
  • Posts: 7
    • View Profile
This is the setup I used. Going to try the Chaosgroup shader!


2020-01-22, 10:08:06
Reply #19

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I'm not very familiar with this map: OSL noise. Is this a Max 2019+ feature or is it available in pre-2019 release?

I thought the OSL additions were only 2019+(?)

2020-01-22, 10:18:21
Reply #20

niljut

  • Active Users
  • **
  • Posts: 7
    • View Profile
That is probably the case, I'm on 2020. it's called OSL Noise (Gabor).

2020-01-22, 11:28:42
Reply #21

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
Sorry, it's called flakes, not glitter, link
https://docs.chaosgroup.com/display/OSLShaders/Flakes+normal+map

You can probably use a (OSL) noise, but the good thing about this OSL shader is it creates circles and tints them with random RGB values which gives each circle a different orientation. Might be possible with bump to some extent but then you need to take care of various maps at the same time - the noise that produces the gradients and the masking which 'cuts out' the flakes... it's way more finicky...

2020-01-22, 13:33:22
Reply #22

niljut

  • Active Users
  • **
  • Posts: 7
    • View Profile
Here's a version based on my old shader using the Chaos Group's OSL flakes shader for random normal directions.



And here I'm substituting the OSL Noise (Gabor) shader entirely for the Chaos Group flakes one.


There are pros and cons to each one. Using only the Chaos Group Flakes shader has the benefit of the flakes lining up with the normal directions, the con is that the colors of the flakes are the same as their normal direction, so all the flakes with left-facing normal directions will have the same color.

I think I prefer the mix, the color variation is nice to have.

2020-01-22, 14:33:24
Reply #23

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
In theory, you could key out each RGB component of the normal map and 'redirect' to a multi-colored noise, then comp again for the diffuse slot.
Also, for anyone digging a bit into OSL it would probably be easy to take the shape creator code and make it get random colors which could then be used as diffuse.

OSL really gives us some cool options now. It can't do everything but it can get us quite far... understanding OSL and some coding required, though.

2020-01-22, 17:29:57
Reply #24

niljut

  • Active Users
  • **
  • Posts: 7
    • View Profile
I ended up modifying the Chaos Group flakes shader to add a randomized color output. I have no experience with OSL so I mostly just plugged in something that seems to have worked. Changing the material parameters have such a large impact on the final result

Code: [Select]
shader
flakes
(
float flake_scale = 10.0 [[ string description = "Smaller values zoom into the flake map, larger values zoom out" ]],
float flake_size = 0.5 [[ string description = "Relative size of the flakes" ]],
float flake_size_variance = 0.0 [[ string description = "0.0 makes all flakes the same size, 1.0 assigns random size between 0 and the given flake size" ]],
float flake_normal_orientation = 0.0 [[ string description = "Blend between the flake normals (0.0) and the surface normal (1.0)" ]],

output color NormalResult = 1.0,
output color ColorResult = 1.0,
output float alpha  = 1.0
)
{

float safe_flake_size_variance = clamp(flake_size_variance, 0.1, 1.0);

vector cellCenters[9] = {
vector( 0.5,  0.5,  0.0),
vector( 1.5,  0.5,  0.0),
vector( 1.5,  1.5,  0.0),
vector( 0.5,  1.5,  0.0),
vector(-0.5,  1.5,  0.0),
vector(-0.5,  0.5,  0.0),
vector(-0.5, -0.5,  0.0),
vector( 0.5, -0.5,  0.0),
vector( 1.5, -0.5,  0.0)
};

point position = vector(u, v, 0.0);
position = flake_scale * position;

point base = floor(position);

point nearestCell = point(0.0, 0.0, 1.0);
int nearestCellIndex = -1;
for(int cellIndex = 0; cellIndex < 9; ++cellIndex) {
point cellCenter = base + cellCenters[cellIndex];

vector centerOffset = cellnoise(cellCenter) * 2.0 - 1.0;
centerOffset[2] *= safe_flake_size_variance;
centerOffset = normalize(centerOffset);

cellCenter += 0.5 * centerOffset;

float cellDistance = distance(position, cellCenter);
if(cellDistance < flake_size && cellCenter[2] < nearestCell[2]) {
nearestCell = cellCenter;
nearestCellIndex = cellIndex;
}
}

NormalResult = color(0.5, 0.5, 1.0);
ColorResult = 0.0;
alpha = 0.0;

if (nearestCellIndex != -1) {
vector randomNormal = cellnoise(base + cellCenters[nearestCellIndex] + vector(0.0, 0.0, 1.5));
randomNormal = 2.0 * randomNormal - 1.0;
randomNormal = faceforward(randomNormal, I, randomNormal);
randomNormal = normalize(mix(randomNormal, vector(0.0, 0.0, 1.0), flake_normal_orientation));
ColorResult = color(cellnoise(base + cellCenters[nearestCellIndex]));
NormalResult = color(0.5*randomNormal[0]+0.5, 0.5*randomNormal[1]+0.5, randomNormal[2]);
alpha = 1.0;
}
}


2020-01-22, 18:43:06
Reply #25

Br0nto

  • Active Users
  • **
  • Posts: 47
    • View Profile
Note: Noise size and contrast modified to emphasize the sparkle effect.
Flakes are achieved with similar technique as that which is described in papers. But instead of circular flakes, i'm using cell voronoi noise (C4D) which drives normal map in a bump channel of a metal layer for a carpaint layered material (below).

Burnin, would you mind posting your shader/scene? We're using C4D too, and while this sounds very similar to what we're working with, I'd love to see exactly how you have yours set up.

2020-01-22, 21:42:19
Reply #26

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
I REALLY do not want to upgrade Max right now - for obvious reasons - even if the OSL shader is doing more or less exactly what I need :/

Pokoy, it sounds like you are saying there might be a way to replicate the OSL shader behavior, but it would be more demanding to prepare?

2020-01-23, 16:05:48
Reply #27

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
I have set up a demo for this in a way I'd do it. I'm not 100% happy but it might be helpful, a zip with the scene (Corona 5, Max 2018) and the result is attached.

Open Slate material editor.
The material is a CoronaLayer mtl:
- base layer - just a black matte
- glitter 1 layer
- glitter 2 layer
- glitter 3 layer
- coat layer

It's a multi color glitter mat here, but you can just disable the layers 'glitter 1' and 'glitter 2' for a single glitter layer.
The base is black for a reason. If you give it a light color, you will have to take care of the glitter materials too, they will appear too dark.
The coat is just a fully reflective material with no diffuse, masked by a fresnel map.

Some controls are exposed (only visible in Slate!), they're all on the left side:
- reflection colors for each glitter material (gold, purple, blue), these are corona color maps
- bump noise size, one bezier float for all glitter materials
- bump amount, one bezier float for all glitter materials
- reflection glossiness, one bezier float for all glitter materials
- glitter size, one bezier float for all glitter materials
- glitter spread, one bezier float for all glitter materials

The glitter material works like this:
Each glitter layer is a colored reflective material, masked with a cellular map set to produce small circles. Each has a noise map as bump to make sure the glitter catches reflections form different places (to mimic the glitter particles being scattered and rotated randomly). Bump noise size and glitter size/spread are related, if one of them is too big/too small you'll start to see the bump structure which is not good. So if you change the glitter size you probably need to take care of the bump noise size too.

Each of the noise maps for bump and the cellular maps for the layer mask need to have different coordinates, otherwise they'd all sit in the same place - so these maps need to be unique, not instanced. That's why they have a bezier float controller so you can set the respective parameter in one go for all 3 maps, without having to do dial in the same value 3 places each time you need to change the settings.

Then there's glossiness for the glitter materials, using perfectly sharp reflections will produce a lot of fireflies and not spread the reflection enough. Make sure to play with that.
And there's a falloff multiplied over the cellular map used for the layer masks. Without it, the glitter would get way too much reflections from the surroundings. Play with the output curve if you feel it's too much (or too little) reflection on grazing angles.

The problem with this setup - which would also be there with the OSL map - is that the geometry is flat and has no volume. I guess in reality glitter particles are scattered on a surface, so some of them will be facing the camera, some not. Here, they all map as a circle onto the geometry which makes them visible at all times - that's why the falloff in the composite node is needed. Also, in reality there's a coating over the glitter particles which causes the reflections of some glitter particles to be invisible to the viewer due to total reflection within/under the coat. So it's a pretty complex effect and doing it all on a 2D surface without any sophisticated ray simulation can't properly mimic it... I think.

The advantage of the OSL map is that it correctly 'rotates' each particle in a normal map and is not faked by bump, plus you need less knobs, it's all in one map. But it's also a 2D map, no volumetric effects so it is limited, too.

It's a rather finicky material so make sure to play with only one glitter layer first.
« Last Edit: 2020-01-23, 17:40:23 by pokoy »

2020-01-23, 16:07:13
Reply #28

pokoy

  • Active Users
  • **
  • Posts: 1482
    • View Profile
I ended up modifying the Chaos Group flakes shader to add a randomized color output. I have no experience with OSL so I mostly just plugged in something that seems to have worked. Changing the material parameters have such a large impact on the final result

Code: [Select]
shader
flakes
(
float flake_scale = 10.0 [[ string description = "Smaller values zoom into the flake map, larger values zoom out" ]],
float flake_size = 0.5 [[ string description = "Relative size of the flakes" ]],
float flake_size_variance = 0.0 [[ string description = "0.0 makes all flakes the same size, 1.0 assigns random size between 0 and the given flake size" ]],
float flake_normal_orientation = 0.0 [[ string description = "Blend between the flake normals (0.0) and the surface normal (1.0)" ]],

output color NormalResult = 1.0,
output color ColorResult = 1.0,
output float alpha  = 1.0
)
{

float safe_flake_size_variance = clamp(flake_size_variance, 0.1, 1.0);

vector cellCenters[9] = {
vector( 0.5,  0.5,  0.0),
vector( 1.5,  0.5,  0.0),
vector( 1.5,  1.5,  0.0),
vector( 0.5,  1.5,  0.0),
vector(-0.5,  1.5,  0.0),
vector(-0.5,  0.5,  0.0),
vector(-0.5, -0.5,  0.0),
vector( 0.5, -0.5,  0.0),
vector( 1.5, -0.5,  0.0)
};

point position = vector(u, v, 0.0);
position = flake_scale * position;

point base = floor(position);

point nearestCell = point(0.0, 0.0, 1.0);
int nearestCellIndex = -1;
for(int cellIndex = 0; cellIndex < 9; ++cellIndex) {
point cellCenter = base + cellCenters[cellIndex];

vector centerOffset = cellnoise(cellCenter) * 2.0 - 1.0;
centerOffset[2] *= safe_flake_size_variance;
centerOffset = normalize(centerOffset);

cellCenter += 0.5 * centerOffset;

float cellDistance = distance(position, cellCenter);
if(cellDistance < flake_size && cellCenter[2] < nearestCell[2]) {
nearestCell = cellCenter;
nearestCellIndex = cellIndex;
}
}

NormalResult = color(0.5, 0.5, 1.0);
ColorResult = 0.0;
alpha = 0.0;

if (nearestCellIndex != -1) {
vector randomNormal = cellnoise(base + cellCenters[nearestCellIndex] + vector(0.0, 0.0, 1.5));
randomNormal = 2.0 * randomNormal - 1.0;
randomNormal = faceforward(randomNormal, I, randomNormal);
randomNormal = normalize(mix(randomNormal, vector(0.0, 0.0, 1.0), flake_normal_orientation));
ColorResult = color(cellnoise(base + cellCenters[nearestCellIndex]));
NormalResult = color(0.5*randomNormal[0]+0.5, 0.5*randomNormal[1]+0.5, randomNormal[2]);
alpha = 1.0;
}
}

Neat!! Need to test it out, currently no time but I do wanna see it in action ;) Thanks!

2020-01-25, 08:59:40
Reply #29

cjwidd

  • Active Users
  • **
  • Posts: 346
    • View Profile
    • Artstation
Hey Pokoy, this is a ton of work and I really appreciate it. I haven't had a chance to dig into your shader just yet, but thank you for taking the time to prepare an example. I will report back as soon as I've had the chance to explore it more thoroughly.