Decal technique from Star Citizen

13456
polycounter lvl 4
Offline / Send Message
dzibarik polycounter lvl 4
I keep hearing around about the decal technique from Star Citizen but I can't find any solid info about it. Can somebody explain what is it?

Replies

  • Eric Chadwick
  • Obscura
    Online / Send Message
    Obscura polycounter
    Hi! If you take a look at the Gladiator Star Citizen art dump, and take a close look at the images, and view the materials (he is showing), you can see that there is one for their decals, and every other is a tiling material. These decals are stuff like screws, bolts, panel lines,texts etc. The technique was also used in Alien Isolation. In Star Citizen, due to the large scale, using full baking wouldn't work because of the needed resolution and complexity. Instead, they used "med poly" model, with a lot of chamfers, and custom vertex normals. On top of that, they placed many tiny planes, for every panel line, bolt and stuff. Sometimes they used decals on top of decals, for things like a button with a text on it. Some of them doesn't modify , just the normals. Some of them modify all the channels, including normals, albedo, roughness. They have their own decal material for that, I don't exactly know how that works, but it can be recreated relatively easily. I made some tests in UE4 with a technique, and it works fine. Here are some of my results. Probably the images explains what I did...
    This was the first test with 2 different modular decals...
    qMAUmgP.jpg
    The screw decal need to modify the normals around the screw, and every channel on the screw. For that, made the screw and bevel from highpoly, and baked down normals, and a mask for the screw. The button decal had to modify the normals around the button, and every channel on the button, plus it needed emissive. I did the same, I baked normals, and now 2 masks from a highpoly. Usually these decals doesn't require alpha, just a mask for blending the decal with the main material seamlessly. If it require it for some reason, then its always a masked blend (alpha test), so its fairly cheap. These are ok, but now you can ask how it can work seamlessly after you add some surface details into the maps... Well, after a bit of thinking, I came up with a tri-planar projection, in local space, so it can work regardless of rotation/position, plus it can project the textures seamlessly to the areas where you want to modify only the normals.
    Here is an image with more decals and decal types:
    HDuW99x.jpg
    It even works for panel lines, but sometimes it worth more to cut that into the topology.
    NgkYXi5.jpg

    And this is the setup of the local tri planar thing.
    F25tsNN.jpg

    You can see the actual examples and as it looks in the game in the Star Citizen art dump thread.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    This is great, thanks Obscura

    So if I understand correctly, you create the geometry you place the 'holders' for the decals onto the mesh as separate planes, and then map the decal texture onto that? Is the decal geo then coplanar with the surface of the parent mesh, or do you have to slightly offset to prevent zfighting? Haha maybe that's explained in the material setup you posted, but I'm not too technically oriented so I'm kinda lost in that regard.
  • Obscura
    Online / Send Message
    Obscura polycounter
    I just added a bit more info about blending...Unfortunately I can't upload images at the moment, but I will upload the full material a bit later. You can pretty much copy it...

    You need a little offset, yes, but not too much, cause then it would visibly offset, and "swim".
  • Eric Chadwick
    Are you using alpha test, or alpha blend?
  • Obscura
    Online / Send Message
    Obscura polycounter
    Usually there is no need for any transparency method. The tri planar projection can seamlessly project the main material onto the masked areas. I just do a lerp. If it require transparency for some reason, then an alpha test can work. Still, the projection solve it without transparency in the most of the cases. But that works only with tiling materials. But Star Citizen has mostly tiling materials on the ships, except the decals :D.
  • Eric Chadwick
    I meant with the decals. How are they blended with the main material?
  • Obscura
    Online / Send Message
    Obscura polycounter
    With a lerp. I simply sample the main material's textures in the decal's material(albedo,roughness, and a metalness parameter), and project them to the exact same place(tiling,shift) as where they are in the "main material". At the end, its like 5 textures. It still works with moving or rotated objects because the tiling textures are projected in local space. I'll upload an image from the full material setup a bit later. I'm having issues with uploading at imgur atm...
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    So if I wanted something like a panel line to encompass the circumference of an object, I would just copy out the ring/loop I want the panel break on, and then map that geo onto my 'decal atlas' ? Like this works with more than just things on a flat plane, right?
  • Obscura
    Online / Send Message
    Obscura polycounter
    Yes, exactly. You just need a small part of a panel line in your decal atlas. You can even change material, and do differently colored panel line on both sides. I did that with my example model, and thats require an extra edgeloop, and an extra drawcall, to change to the differently colored material "main material". But remember, the materials, except the decals need to be tileable because the projection works only then with my solution. So if you want panel line then you only need a normalmap of that in the decal atlas. A screw would require a mask too, for blending a metal material to the screw. A button with emissive would require one mask for masking the button, and one for the emissive. But these masks can be packed into channels for saving texture samplers.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Ok, so is the tri-planar projection rig for the purpose of propagating only normals down to the 'base texture' of the underlying mesh then? Sorry if thats a dumb question, like I said its easy for me to get lost when stuff gets too technical :P
  • Obscura
    Online / Send Message
    Obscura polycounter
    Yes, for projecting the base material to the areas, where you want to see only the normals of the decal. Also this is the reason for the no need of transparency.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Aahh ok, I get it now. Haha I would have assumed unreal had a material type that let you do that, i see now what you mean about the decal thing being more technical than it seems. But yeah, thanks a lot for building that set-up, I intend to play around with it in the next few days.
  • Obscura
    Online / Send Message
    Obscura polycounter
    The built in decal solutions in Unreal would be a pain to work with, with such amount of decals. Also, you can't use them in your modeling package, and you couldn't do things like panel lines with them.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Full material:
    mY997vV.jpg

    If you want albedo texture too, then you need the albedo texture parameter 3 times, and the same continue as what the roughness map has in my example (multiplies->adds->lerp), and you can connect the original tri-planar coordinates into them as uvs.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Awesome, thanks for sharing the full thing!
  • dzibarik
    Offline / Send Message
    dzibarik polycounter lvl 4
    I need to get my head around this setup. So far I can't understand it but thanks for detailed explanation, Obscura. I'm sure I'll get it in some time. Also I wonder if it is possible in Unity with its standard setup.
  • Obscura
    Online / Send Message
    Obscura polycounter
    I don't think. If there is a decal type that can modify only normals, or do both if needed, then you would get into the same case with the Unreal decals. Pain to work with, if you use many decals, and wouldn't work for complex shapes. Later today I'll upload a detailed tutorial about this, a similar one to the custom normals.
  • akaChris
    Offline / Send Message
    akaChris polycounter lvl 2
    this stuff sounds really intriguing! but it's still a bit puzzling to me from the example above. What I can't figure out is what you do to blend the decal material onto the base material without getting separate lighting for the decal element with lightmass. when I try this and bake lighting I get very bad results as it creates a shadow for the surface beneath the decal poly.
  • Obscura
    Online / Send Message
    Obscura polycounter
    This is not really a surprise, I thought this will happen with lightmaps, so I did it with dynamic lighting. The mentioned games also use dynamic lighting (I'm not sure about Alien Isolation, but I'll ask Marks).
  • marks
    Offline / Send Message
    marks polycounter lvl 9
    Yeah A:I had 100% dynamic lighting (well, maybe like 99% as there were some extremely huge exterior sections which we had to lightmap but they were very small proportion of the game). We used method whereby decals have 8-bit alpha mask and directly overwrite value in the gbuffer for that pixel - so we had decals which only affect normals to add indentations and such. I'm not sure if there is any info available online about this though.
  • radiancef0rge
    Offline / Send Message
    radiancef0rge Polycount Sponsor
    marks wrote: »
    Yeah A:I had 100% dynamic lighting (well, maybe like 99% as there were some extremely huge exterior sections which we had to lightmap but they were very small proportion of the game). We used method whereby decals have 8-bit alpha mask and directly overwrite value in the gbuffer for that pixel - so we had decals which only affect normals to add indentations and such. I'm not sure if there is any info available online about this though.

    this ^ is usually how its dealt with. aka gbuffer decals
  • leleuxart
    Offline / Send Message
    leleuxart polycounter lvl 5
    Obscura wrote: »
    I don't think. If there is a decal type that can modify only normals, or do both if needed, then you would get into the same case with the Unreal decals. Pain to work with, if you use many decals, and wouldn't work for complex shapes. Later today I'll upload a detailed tutorial about this, a similar one to the custom normals.

    It's been awhile since I've played around with it, but I'm pretty sure there is. At least, I know decals can support normal maps, so I feel like it should be possible. I know there's a checkbox in the material parameters that's off by default on masked materials that allows it to be affected by the dominant light.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Thanks for the info marks! Unfortunately there isn't anything about this on the web. I'm almost sure, this is the first article about it.


    Leleuxart - The "traditional decals" wouldn't allow you to make panel lines, and would be hard to work with. Maybe this new example explains why.

    Okay so Count Vader asked if I made this door with decals.

    DknmGCm.jpg

    Originally I didn't use decals, just support loops on this door, but I think it can be a great example for decals too, so I remade it with them.

    ypkG6vP.jpg

    This was the decal set that I used:
    IPsPJad.jpg

    And I baked normals, and a mask for being able to modify other maps other than the normals where I want.
    BMZU8Ac.png
    hs6x54J.png

    For saving texture samplers, I've put the decals into an atlas, and I used a material mask for the door itself, so it doesn't require an extra material for the color change.
    ZEPJWfk.jpg

    In Unreal I needed one material for the door, one for the decal that modify normal and other maps too, and 2 for the only normal modifier decals. 2, because they needed 2 different colors. So its 4 materials. But the second normal modifier was an instance of the first, with changed base color parameter. My material solution in Unreal doesn't use any transparency, just a lerp between the needed textures. You get them seamlessly, because of the projection.

    "main material":
    qc9UBPy.jpg

    normal modifier decal:
    MvjjOmb.jpg

    normal+color:
    MmcvjuY.jpg

    and here is the result:
    oiMIVMc.jpg
  • akaChris
    Offline / Send Message
    akaChris polycounter lvl 2
    awesome example and great result using this technique! I`m curious, are you skipping lightmass altogether then, using only dynamic lighting? I thought unreal would rely very heavily on lightmass for good interior lighting results. haven't gotten around to testing dynamic versus baked yet tho.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Yes, I completely disabled static lighting. For getting dynamic gi, you can use distance fields, or light propagation volumes, so you not must have to bake lightmaps for getting bounced light. Also, you can add fill lights, so you don't even need dynamic gi, but that would look better.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Haha, in another thread I actually brought up the whole lightmass/vs dynamic thing. Since this decals thing would be getting used with tiled textures, I was hoping to skip the unwrapping process altogether, and just have no light maps at all (only using box Uvw map modifier in max). It looks like I pretty much have to now, if the decals are gonna be all effed up from using shadow maps. I think that 'sci-fi bunk' scene by Liam Tart is all dynamic http://www.polycount.com/forum/showthread.php?t=137709 and the lighting looks pretty great in that.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Yeah, earlier I wasn't completely sure if it works with lightmaps or not, but not we see, it doesn't :D Anyways, you don't need uvs at all if you use the tri-planar projection, because thats basically a "box unwrap" but without seams... You need uvs only for the decals.
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Lol, bye bye light maps i guess

    In any case, door looks great with the decals. This question's sort of off topic, but how do you get that panel break strip to map onto the decal atlas and tile horizontally, since that bit doesn't span the entire width of the texture and it doesn't seem like you broke up the geometry on it and overlaid only over that specific part of the texture. Is this some method I don't know about ??

    ts7ZS4N.jpg
  • Obscura
    Online / Send Message
    Obscura polycounter
    This is how I mapped that part. Its not a problem if its mapped like this, because it won't change the albedo/roughness, because those gets projected with the tri-planar thing. Its only used for the normals and proper tangents. I did the same with the other panel lines too.
    KSz5sim.jpg
  • Count Vader
    Offline / Send Message
    Count Vader polycounter lvl 5
    Aah ok, make sense. So I guess if that panel line was affecting roughness or albedo, you'd be projecting it separately from the normals associated with it?
  • Obscura
    Online / Send Message
    Obscura polycounter
    Mmmm. I would say take a look at Tor's scene that you linked in your thread. But basically these decals could be even combines. I mean I could make a Cross shape with using the rectangle decals, and some extra edges/uv cuts. Shape doesn't matter, everything is up to your imagination, and how you can work with the decal's uvs+edges.
  • akaChris
    Offline / Send Message
    akaChris polycounter lvl 2
    I find it puzzling why this isn't possible with the deferred decal material domain within ue4 as this seems exactly whats needed for a clean solution utilizing d or g buffers. currently it appears when using deferred decal materials it seems to override texture coordinates and expect these from the deferred decal actor instead of using those provided by the mesh. I posted about it here: https://answers.unrealengine.com/questions/273215/deferred-decal-material-not-usable-without-actor.html

    maybe someone can shed some light on this...
  • Obscura
    Online / Send Message
    Obscura polycounter
    Okay, so I figured out I could use layered materials in Unreal, for ending up with one mat/one draw call, but the documentation is saying that maybe its better to use individual materials, If I don't need per pixel blending, which I can understand. The question is, which would result less heavy performance cost.

    An another solution I'm thinking on is to use vertex color markings, and use one, but a bit more complex material, with a "material selector" based on vertex coloring.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Actually this is just partly connected to the topic, and more related to the UE settings...But once you disable static lighting, you'll notice that your reflections gets also disabled. After a bit of digging, I found a solution, which gives them back. I really don't get why there isn't a button for this! So the only thing you need to do, is to put this line into the consolevariables.ini that you can find in the engine\config folder.

    r.DiffuseFromCaptures=1

    After adding this into it, the reflections will work with dynamic lighting.

    Also, you must need stationary light or static light to get anything into the reflection environment from the reflection captures.
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    Can someone explain how a Unity shader enabling this would work? Either a CG one or maybe a Shader Forge graph, no matter. I feel like I'm missing something because there is no existing system similar to UE4 material blending in Unity.

    There are existing examples of deferred decal implementations using Unity 5 Command Buffers feature, but those are an overkill and are a bit different - after all, we do not need anything like projection from box volume here, it's just a plain geometry. Only thing unusual about the required shader is the fact that it should write to the buffer instead of just being blended in. Existing deferred decal samples show that it's possible, but this new shader will probably be more simple than ones used in those decals.
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    Hell yeah, managed to get this working in Unity! Huge thanks to Dolkar and Marco Sperling for helping me with all the issues I have encountered along the way!

    Here is how it looks. I can separately control specular, smoothness, occlusion, cavity, normal and emission blending per decal material thanks to new Unity 5.2 feature called finalgbuffer. I use just one packed map in addition to the normal: albedo R + smoothness G + occlusion/cavity B + opacity A. So you can use this to add scratches through smoothness override, or add only slopes to lighting/reflections through normal override, or add only occlusion through occlusion override, and so on. It's not a semi-transparent forward shader, it's fully deferred, so it's performance friendly and properly lit both by all deferred lights and by GI system.

    g7bXkrJ.jpg
  • Kbrom12
    Offline / Send Message
    Kbrom12 polycounter lvl 7
    looks solid man, after doing that technique for more than a year myself I think ya did a great job
  • Obscura
    Online / Send Message
    Obscura polycounter
    Nice! :) Have you thought about including parallax mapping? Also are you planning to put this up into the asset store? Or want to share it for free?

    Anyways, my issue was the same as yours. There was no proper decal shader by default in UE for this, so this is why I came up with the own solution. I'll take a look again cause a few new versions came out now, and maybe there was a modification which allows to do it easier now.
  • cupsster
    Offline / Send Message
    cupsster polycounter lvl 7
    Good job, did you do edge chamfer on main geometry? These edges looks very nice and well defined!
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    Kbrom12 wrote: »
    looks solid man, after doing that technique for more than a year myself I think ya did a great job

    Thanks, it means a lot to hear this from you!
    Obscura wrote: »
    Nice! :) Have you thought about including parallax mapping? Also are you planning to put this up into the asset store? Or want to share it for free?

    Anyways, my issue was the same as yours. There was no proper decal shader by default in UE for this, so this is why I came up with the own solution. I'll take a look again cause a few new versions came out now, and maybe there was a modification which allows to do it easier now.

    Should be cheap and easy to include traditional parallax mapping (that is, UV distortion), yeah. Not sure what to use to drive it, though - I can't use normal map alpha because normals are compressed with DXTnm, and my main packed map is already using 4 channels for a variety of other things. Certainly won't include parallax occlusion mapping, though, that would be really expensive and messy.

    If you're curious, here is how my packed texture works.

    Here is the MainTex R channel, which is used in o.Albedo (not the greatest albedo depicted here, sorry - I know it should look different in PBR; and alternatively, I sometimes just use a solid color property):

    5qkRzC6m.png

    Here is the MainTex G channel, which is used in o.Smoothness (sometimes you only want your smoothness map to use values from e.g. 0.8 to 0.9 - that's all nice and dandy until you realize how bad that looks with compression artifacts - here, to use whole range of black to white values, I don't store smoothness explicitly and instead simply author a mask between low and high values, which are then separately configured in a material, as you can see):

    tFtgOztm.png

    Here is the MainTex B channel, which is used in o.Albedo and o. Occlusion (depending on the size of the decal or visual style of a game, it might be appropriate to output the ambient occlusion map either as true occlusion - only in o. Occlusion, where Unity lighting functions will use it to kill ambient - or as cavity - by multiplying it over albedo):

    4BaAXq1m.png

    Here is the MainTex A channel, which is used as an alpha mask:

    FpIWAEKm.png

    And finally, here is the normal map:

    XoqMOL1m.png

    As about the asset store, I'm not sure. Doesn't feel right to me to sell something that wouldn't have existed without this thread and without answers from some people on the Unity 3D forums. I put some hours into this, of course, but in the end, the shader is pretty simple and most of the reason this was never done before was lack of finalgbuffer function in Unity prior to 5.2, making it impossible to selectively blend GBuffer outputs.
    cupsster wrote: »
    Good job, did you do edge chamfer on main geometry? These edges looks very nice and well defined!

    When you go Star Citizen, you might as well go the full way! :D I used one smoothing group for the whole object, applied a simple chamfer along all edges and used the face weighted normal script from a recent thread about FWN. Vertex count is identical to the hard-edged model in the top right of my screenshot, so I get delicious looking shading and silhouettes for free, without any normal maps!

    gxPED7J.jpg
  • cupsster
    Offline / Send Message
    cupsster polycounter lvl 7
    Right, my initial feeling was right. I would go about that big, mostly flat surfaces same way. Need to look at that script. Might get handy on current project.
  • cupsster
    Offline / Send Message
    cupsster polycounter lvl 7
    Oh man, I was unaware of this new decal and finalgbuffer thing in unity. I'm still on 5.0.1 or something like that. This stuff should solve some things for me as well! Thank you. I found your unity forum and digging through it right now!
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    cupsster wrote: »
    Oh man, I was unaware of this new decal and finalgbuffer thing in unity. I'm still on 5.0.1 or something like that. This stuff should solve some things for me as well! Thank you. I found your unity forum and digging through it right now!
    If you're referring to deferred decal:add feature mentioned in Unity 5.2 release notes, I actually have no idea what that's supposed to be useful for. But finalgbuffer function is indeed an amazing addition.
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    nZkMbfF.gif

    This might not be new to people here, but it wasn't obvious to me. You can actually get completely smooth shading gradients between faces in curved quad strips if your mapping has no seams! I thought that wasn't possible, but proper mapping makes everything perfectly smooth.

    This allows you to drop huge circular decals completely, instead building them from quad strips mapped with linear texture areas. Huge possibilities with resolution, constant and crisp edges (no matter the angle, slopes stay aligned to pixel grid!). Nice :)
  • wirrexx
    Offline / Send Message
    wirrexx polycounter lvl 6
    Wow, this technique seems awesome unfortunatly i can't wrap my head around how you guys are doing it..
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    wirrexx wrote: »
    Wow, this technique seems awesome unfortunatly i can't wrap my head around how you guys are doing it..

    It's incredibly simple, just follow those steps :D
  • Obscura
    Online / Send Message
    Obscura polycounter
    Cool. I have a question about your implementation. In Star Citizen, and in my implementation, its possible to change material based on a mask. Like on this model, I added some button like objects, and around the button, I wanted the material of the door, and on the button, I wanted an another material. This was done with a mask to blend between the 2 materials. Its also possible to blend between more. On the first page, I'm showing a display model, and there are plastic buttons with emissibve line. There I used 3 materials. One around the button, one for the button, and a third emissive on the line. Is this possible with your shader?

    Material changes with masks
    Material changes with masks2

    As a side note, there is an another way too, but that works better when you have 2 panels next to each other, and you want to change material where they meet. This can be done with additional edge, and a +material there.

    Material change with extra edge
  • bac9-flcl
    Offline / Send Message
    bac9-flcl polycounter lvl 4
    Obscura wrote: »
    Cool. I have a question about your implementation. In Star Citizen, and in my implementation, its possible to change material based on a mask. Like on this model, I added some button like objects, and around the button, I wanted the material of the door, and on the button, I wanted an another material. This was done with a mask to blend between the 2 materials. Its also possible to blend between more. On the first page, I'm showing a display model, and there are plastic buttons with emissibve line. There I used 3 materials. One around the button, one for the button, and a third emissive on the line. Is this possible with your shader?

    Material changes with masks
    Material changes with masks2

    I am not sure how blending with the underlying surface works in your UE4 shader (i.e. whether it's an opaque shader that does no alpha blending and just outputs a result duplicating the underlying surface for areas with "One around the button" material; or whether you're doing proper alpha blending that requires no knowledge of an underlying surface), so I'm going to assume your shader is just traditionally alpha blended.

    The same end result is easily possible, yes, but I'm afraid that Unity and UE4 refer to very different things under the blanket of "material". In Unity, Material is a standalone asset that contains:
    • Reference to a shader
    • Texture reference fields fetched from that shader, either empty or filled with user-defined texture references
    • Value type fields fetched from that shader (numeric values and vectors/colors) filled either with default values specified in the shader or with user-defined values.

    Objects that have to be rendered with a surface shader have a Mesh Renderer component, which accepts a Material object reference (or multiple references, if mesh has a multi-mat setup with many IDs inside).

    Shaders, in their part, are ShaderLab code (pretty similar to HLSL, just wrapped with Material property definitions that can then be sampled and used in the shader code). Whatever you set in the Material object (normal map, metalness slider value, emission color etc.) is passed into the shader.

    There is a system similar to UE3/UE4 shader editor (called Shader Forge), but it simply allows you to automatically generate traditional vertex/fragment code with all the properties and attributes.

    This means that a shader or a material CAN NOT ever be an input to another material. It's not a value, it's not a vector, it's not a map, you can not sample something like this.

    You can easily make a decal shader that will use a mask to output different albedo/spec/smoothness/emission based on mask factor. But you can not create a field for that shader that will accept another Material with another shader (with an opaque surface shader configured with maps for plastic, for example).

    If you want to mix tiled maps in a decal instead of authoring one composite map for the decal, you can do that, but setup will be different to UE4. You will have to cram all properties of all blending participants into the decal shader, like this:
    • Albedo map A
    • Albedo map B
    • Normal map A
    • Normal map B
    • Specular map A
    • Specular map B
    • Occlusion map A
    • Occlusion map B
    • Emission intensity A
    • Emission intensity B
    • Emission color A
    • Emission color B
    • And so on and so on

    And then you'll have to manually plug every map and manually type in every value into the Material of a decal using that shader, and then your shader will do simple interpolation:
    o.Albedo = lerp (_AlbedoMapA, _AlbedoMapB, _MaskValue);
    

    This is pretty inconvenient and will waste insane number of texture samplers. You can, of course, do some packing, like I love to do.
    • Map 1: Dielectric albedo/metallic specular (RGB)
    • Map 2: Metalness (R) + Smoothness (G) + Emission (B) + Occlusion (A)

    Then you'll just have to plug four maps into a Material for 2-way-mixing decal shader (in addition to decal specific maps like mask and alpha). This will be pretty performant, although still maybe a bit inconvenient to set up.

    You can, of course, write a custom shader inspector UI for your decal shader (inspectors are simple classes using Editor UI, so they can be completely replaced), which will have input fields for Material objects, but will internally grab actual references to stuff like maps from referenced materials, and will slot them into numerous properties of the decal shader. Extremely user-friendly. I prefer to keep all actual inputs of the shader visible tho.

    Another thing, if you have something very, very exotic going on in the surfaces you want to blend (for example, one of them is not physically correct), you can also move all shader code required to get that unique color right into your decal shader. That makes your shader very inflexible (it will be Decal Shader 35: Mixing Weirdly Bright Cartoony Material With A Normal Physically Based Material) but keeps it performant.
    float3 weirdCartoonyColor = [huge function getting it]
    o.Albedo = lerp (_PBRMaterialAlbedo, weirdCartoonyColor, _MaskValue;
    

    Finally, you can make a multi-pass shader that will just completely duplicate the shader code of first surface type, then second surface type, and then will blend the results of both together. Easiest to write, and that's what I suspect UE4 is generating internally when you use another material/shader as input (I might be mistaken, though). But this is not really very nice performance wise, so I'd prefer to never do that. Especially since 99.99% of all surface types you likely want to blend are traditional physically based things, so you'll just go through identical code three times.

    So, in the end, I prefer to just author the final content of the decal directly. I make a normal map, an albedo map and a smoothness/metalness/emission/occlusion packed map with plastic, aluminum, floating glass, wood and whatever other surfaces I need in my floaters, and use them in a neat and short decal shader with just three of those inputs. Do you really need to reuse a the same mask for different materials, anyway? A high-tech circular seam with some vent cutouts works on plastic but won't work on marble, so it makes sense to just author some completely unique decal maps for marble instead of devising an approach using material blending.

    I'm also using some tricks to speed up the setup: for example, I do not use an explicit smoothness map in my shader - instead, I author a minimum to maximum smoothnness mask using whole 0-255 range of a packed map channel, and then use a value sampled from it to lerp between two freely configured smoothness inputs from the Material. That way, if I want to tweak the smoothness of exposed edges or fade the seam innards a bit, all I have to do is to drag min/max sliders a bit - no need to open PS and modify any maps.
    Obscura wrote: »
    As a side note, there is an another way too, but that works better when you have 2 panels next to each other, and you want to change material where they meet. This can be done with additional edge, and a +material there.

    Material change with extra edge

    I have two approaches to this. First one is pretty obvious, yeah - using a multi-material setup with many tiled materials. Then it's very easy to do sharp edges (optionally covered with seam decals etc.).

    If I do not want a perfectly sharp edge, though, I have another approach. I use VertexPaint modifier in 3ds to transfer all diffuse color from multi-material setup into vertex colors, and then bake the resulting vertex colors into UV2 space. As I'm likely using one UV2 map anyway (for per-object ambient occlusion), I'm already using a texture sampler for that, so I might as well cram RGB material color or single-channel material mask into a UV2 map for free. That's what I used in the wall panel screenshot above - red/gray/yellow segments used a baked UV2 color map.

    The benefit of this second approach is obvious - you get the underlying surface with just one draw call.
  • Obscura
    Online / Send Message
    Obscura polycounter
    Wow, thanks for the explanation. I didn't use alpha blend nor alpha test. It was something like the lerp you mentioned. In unreal, you can use "layered materials", which is also a kind of lerp, but it allows you to blend between materials. I was planning to update my materials to use this, but actually I left this project for some time. I think I'll get back to it when I'll have time, and check the options for Gbuffer solutions, and also the layered material thing.
13456
Sign In or Register to comment.