hey guys, over the last few days i've been working on this:
I'd love for people to play around with it and let me know what they think.
http://crazyferretstudios.com/public/PhysicallyBasedLighting.upk
The reason i made this was to get used to a newer way of working, with the industry moving toward a PBR setup, and very few tools out there to use.
To use this tool, there are two materials in the pack, the material itself, and an instance. please use the instance.
the maps you will need are:
Albedo - similar to the current diffuse model, except you just do colour, try not to include any lighting information at all. also, try your best to look up colour values for particular things, especially metals.
http://seblagarde.files.wordpress.com/2012/04/dontnodgraphicchartforblinnmicrofacet_lowres2.png?w=630&h=630]something like this should help
Mask texture - this texture has four grayscale maps, one in each channel, which are:
- R: Roughness - this defines the roughness of the material, 0 is not rough, 1 is super rough.
- G: Metalness - this defines whether the material is metallic or not. DO NOT USE GRAY VALUES. this map should either use black for not metal surfaces, or white for metal surfaces. example - if you have a painted metal surface with chips, the paint should be black and the chips should be white in this map.
- B: Emission - This map defines any surfaces which are emissive, it multiplies over your Albedo colour.
- A: Cavity - use this sparingly (there is also a parameter to increase/decrease cavity strength), can be used to remove lighting from cavity areas. could use a light AO map as well.
Normalmap - nothing special here.
Cubemap - you can use pre-filtered maps, or capture from inside UDK. you can use DX9 if you're using pre-filtered maps. if you're using UDK captured maps, please use DX11. there is a parameter for the number of mip-map levels your texture uses. the more the better. (usually 10 is max).
There are limitations with this shader however.
- Currently the image based lighting is using a hacky workaround and isn't true IBL. hopefully i can resolve this in the near future.
- Currently UDK doesn't support area lights that will be used in the future. i have no idea if it's even possible to program a new light type into udk.
- Currently UDK doesn't allow you to bake lightmaps from custom shader setups like this.
09:45 - 22/08/2013
just pushed a new version, fixing the following issue:
cubemap reflections weren't present in dielectric materials at all. they should be vaguely present.
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1.01.upk
11:02 - 25/08/2013
just found out that the above file didn't work. this one should!
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1_02.upk
03:26 - 27/08/2013
BIG OOOOOOOL' UPDATE!
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1_03.upk
Have just put in a basic layering system! you can now have four different material layers which can be defined in the following ways!
- Albedo Colour: choose your materials base albedo. use texture on/off set to 0.
- Albedo Texture: if you want your material to have a texture, put it here. use texture on/off set to 1.
- Metalness: is now a constant (not a mask/map) please use 0 for dielectric, and 1 for metals.
You now need two different mask textures. the first is the material mask, which works in the following ways:
R: Black = layer 1, White = layer 2.
G: Black = layers 1 + 2, White = layer 3.
B: Black = layers 1 + 2 + 3, White = layer 4.
think of it as building up from a base. if you were texturing a metal pipe made of copper, with black glossy paint, and a little surface rust. this would only require 3 layers. so you would start off with the copper, and mask that off with black in the red channel. then add surface rust in the second material, and mask that with white in the red channel. then add black gloss paint to the third material, and mask that with white in the green channel. you will need to do the same thing with normalmaps, although they share the same layer mask texture.
the second mask is roughness. you will need one roughness mask for each material.
R = material 1,
G = material 2,
B = material 3,
A = material 4.
IMPORTANT NOTE - due to feedback, roughness maps are now inverted, treat them the way you do with current gloss maps - black = rough, white = glossy.
there is a (very very basic and bad) set of example textures in the package to demonstrate. i only spent a couple of minutes making them.
this system should hoooopefully allow people to use tiled textures on the various channels and come up with some cool effects. it also allows you to choose whether or not you want to use a basic constant coloured material, or texture per material, or even mix between them.
current functionality removed:
emission, cavity map. these will be added in again soon when i can figure out an efficient way of doing it.
i'll make a good example asset and some maps over the next couple of days to demonstrate better, unless someone beats me to it!
cheers guys, have fun!
20:00 - 27/08/2013
LATEST RELEASEhttp://crazyferretstudios.com/public/PhysicallyBasedLighting_v1_04.upkUPDATE TIME!!!
00:08 - 27/09/2013
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1_05.zip
I STRONGLY RECOMMEND DELETING ALL PREVIOUS VERSIONS ENTIRELY.
this will stop any cross over between the shader functions, and hopefully minimize any errors. there are a lot of changes under the hood in this update, so this is the best course!
I've got good and bad news! i've managed to get IBL working the way the UE4 paper says they do, but it's WAY too intense for UDK. my rig is a beast, and it chugs so bad i had to abandon it. which means i need to figure out a better/cheaper way to do it... so here's hoping!
until i've figured that out, the IBL is in the emissive slot, along with your emissive map.
new features/functionality:
four materials to blend between. each material has it's own normalmap, and albedo slot. they also have a metalness and roughness parameter. simply slot in your albedo, tell it whether that material is metal (1) or not (0), and define how rough it is with the slider. if you want additional functionality, you could put metalness in the alpha channel of the albedo, which would allow you to have more detailed materials, but you would need to swap the alpha and the parameter around in the shader. you can also adjust how much each layer tiles with a parameter, each layer can tile separately from one another.
there is a texture slot in "Masks". this is your layer mask:
R - black = base layer, white = second layer.
G - black = combined first and second layer, white = third layer.
B - black = combined first second and third layers, white = fourth layer.
there are two "Global" map inputs:
Global Normals - here is where you put your models unique normals.
Roughness/Cavity/Emission - R = Roughness channel, again white is rough and black is glossy. G = Cavity, this multiplies lighting down globally, use this for very fine details you want to convey, things like cloth seams or similar. B = emission, multiplies over your albedo to give a coloured glow, there's an emissive parameter to strengthen this effect as desired.
there is a "Cube" input. this needs to be the T-shaped cube texture. you can generate one inside UDK if you need to. currently UDK doesn't support DDS textures, so no custom mip-maps just yet =[
enjoy!
Replies
I'll definitely take a crack at it when I get a chance.
FYI, the cube mips is set to 5 in the material instance, change that to 10 for a smoother transition between cubemap blurs.
edit: am aware of an issue where having lights too close to the object with the shader causes a strange artifact. working on a fix now.
I don't really have any close lights, but a dominant directional one.
please re-download the file, as i've just put in a fix that will stop you getting a horrible halo effect at angles away from a light source.
@Stromberg, i'm not sure what that is, other than it looks like some horrific compression... would you mind posting your source maps?
Here is the normal map.
and yes, UDK has shitty normal compression.
When removing the dominant directional light it gets a lot better.
I'll give it a go tonight if I have the time, thanks man.
Also, make sure if you're using a program like dDo2, you use high end texture, and not JPG, as the acne from compression will transfer to the normal map.
just realised that metallic specular isn't tinted by underlying colour. will fix asap.
I bake with max anti-aliasing(4x) in xNormal and always use .tga files, but I think it's mostly my own fault, it's not too bad when removing the sunlight in udk.
almighty_gir: that's good to hear
Anyway awesome work here!
Happens in both dx9 & dx11
And tried in both the feb&july2013 release (july being a fresh install on my c-drive).
edit: downloaded it again, and now it suddenly works
Just uploaded a new version, please redownload. this version has tinted specular for metals.
from now on i'll upload a new file with a unique version number.
@Stromberg, try setting the LOD group to UI as well, that forces it to import with the least compression.
@Esselle, in your mask texture, select the green channel, anything you want metallic paint pure white (255,255,255) with a 100% hard brush. anything you want non metallic, make black (0,0,0).
@joeriv, i created this with July 2013 version of UDK. is there any specific message it has other than "loading package PhysicallyBasedLighting"?
Yeah, this... i made it white for metallic, but the appearance of the surface, the diffuse in other models, is completely black
seems to be working okay for me... just to be sure, your mask texture looks like this?
thank you and sorry for the time wasted
be sure to download the newest version again if you haven't already.
cubemap reflections weren't present in dielectric materials at all. they should be vaguely present.
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1.01.upk
thinking of adding in a switch which will allow you to simulate HDR in non HDR cubemaps, if people think that would be useful.
Let's make an example:
I have a smooth titanium plate painted in red and it is scratched.
Albedo: painted surface - red albedo; scratches - titanium albedo.
Roughness: painted surface - black/gray (not rough); scratches - white (full roughness)
Metalness: is a painted metal metallic or not? And scratches? I guess both are metallic...
let me now if i am right
Painted stuff, unless its metallic paint = non metallic. Scratches = Metallic as its exposed metal.
read through this: http://www.polycount.com/forum/showthread.php?t=124683
I'm just curious, because the current system in the shader only works with mip map generation, which to my understand you don't have control of in UDK. Even with a prefiltered cubemap, there isn't anything in the shader that would tell it to be blend properly.
as for prefiltering cubemaps, you can do it with ATI's cubemap tools but they output to DDS, and i'm not sure you can easily convert to another format for UDK to read them.
that said, why work in dx9? the newest cryengine for example doesn't even support dx9. i doubt many new engines will.
First off, you're not using any specular maps. It's an interesting choice to pull from the diffuse. Out of curiosity, is there any reason behind that, other than to try and save on some memory? Typically PBR relies on a black (or almost black) diffuse for metal, with the specular defining the color value.
I've also noticed that how the material deals with roughness seems to be inverted.
Black should typically provide you with the blurred reflection, with white giving you a sharp reflection. I'm having the opposite occur. It's easy enough to change, just wanted to give you a heads up.
Aside from having non-photo real effects, things aren't really going to reflect the environment in a different color than they appear to be. (thin film and iridescent materials excluded, however just a metallic slider won't be physically based with those anyhow...)
On the roughness. Perhaps labeling it "smoothness" would help?
Fair point on the diffuse. That makes sense for a material that is completely metal, but if you have a texture with multiple material definitions, you'll need to have the differentiation, or some form of mask that you would then lerp in a color value from a constant 3. It is an interesting option, but I think you can forgo the mask texture, replace that with a spec with roughness in alpha, and you have the same amount of texture calls. To be fair, this does not include a cavity or emissive option, but that can easily be adjusted for as well. Worse case scenario, you're adding one more map but getting much better control.
As for roughness, I don't quite follow? Changing the name doesn't change how you interact with it. The reason being, I've worked on two engines that use PBL and both went from black (blurred) to white (sharp), not white (blurred) to black (sharp). The issue can't simply be fixed by inverting your maps or using OneMinuns, either, because the highlight will still be incorrect. It will change the area that is blurred, but the highlight will still be sharp and strong on the bumpy portion while large and weak on the smooth potion, if that makes sense.
so say you wanted gold, you put your gold colour in the albedo. then mask it as metal. the shader takes the gold colour and puts it into the specular, but turns the final albedo black for that masked area.
Ah, okay. That's pretty awesome actually. That's a pretty nifty workflow.
Any thoughts on the roughness being inverted (where black is getting the strong, smaller highlight with white getting a larger, broad highlight)?
I've tried to look at the equation and adjust it, but it isn't giving a correct result.
http://i.imgur.com/KFRAddl.png
add a "one-minus" node, and plug the R channel into it like this:
http://i.imgur.com/HWUNFUU.png
then plug that node into this constant clamp here:
http://i.imgur.com/SVayQov.png
and this multiply node here:
http://i.imgur.com/ZzXdEd2.png
So, according to metalness map, that can only be 0 or 1 (black or white), a mterial can only be metallic (black diffuse and cubemap) or dielectric (colored diffuse and no cubemap). But i didn't understand this... let's talk about a sign on can, a gloss paint, or a colored gloss plastic. They should be dielettric, but even if they have colored diffuse, they also have a cubemap reflection. Maybe the sign on the can is some sort of translucent paint that let light penetrate and let it interact with the metal, but a gloss not translucent paint or a gloss colored plastic, what kind of material is it?
In the UE4, for example, i guess it can be done with layered materials, a layer of gloss paint on a metallic material. Am i wrong?
In this shader i know it is nearly impossible, or anyway very difficult to create, but I also have seen that metallic characteristic in UE4 can be setted to any value between 0 - 1. So, shouldn't we have to use gray metallness map? I tried to set a gray metallicness and it works with no artifacts or some other errors, so i don't understand why the metallness mask has to be 0 or 1, no other values.
that issue should have been fixed in version 1.01, however there seems to be a bug with udk files, where if you rename the package to something else outside udk, udk won't load it properly. please use this file, it should work now:
http://crazyferretstudios.com/public/PhysicallyBasedLighting_v1_02.upk
to answer your other questions:
in UE4, they would have two materials, one for the paint, and one for the metal underneath, you would then mask on/off those materials to get your effect. my shader is a simplified version of that.
in my shader, you can also use gray for metalness if you want to. but that doesn't mean you should (and the only reason they do in the UE4 tech-paper, is to show the difference gradually). there are four semi-metals which exist in the real world, all of which have the reflectance qualities of actual metals. thse semi-metals are:
antimony
arsenic
grey-tin
graphite
so, because there is no material in the real world that has semi-metallic lighting properties, we should only use 0 or 1 for that setting.
The OneMinus trick does not work. I pointed out earlier that the issue behind is more systemic of how the system is interpreting the roughness map.
Right now, a value of zero will give you a sharp, clear highlight and will also use the highest quality cubemap (the non-mipped version).
This is, according to most PB shaders, incorrect. White, or a value of one, should give you a strong, small highlight and a clear cubemap. Black (zero) should give us a low mip cubemap and a soft specular highlight. Plugging in a OneMinus doesn't fix the issue because it just inverts the map, but not the equation. You could potentially put a OneMinus on the end of the Specular D part of the equation, but it will blow the material out (although maybe a constant clamp will fix that, I'll experiment with that).
The issue isn't in your Specular D equation, but I think it is coming in the Custom node right before it where you input Roughness and NdotH. I looked at the HLSL and I can't quite figure out what it is doing or where it came from (it's not in the UE4 paper most of your code is based off), but either way, the code is producing the opposite result of what you want.
Obviously, Roughness squared on its own also does not produce a good result, but the values are at least not inverted.