Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved PBR resource pack support #78

Closed
Voxybuns opened this issue Aug 5, 2019 · 22 comments
Closed

Improved PBR resource pack support #78

Voxybuns opened this issue Aug 5, 2019 · 22 comments
Labels
enhancement Feature requests or new functionality suggestions
Milestone

Comments

@Voxybuns
Copy link

Voxybuns commented Aug 5, 2019

Currently, MCprep's shader graph only supports grayscale specular maps in resource packs, which are used as gloss maps. Other properties, like metalness and emission, are instead applied on a per-block basis, and make no use of texture maps.

In practice, this works fine for the vanilla textures and older packs, but this causes various issues when you try to use a resource pack designed for PBR-compatible shaders.

Admittedly, these issues are caused by the nonsensical way SEUS and other PBR-compatible shaders handle materials. In SEUS' case specifically, rather than providing separate textures for glossiness, metalness, and emission, they are all combined into a specular map using RGB channels.
It's a complete fustercluck and oh my god why why why

image

Because MCprep will treat it as a single texture, materials will be rendered incorrectly. In the examples above, the glowing lava from the magma block will instead look glossy, and the metal parts of the piston head will not benefit from metalness.

My proposal

In order to make full use of such PBR textures, the Separate RGB node could be used to redirect each channel to the appropriate material property. Since this setup is incompatible with traditional spec maps, this would be optional, the user choosing whichever solution is compatible with their resource pack of choice.

Now, I'm aware this is probably too much of a hassle for an issue that doesn't appear to be so bad, but I thought I'd give it a shot and suggest it. 😛

@TheDuckCow
Copy link
Member

Firstly, I just wanted to quickly respond to say:

  1. Thank you so much for pulling together this description and proposal
  2. Oh my god <re: why we can't have nice things, indeed>
  3. This also explains oddities which to me in the past, I dismissed as perhaps poor resource pack setups, since I was only viewing it from the blender perspective. I don't actually play Minecraft that much now, and don't have any such shaders installed to live test how it should look.

Will respond back more later, but I think this is feasible and the right direction - also good timing as I'm reconciling updates to enable texture pack swapping for Mineways and further naming convention compatibility. I think an option for the user to select the approach would be good, though I'll have to think hard about what the default should be (or if there's a way to intelligently detect).

Any chance you could share some examples of PBR packs that do use this SEUS-approach of RGB channel maps, and if you happen to know of other resource packs that do not use this approach (ie "normal" use of such maps). Would be good to help cross verify. If pretty much all packs that leverage additional passes beyond diffuse/albedo are using the SEUS approach, then that actually might make things simpler in a way.

@Voxybuns
Copy link
Author

Voxybuns commented Aug 6, 2019

Thank you for replying and showing interest in my suggestion!

I found some interesting tidbits on the texture documentation provided by Sonic Ether for his shaders.
They confirm that R handles gloss and G handles metalness, but it also says the B channel is unused, which is odd because that Vanilla Normals pack I've linked to you on Twitter makes use of it... It's giving me a headache. 🤪

I'll have to think hard about what the default should be (or if there's a way to intelligently detect).

Well, SEUS PTGI got quite a lot of attention lately, but on the other hand, non-PBR, lighter shaderpacks are also quite popular, so it's a tricky question indeed!

Any chance you could share some examples of PBR packs that do use this SEUS-approach of RGB channel maps, and if you happen to know of other resource packs that do not use this approach (ie "normal" use of such maps)

Here's a PBR-compatible pack that makes use of SEUS-style encoding.
And here's a non-PBR pack that uses grayscale spec maps.

And just to make your life even worse, I found out that there is yet another PBR texture encoding used by another shader pack, called Continuum. This one seems to use the blue channel for glossiness, and the red channel for metalness instead. See the demo pack they feature alongside their shaders. There aren't any emissive blocks in their pack yet, and I don't think there's any sort of documentation for texture artists so I don't know how they implemented it and if they implemented it at all.

UPDATE
Soooo... After asking Poudingue, the creator of the Vanilla Normals pack, it seems that yes, the blue channel must be used for emission by SEUS PTGI, but... well... he said he would soon switch ANOTHER format called lab-pbr, which is an initiative to create a PBR utopia with a single encoding system. However, it is a huge mess because it tries to cram in a ton of parameters into two textures. Take a look at the documentation, it's crazy. Hell, apparently normal maps need decoding because the AO map would be multiplied onto it. Crazy stuff. XD

I honestly don't know if this is even possible to handle in Blender, so I really hope this won't gain too much traction outside of this niche crowd, haha! It's probably better to keep it at the simpler support offered by SEUS and similar shaders.

@TheDuckCow
Copy link
Member

TheDuckCow commented Aug 11, 2019

Thanks for continuing to dig into this one! You're likely right that at a certain point, it won't be possible to keep up with the oddities of how each individual pack is setup, and thereafter I also don't want to be put in the position of needing to claim specific support for specific resource packs which could change at any moment.

Nonetheless, I think it's still worthwhile to categorize the "major" use cases, and at least provide out of the box examples for those:

  • Standard use case: ie spec map is just spec map, a true black and white map without hacking channels in any way (and normal map is normal)
  • SEUS Gloss/Metal/Emit: ie corresponding to the image you shared in the original post
  • ... others?
    • Edit: See where packs like Vanilla PBR, "Vanilla-Normals-Renewed"; as well as others I've tested against before (possibly incorrectly) like "S&K 64x PBR", "R3D 64x PBR", "PulchraPurePBR", and "BackyardCraft"

I will also call out though, you can do complex things with blender node shaders (teaser), so I have doubt that the decoding can certainly be done, even if at the level of implementing sequential math nodes. The question is more whether it's worth the time in implementing, and can be ensured to be up to date. Probably not, but I could hear it if people argued for it.

@Voxybuns
Copy link
Author

Yeah, I definitely spoke too soon about how incredibly complex shaders can get in Blender, haha!

To tackle the issue of use cases, along with those two presets you mentioned, maybe it'd be interesting to provide a way for the user to specify which RGB channel should be used for what property?

@TheDuckCow
Copy link
Member

TheDuckCow commented Aug 12, 2019

I think Arkam's razor (ie simpler = better) might be a good principle here, but open to input. My current thoughts:

  • In the swap textures/resource pack operator, create a sidebar dropdown set of the methods above (ie pick one of 2 or 3)
  • If they need to do more custom work, then they can do so by manually changing each material.. but then save this into a library INSIDE the folder of the extracted resource pack
  • Then, any future "prep materials" will then try first importing from this custom set of materials, for those that exist. (This is my "material sync" feature, work in progress).

So with this, at least the user has an avenue, per texture pack, of having hyper custom materials/tuning as needed, only needing to make the manual change once and not for each one. I'm tempted to create another operator that "synchronizes" materials to be the same, ie same node layout and other settings, but just the images swapped out as available. But even this I think starts to get a little too niche or managed, and is more defendable to just create the "sync material" button/mat prep option.

@Voxybuns
Copy link
Author

So people would be able to create their own material setup for each pack they'd import? That sounds neat!
I personally think that out of the box, SEUS PBR should be supported as I believe it to be the most publicized, PBR-compatible shader pack. Maybe non-PBR packs should be too?

I took a look at those pack you mentioned in your earlier reply. Vanilla PBR, Vanilla Normals, and the S&K and R3D PBR addons all use the SEUS encoding. BackyardCraft only provides normal maps, and I couldn't test PulchraPure as it is a paid pack.

@Voxybuns
Copy link
Author

Voxybuns commented Jan 2, 2020

Any updates? 😄

@TheDuckCow
Copy link
Member

Hi there! Thanks for poking me, it helps - haven't gotten to this yet, but remains probably the single most impactful thing I could do. Trying to address some other as-is bugs or troubleshooting support, then will try to finally tackle this. Let me know if you're will to be an alpha tester as I get closer to something functional!

@Voxybuns
Copy link
Author

Voxybuns commented Jan 8, 2020

That's totally understandable, gotta squish all those pesky bugs!

I'd love to test it out when you're ready to work on it!

@TheDuckCow
Copy link
Member

No new code developments yet, but recording this link for future reference. Seems like a good chance the outcome will be yet another format for pbr materials to detect and apply. The good news is arguably they are using the same approach for packing multiple pbr passes into the same image files, so the same node layouts can be used (perhaps just swapped links between the channel inputs). There is also a slight nuance of treating a normal map as such vs a heightmap (and requires looking at all the pixel data to affirm which to use).

@Voxybuns
Copy link
Author

No new code developments yet, but recording this link for future reference. Seems like a good chance the outcome will be yet another format for pbr materials to detect and apply. The good news is arguably they are using the same approach for packing multiple pbr passes into the same image files, so the same node layouts can be used (perhaps just swapped links between the channel inputs). There is also a slight nuance of treating a normal map as such vs a heightmap (and requires looking at all the pixel data to affirm which to use).

Yeah, RTX support is a thing now, although... Hmmm... Do you want to support that format too? It's not available for Java edition, only the Bedrock one. I don't even know if resource packs from that version are in the same format as the Java ones...

@ghost
Copy link

ghost commented May 14, 2020

This feature would be quite useful for me, as importing my PBR resource pack is not working so well and I have to manually adjust every block in the scene.

To add to the above, there are actually several different texture formats for MC being used right now. Here is a list of the ones I know of so far.

  • SEUS PBR (aka Old PBR)
  • labPBR
  • Specular (I do not know the name of this, but it uses a grayscale specular map for the specular value, this is currently being used in MCprep)

However, the new format developed by Nvidia will not work, as it is for the Bedrock Edition of Minecraft, and MCprep is designed to work with worlds from the Java Edition of Minecraft.

My suggestion would be to have only 3 types of generating materials in the generate.py script in the materials folder. Currently, there is matgen_cycles_principled, matgen_cycles_original, and matgen_cycles_emit. The new generating functions would be for each format of textures, such as matgen_seus, matgen_labPBR, and matgen_spec, and the function used would be decided by the user since there is no simple way to detect the different formats. In this case, only the matgen_spec function would need to support specific emission, since emission values in SEUS PBR and labPBR are stored in the texture. This could be done by passing an integer into the matgen_spec function, where 0 means no emission and 1 means full emission, thus 0 fully omitting the addition of an emissive shader mixing with the diffuse shader. The other PBR formats can have the emissive value as the factor between an emission shader using the texture as the color input and a diffuse shader.

Here is an example node setup for the SEUS PBR format. Note that special node-setups will need to be created for things like grass, water, and glass.
Screen Shot 2020-05-13 at 6 20 55 PM
If I have the time later, I'll try to create a PR with these new functions and support for the 3 texture formats listed above.

@TheDuckCow
Copy link
Member

Thanks for laying this out. Your image example for SEUS is great - any chance you'd be willing or able to share an example node layout that would be correct for labPBR?

As for incorporating the treatments, I'd like to make it flexible so that every new format doesn't lead to making an entire copy of the node layout generation, but only affect the relevant parts. This way we can use it with the non principled generator as well, to maintain support for older blender versions without making permutations with the PBR types. As such, it would be great if we could abstract the three methods into their own sub functions (SEUS, LabPBR, and Specular/current), where these functions only generate the nodes/links based on the minimum set of input nodes, while the rest of the material logic executes the same way regardless of which pbr option is set. Only difference is that if SEUS is selected, we must always use the emission layout (so we'll still only have an emit and non emit version). This avoids entirely copying logic - less code duplication, less likely to get out of date. I think a function with the signature below could be it, though it looks a little complicated and might not be comprehensive:

def pbr_cycles_seus(spec_img, diff_img, diff_socket, rough_socket, emission_factor, metallic):
    """Generates the pbr logic as per SEUS specification; inputs are references to sockets"""
   

def pbr_cycles_none(...):
    """Pass through, current behavior/case of non pbr selected"""

Thinking a bit further, maybe even simpler is to collapse the emit_cycles into both the principled and non principled generators, and just mute emit if no specular pass is detected & it's not a known emitting block. This way we have just two material generators (principled & non principled) and then three treatments of the pbr configuration. Open to thoughts!

@ghost
Copy link

ghost commented May 15, 2020

Ah, yes. I completely disregarded older Blender versions that do not have principled shaders. I'll look into different node setups for principled and non-principled alongside with the ones for labPBR and spec/current. labPBR is even more messy than SEUS, as it tries to incorporate porosity and different maps into one channel(why), so some logic would be required in the nodes. I will probably have this done in a few days.

The idea to have just principled and non-principled generators sounds great! However, muting the emission node would leave the texture half empty and half shaded, so we would also need to edit the mix shader node that mixes the shader and emission to have a default factor of 1 (or 0, depending on the nodes). This should quite easy to implement though, so not an important issue.

I'll take a deeper look into these things in a few days when I have more time.

@TheDuckCow
Copy link
Member

Thanks so much! Really appreciate the help. And indeed, we'd have to "tag" the mix shader to also be updated, but I'm okay with this because it'll be consistent between the principled and non principled setup I think.

@Voxybuns
Copy link
Author

However, muting the emission node would leave the texture half empty and half shaded, so we would also need to edit the mix shader node that mixes the shader and emission to have a default factor of 1 (or 0, depending on the nodes). This should quite easy to implement though, so not an important issue.

Wouldn't using an Add Shader node work in that case? I took on the habit of using that to mix emissions and principled shaders as it makes more sense to treat emission as an additive effect, unless it has a downside I'm not aware of. :P

@ghost
Copy link

ghost commented May 15, 2020

Technically, using an add shader is not physically correct, however, it does not make a large difference when using an emissive shader. When using an add shader, the light reflected back can be more than the light hitting the object. With an emissive shader, this happens anyways, so it does not make a big difference.

Mix:
mix
Add:
add

Even the positions of the fireflies are the same! The only difference to the eye is that the add shader has a very slightly smaller shadow than the mix shader, probably due to surfaces reflecting more light than given.

One last thought, should the addon tinker with the emissive brightness and light falloff? In some previous renders, I had issues where the light sources were much too weak since 1 square meter of colored light based on Minecraft's PBR textures will not go very far(about 1 meter). I thought of using a light path node to have a brighter source while keeping the image texture visible, however, exporting in an EXR format will reveal this clearly if the ground is brighter than the source. This method is being used in the current version of MCprep. Another solution would be to use linear light falloff, however, this is not physically correct. Open to thoughts on this!

(note: the images of the lamp above use a constant light falloff with a strength of 2, making the lamp colors appear to be white)

@Voxybuns
Copy link
Author

Yeah my untrained eye can't spot a single difference between the pictures. Looks like it could work, and it'd make it much simpler to just mute any emissivity in the graph.

@ghost
Copy link

ghost commented May 16, 2020

So from my understanding, using PBR or Specular resource packs will work as follows:

User Experience

  1. The user swaps the texture pack with a PBR or Specular one.
  2. The user selects between SEUS PBR, labPBR, or Specular near the prep materials button.
  3. The user selects between Principled(2.79 or later) or Non-Principled near the prep materials button.
  4. The user presses prep materials.

Script(when Prep Materials is executed)

  1. Looks for all textures on the selected object.
  2. Loops through all textures on the selected object.
  3. Replaces missing textures from the currently selected resource pack if necessary for each texture. (Next steps are assuming Eevee or Cycles)
  4. Generates shader node setup (Principled or Non-Principled) depending on user selection.
    a. Generates the node layout.
    b. Sets the default values for certain nodes.
  5. Generates texture format node setup (SEUS PBR, labPBR, or Specular) depending on user selection.
    a. Moves existing texture nodes to the correct positions.
    b. Generates the node layout.
    c. Mutes the unused nodes (if not already).
    d. Sets emission (only for Specular format, or for SEUS PBR and labPBR if no specular is defined) based on the block.
    e. Connects the correct outputs to the correct sockets on the shader nodes from step 4, which are defined from the input to the function. (Or, connect to labeled Reroute nodes generated with the shader nodes, to simplify things)
  6. Done!

Let me know if I interpreted something wrong from the conversation above. Note that I was able to omit the need for emission, as no emission input should default to no emission at all. We could pass an integer if needed on whether blocks should be lit or not (for specular, does not apply to SEUS and labPBR)

def pbr_cycles_seus(spec_img, diff_img, diff_socket, rough_socket, emission_factor, metallic):
"""Generates the pbr logic as per SEUS specification; inputs are references to sockets"""

Passing the sockets to connect would work, however, for the Non-Principled shader, there would need to be many sockets listed(see below). My suggestion would be to have the Principled and Non-Principled shaders generate Reroute nodes alongside them, and label them accordingly. This would allow the generate texture format function to search for the nodes from the passes attribute, and would not require all of the specific attributes to be passed to the function.

Setups so far (for future refrence)

Shader Node Setup

Principled

principled

Non-Principled

Haven't made one of these in a while!
non-principled

Texture Node Setup

Specular

specular_shader

SEUS PBR

seus_shader

labPBR

(In progress)

For future reference, I have labeled which nodes should be muted in order for it to correctly bypass, and the default values for some input sockets (we don't want blocks with no specular maps to appear shiny)

I am currently working on labPBR, as it requires a lot more logic to figure out.

@ghost ghost mentioned this issue May 28, 2020
10 tasks
@ghost
Copy link

ghost commented May 28, 2020

I have added basic SEUS support in #127. There are still many bugs, and I have only tested with Blender 2.82a on macOS 10.15.4.

If you want to try, you can clone and build the add-on from my fork under the dev branch. All you need to do is swap textures with a PBR pack, choose the proper format(see below), then use Prep Materials. Sometimes it does not work with existing models, so you must swap the texture pack again.
new

Notes

labPBR is still being worked on.

I was also able to bypass using reroute nodes by using a nested array.

Glass and water have custom shader setups, and are not finalized. The reason behind this is resource packs do not consider the rendering of glass and water, as that is up to the shader pack, meaning the add-on must provide a custom shader layout for each.

@TheDuckCow
Copy link
Member

Thanks again, and awesome progress. I also like the idea of providing more options around glass and water shading, and that makes sense what you say. I wonder if that should behave as a dropdown preset of options (e.g. water: vanilla, smooth reflective, semi transparent.. etc)? Or is it something we can infer from the pack itself?

Keep going as you are - but one thing I am thinking of, is whether we want to make the option for selecting the type of PBR more hidden, and only provide when needed. For instance: run prep materials, but if it detects that there are any normal/pbr maps, then offer the setting in the popup. Alternatively I might end up putting it under advanced settings.

Another alternative, is to cache some metadata next to the texturepack itself. That is, once you've swapped a texture pack once, subsequent times it'll use that same setting (but you could still have the option to change/overwrite in the operator popup or filebrowser selector view).

Nothing that needs to be finalized now as it's easily adjusted later. I'm also still pondering the idea of having "stacked/installed" texturepacks, in which case this would be a setting associated at the individual texturepack level (sort of the way you have multiple resource packs in the game, greedy applying the first pack with matching textures for a given block).

@TheDuckCow TheDuckCow added this to the v3.2.4 milestone Sep 23, 2020
@TheDuckCow
Copy link
Member

I'm going to mark this feature as "completed" for now, and leave future improvements to the issue tracker. @bytzo I think your account has been removed, but nonetheless thank you greatly for making this feature a reality!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Feature requests or new functionality suggestions
Projects
None yet
Development

No branches or pull requests

2 participants