Hey to all,
I'm trying to create an Oren Nayar material like this:
https://lva.cg.tuwien.ac.at/cg1/wiki/doku.php?id=students:oren-nayar
But I'm running into some issues since I don't have any idea on the way certain functions are written.
For example, in the link, it says basically to Max and Min my alpha and beta functions, but I have no idea on how to do that in UDK.
Here is my current shader
http://www.mediafire.com/?ss209mm85pvlnce
It's abit of a mess, so I uploaded the UPK file, if anyone could lend me a hand in taming this beast, it would be super!
Replies
secondly you need to double check your bodmas . currently for A you've got (1 - 0.5) * x rather than 1 - (0.5x) which isnt the same thing at all. you also seem to have completely omitted the squared term from your roughness factor in both A and B.
as for your min and max question, it's as simple as comparing the two numbers and taking the higher or lower. ie use an if node and "if A > B then A, else B" would be the max(A,B). gets more complicated for more values of course but you've only got two here.
Lastly i guess my question is why are you trying to do this? unless i'm misunderstanding something the oren-nayar shading model is used to simulate a rough surface which is what a normal map does and which is almost certainly more accurate, controllable and more efficient?
make a custom node
return max(x,y)
gestalt, i don't understand what you mean. Oren-Nayar accounts for a specific case of retroreflection, it's a brdf and is thus bidirectional. It has little to do with fresnel or specular reflections on it's own, it's just a step in the right direction for diffuse interreflection behavior.
Edit: I looked at the link and I think the formula is wrong. It doesn't make sense that you'd go through the trouble of finding the max and min and then take the sin of both and not use them differently. I looked up the formula on wiki and it says tanβ and not sin.
OR you can get the arcosine by a 1/cos(x)
Gestalt: Neither will a lambertian diffuse. So what?
As far as aniostorpic effects, you can extend most specular models into anisotropic versions by splitting the reflectance vectors into parallel and perpendicular parts to your grain, and having separate coefficients for each.
http://www.cs.virginia.edu/~mjh7v/bib/Oren95.pdf
A good source for Oren-Nayar with descriptions, tests, logic behind it, etc.
http://graphics.stanford.edu/courses/cs448-05-winter/papers/nicodemus-brdf-nist.pdf
A good source of terminology, formulas, etc.
arcos(0.6) = 0.927
1/cos(0.6) = 1.212
the arcos of x should be thought of as "what do i have to cosine to get x" not "one minus" or "one divided by the cosine of x"
so you'll have to either use a custom node or rewrite your equation in terms of normal functions (sin cos tan).
The closest I can think of is a Transformed Normal Map, multiplied by the Light Vector and Lerped with a Fresnel and using a copy of the Diffuse as a the control in all cases with an added Color for tint.
Also, would like to thank all the peeps who helped me so far, but I think I will drop Oren for now, there is no way with my current abilities I would able to even get it working properly, so I think I will try hacky methods.
I've noticed the blue channel of the vectors appears to be the same as the dot product of the vectors with the normal. Does anyone know what the other channels (red and green) do for the light and camera vectors and if they'd be useful to find the angles the vectors make with the normals? If there is a way I'm missing to finding the angles please let me know.
As for the max and min I'm using the 'If' node.
I found this for arccos: http://wiki.beyondunreal.com/Legacy:Useful_Maths_Functions#arcCos_funtion
As for the Normals, I plug my Normal and Normal Map into a Lerp node and use a constant to control the harshness/softness of my normals, it could prove useful for the testing purposes.
Do I just put this as is into a custom node or is there some more setup to it?
edit: "I should really learn HLSL" - i was just thinking that this morning
The alpha/beta part of the function was precomputed and basically made into a texture 'look-up table'. This greatly reduced the instruction count and made it so that inverse trig functions weren't needed.
the second version from the link posted to start with seems to work alright though. the roughness definitely changes the falloff of the lighting although you can see where the two sin functions are interacting and creating banding, imo.
hope that helps people - i've learned something from doing it, although i dont really see that it's useful enough to go through all this hassle still! if you want to update it to use a normal map then i think you just have to replace all the 0,0,1 vectors with the normal map you want. i'd be interested to see some comparisons if people do use it at all.
cheers
I am this close |-| to learning Cg (with that new eat3d DVD) because I want to be all shader 1337.
You should totally get that DVD. It's very well-structured, and the various shader languages are quite similar, just some minor syntactical differences.
Also the packages here don't seem to show anything in my version of UDK, what release are you gents up to?
Further: I built up a functional oren-nayar model. And I learned to be VERY VERY careful about order of operations when dealing with UDK nodes. no sloppy nodeing. I lost a good half hour or more just because I effectively had a few parenthesis in the wrong places. ha! Harder to see with node connections.
also here's the HLSL code listing, which if you put in a custom node, will do nearly the same thing with a few more instructions due to lack of optimization. There is a difference in the look between code and node based, but I haven't isolated where or why its occurring. :shrug: it is rather minor.
edit:
Also here's an image.. see if the change is really worth the extra cost to you.
-I noticed you didn't Power your Roughness Parameter, I was wondering if this is necessary or not.
-I thought that Oren Nayar was limited to values of 1 and 0 for the Roughness, is that not the case?
-For the custom node in ArcCos, is it written like this: acos(x) ? Is it really that simple? Is it the same with the Custom Sin node?
-In the Formula, I noticed this part (which I still can't understand what it means); (...A+B* max(0,y) *sin(a)...)
Cheers and thanks for everyone for helping, much appreciated.
max(x, y) means take the larger value of the two.
In the case of max(0, y), it's basically keeping the expression to a minimum of 0 (ie, not negative).
-Roughness goes from 0 to infinity. But anything over 1 might not make sense.
-AVOID INVERSE TRIG. yes, that is how you do it (with all hlsl commands), but doing tan(acos(x)) and sin(acos(x)) is kind of terrible for performance and can be greatly simplified.
-Just saturate that (since it's in the range of 0 to 1).
I don't have udk installed but here is code for an exact solution without any trigonometric functions:
(rms = roughness, v = view/camera, n = normal, nv = n.v, nl = n.l)
edit: you don't even need a custom lighting model for this, just multiply your diffuse texture by abc before plugging it into the diffuse slot.
Edit: This could be helpful http://content.gpwiki.org/index.php/D3DBook:(Lighting)_Oren-Nayar
he also uses a lookup
Edit2: I just found this ( http://fgiesen.wordpress.com/2010/10/21/finish-your-derivations-please/ )which apparently gets rid of the need for the lookup.
Really? That's interesting, say, it wouldn't be possible with an Half-Lambert, would it? I mean the part about not needing a custom lighting.
Yes this can and should be simplified for realtime use.
As built this would not compile on SM2, and is expensive. It is built "by the book" for illustrative purposes mainly.
One could use texture lookups for the alpha and beta values, indeed my reference material did just that. Personally I feel it's a waste of a texture lookup unless you're using this model on many assets. it WILL reduce the instruction count.
No you do not need custom lighting for this. I've used multiple lighting models on a single physical model before and just plugged it into the diffuse slot. See the angel turnarounds on my youtube page. The lycra body suit is using a minnaert model. The lighting models effectively just create, well, areas of light and dark. You can combine them with arethmetic just like any other 0-1 value. I'm using custom lighting here, again primarily for illustrating the shader itself.
Not sure about udk's shading being off. It looks damn lambertian to me. What can be a factor is light intensities greater than 1. May wash stuff out, especially with simple shading models
Also yes the custom trig nodes are really that simple. Return Acos(IN); That's it.
Thanks for the link on the trig identity refresh. I can never keep those things memorized and it will help me with finishing up my Marschner hair shader implementation.
Which is what has been driving me mad, most tutorials show a basic setup which still mimics the same 'issues' found in the material, the ones that try something 'new' (like eat3D's Shader DVD) end creating a 100% transmission based material for the lambert, which is still wrong, unless you apply it on a sphere model or plan on faking a very bad SSS.
Also, Custom Materials in UDK still fight with Tanget Transform nodes, as well Transmission slots, it's pretty vexing, not to mention in some very finicky cases they break the Translucent material completely alongside the opacity, which is why I after my Oren Nayar and Half Lambert attempts, I'm trying to avoid custom materials in UDK.
Vailias: Ah thanks for the info, much appreciated!
Also what are you wanting to transform so much that you're having issues with? Do you need a lot of world space info things and vertex colors?
There are likely some solutions to what you're looking for, just depends on what approach need to be taken.
HSLS in 3DS Max by Ben Cloward (CG Academy) and ShaderCGFX for Maya (eat3D) go through such basics and almost always end up NOT translating well for UDK.
I was going to make a Strauss lighting model alongside Oren Nayar, but the fact that I was Transforming my Normal Map and Reflection nodes into a Transform - Tangent node which was creating a transmission effect because Tutorials X told me...well, lets say I'm not ready for any of that.
Straight hlsl stuff will require manually making all your data agree on the space it's in.
Glad you're trying more stuff though.
Seriously though, you may be better off with language reference than a tutorial. Search for HLSL on MSDN and you'll have a full function listing and syntax help etc.
Cg is a subset of hlsl. Meaning everything you can do with Cg can be done in hlsl and more. The syntax is Identical.
edit: ok quick thing to get you started.
UDK custom nodes are equivalent to an HLSL function.
The properties of the node are like its function name and associated variables. The return type, and variable types are set implicitly by UDK.
You will need to return a value manually from the custom node though. Just use a return statement
HLSL is a typed, curly bracket language. So you'll need to declare your variables.
numbers come in INT and FLOAT flavors.
Vectors come in FLOAT2, FLOAT3 and FLOAT4, for 2 3 and 4 component vectors.
Matrices can be declared, but in my experience UDK doesn't play nice with them.
So for the simplified c term, you'll need the Camera vector, normal vector, and light vector (or you could pass in the dot products as floats. Whatever.
it should look like this
@Computron I got and finished the dvd, and I thought it helped a lot so thanks!
@Vailias That quick step-by-step helped a lot actually (clarified things about input); I set up a custom node and got things working, but for this case it turns out I can do things without a custom. I finally go oren-nayar set and without custom nodes!
Personally I highly encourage you to reverse engineer a sample material that comes with your dcc app. Grab an hlsl reference to check what stuff is that you can't intuit.
And or slog through building your own blinn material.
Actually this reminds me. I wrote a tutorial like 5 years ago on doing just that. Here. It's at ga
http://www.gameartisans.org/forums/showthread.php?t=472
I found this free app called Paragraf for my iPhone earlier this week, it lets you write GLSL code and preview it instantly with hardware acceleration using the iPhone's camera as input for textures. Had some fun reverse engineering the provided examples.
My shader is also going to have vertex-painted water, a wet/raining variation and additional ice as well, all modifying the specular and reflectivity of the surface too, so I need to save instructions wherever possible really!
I found this shader recently which claims to use the Oren-Nayar model, I can indeed see similarities but it's much less expensive (and I assume, less accurate) than the versions posted and uses no HLSL. Anybody have any insight to offer on this?
http://oliverm-h.blogspot.co.uk/2012/02/how-to-use-oren-nayar-lighting-for-ue3_13.html
Edit: After building both versions, there is very little visual difference between the two with the added benefit of fewer instructions and no need for a custom lighting model.
Also, *Facepalm*, I noticed that the article links to the same simplification article that somebody else did earlier in the thread. I guess that just makes it all too easy for me!
One thing I am noticing however, I constantly have to clamp the output to prevent getting negative values at the materials master node, causing black spots. I guess it's good practice anyway, but is anybody the wiser about why this is?
I'm not sure where you mean you're getting negative values, but any dot product does range from -1 to +1. In some cases that doesn't matter, in others it may, and so you clamp it.
Also, why an oren-nayar. Do you need the extra soft look it can give or are you building it as an exercise?
You don't get that with the full ON math.
The negative values might just be something else, but I was getting both black and white artefacts in the resulting material. I must have forgotten to clamp something somewhere...
It's a bit of both really, I want to see if I can build one for real-time use that also has a lot of other functionality. I've also heard that it's notoriously good for rough surfaces. One of the surfaces in the game is one you'll be spending a lot of time around, so I figure I want to make it look as decent as possible, but at the same time not be a performance crusher.
Ideally then, I would want to use the custom lighting model only, not UDK's in-built Lambert shader as well (which surely, would also add instructions too?)
I'm still a little new to building shader models/materials, so pardon my ignorance all
Not sure if I understood correctly, but the lambertian term is part of the oren nayar formula. That's the only reason why it also works with MLM_Phong and not only a custom material.
With a roughness parameter of 0 the whole oren-nayar term equals to one so what's left is the simple lambert diffuse. In case of a master material + instances the roughness should be a scalar parameter so you can easily switch to lambert (and cut off the extra instructions) for less important models, LoDs etc.
I wasn't aware of such issues. Do you have any sreenshots at hand showing that problem?
if I plug anything into the 'Diffuse' slot on the master material node, I will get a Lambertian model applied to whatever is going into that node correct?
So if I plug the Oren-Nayar output into it, I get Oren-Nayar + Lambert. If I plug the Oren-Nayer into 'Custom Lighting' and 'Custom Diffuse', I get Oren-Nayar only?
Also, Oren-Nayar with a roughness of Zero is the same as Lambert, but more expensive.
Next challenge, Oren-Nayar Cook-Torrence.
It's an Oren Nayar issue me thinks, not your implantation, since from what I remember, the lite version of the code that is around the web cuts out the the direct falloff rate and only keeps the light/eye direct math, hence why any kind of SSS solution that could use Oren Nayar as it's lighting term will cancel itself out.
It's the exact same for me. I guess there has been done some optimizations for the material editor/shader compiler not that long ago. Using July 2012 build here cuts off all the extra instructions for a roughness of zero.
I observed a similar behaviour for different setups, e.g. zero specularity does not cause any additional instructions.
Good luck, though I guess you won't really need the full cook torrance functionality (it's quite heavy on instructions).