About Me

Hi. I'm Josh Ols. Lead Graphics Developer for RUST LTD.

Contact:
crunchy.bytes.blog[at]gmail[dot]com

View Joshua Ols's profile on LinkedIn

Meta

Entries in Demos (5)

Saturday
Jan192013

Museum of the Microstar Demo

Ladies and gentlemen...I give you Museum of the Microstar! Our entry into Unity3D's DX11 contest.

In it, you will find some crazy stuff including displacement tessellation, and compute shader driven particle systems. In particular, all materials in this demo utilize the latest and greatest version of my physically-based BRDF material shaders. They are all linear HDR compatible, have consistent visuals between forward and deferred mode, and integrate with Unity's baked lighting systems.

Follow the link and check it out! ;)

Saturday
Aug272011

Dice Poker Game (CANCELLED)

[Unity3D, RSRM] Dice Poker prototype

Unity3D Web Demo

Art and game behavior courtesy of Anton Hand.

 

Instructions:

Click ring to drop dice in box.

Click chips around box to chuck chips in center.

Click button in upper left to reset ring.

 

UPDATE:

This demo will only work for SM3.0 level GPUs. If you attempt to use it on an earlier generation GPU, you will just see black on all the geometry that is using the RSRM shader.

 

Situation:

If you were wondering why I haven't posted much lately then please allow me to fill you in on the details. Recently, I tried getting my Physically-Based Rendering (PBR) tech into Unity3D, with surprising success. Having gotten this working in a prototype, my artist friend set out to build a game using this new tech. Sadly, the project encountered some complications, and ultimately had to be cancelled.

 

Despite this, the prototype is in a state where the basic functionality is working. So I have decided to re-purpose it as a tech demo, which you can access via the above link. Please check it out and leave some feedback about the visuals in the comments section. ;)

 

Results:

The prototype shader used for this demo was single-pass forward rendered using two fake directional lights and a Radially Symmetric Reflection Map (RSRM). The scene itself also has SSAO, Bloom, and FXAA just to top it off.

 

The results are slightly incorrect due to my misunderstanding of the need to plug the BRDFs into the Punctual Light Equation and cancel some terms out. As a result, the specular ended up too bright, and fresnel for RSRM gives too much rim for rough surfaces. So while it is significantly better than the current standard of Phong & Blinn Phong lighting models, it still falls short of what I wanted to achieve.

 

Currently, I am working on an improved version that will correctly integrate with Unity3D's forward multipass lighting system. It will correctly accumulate the lighting in an FP16 target in linear space, then receive tonemapping before being passed to the rest of the pipeline. I will also being improving upon the built-in Bloom, SSAO, and Depth of Field effects to really sell the effect.

 

Keep your eyes peeled for future updates! ;)

 

Other Updates:

Other than this, I am currently working on a revised RSRM article, to centralize all I have learned in an easy to reference article. It will also detail the PBR BRDF I have chosen for my project, including strengths and weaknesses. Finally, this will provide a good opportunity for me to clear up some incomplete and flat out wrong information from my old articles.

 

Other than that, I've also made a small update to my Partial Derivative Normal Map (PDN) article. Basically, I found an optimization to use a MADD to save an assignment, shaving off another instruction from the recovery equations.

 

Hope you will find them useful. :)

Thursday
Sep302010

Cubism Demo & Source

UPDATE:
Had to briefly take down the code for some last minute modifications.

UPDATE2:

Demo is back up again. Sorry about the inconvenience.

Original:
Well people, it took longer than I'd like, but I'm ready to post an actual demo with source code. Following up on my Cubism prototype post, I have now released the completed demo on my website so that any interested parties may have a look. Just visit the new "Projects" link on the navigation bar at the top of the page.

Anyone who has questions/suggestions/etc, feel free to post in the comments section. ;)

Monday
Sep062010

Cubism & Framework

Up to this point, I have been taking an ad-hoc approach to my demo framework. Whenever I needed a feature, I just added it to the existing codebase. However, my code was reaching a point where it was becoming unpleasant to use, and difficult to upgrade. Finally, I hit my breaking point and decided my codebase needed a massive overhaul before I could continue with anything else. So refactoring everything has been occupying my time, in-between trying to find a job.

To test out my new framework, I decided to toss out all my old demo code and try something new. I wanted to go in a different direction with this one, opting for a test scene with lots of small lights, and a lot of moving elements. To that end, "Cubism" was born!

Reasoning:
"Cubism" was loosely inspired by the look of 3D Dot Game Heroes, and its impressive demonstration of pixelated voxel art. This approach seemed like a good way for me to introduce complexity, without having to commission an artist for a detailed animating object. However, this raised the problem that I am not myself an artist, and could only hope to do some kind of procedural programmer art. So it had to be visually interesting!

Content:
Deferred Rendering:
I decided to use Afterlights as my Deferred Rendering approach for this demo, because it is the simplest approach available. Also, I could get away with the lighting inaccuracies, since this demo isn't shooting for photorealistic graphics.

Scan:
This was meant to have a line of peaks going across a row, where each peak was unique to its column. This line would then scan to an end, then reverse direction to scan back to the other end. Since this is broken, I am going to try to implement a ripple effect instead.

Voxel Sprite:
This was made using an .xpm file included with in the compiled code. Every pixel is represented by a colored cube, with transparent pixels having no cube.

Ocean Waves:
This grid uses sin() functions to generate heights based on the cube's position in the grid.

Tidal Wave:
Similar to the Ocean Waves grid, but having waves without gaps.

Conclusion:

So that's it for now. This little project is far from finished, as it still needs a lot of work to clean up various hacks I used to get it running. Also, during the process of coding this demo I encountered problems with my new framework design that have forced me to rethink some of my decisions. Once I have finished revising both the demo and the framework, I hope to release their source code so that any interested parties may have a look. ;)

Anyone who has questions, feel free to comment or contact me via e-mail.

Sunday
Feb072010

Self-Shadowed Bump maps

UPDATE:
Something I thought I should mention that I realized only recently. In the section "Usage tips", I realized I was in error by saying that you need to swap the green & blue channels to make it work with RH normals. It is actually much simpler to swap the bottom two vectors in the basis in the shader to get the same effect at no extra cost. This way, you can use readily available tools, without any need to modify their output and introduce another step in the content creation pipeline.

Other than that, forget to mention the bonus pictures I added to the end of the post. Check them out, if you haven't already. ;)

UPDATE2:
SashaRX was asking about reflection vectors from an SS Bump map, so I thought I'd add it up here where everyone can see. Basically, all you need to do is get a tangent-space normal back, and then apply standard techniques from there. This is achieved by applying an inverse transformation to the SS Bump value using the basis vectors. Using just the basis vectors, the result will be in tangent-space. If you concatenate the tangent2world matrix with the basis vectors, you can transform staight to world-space.

Hope that helps. ;)

Code:
tanNormal = bumpBasis[0] * bump.x + bumpBasis[1] * bump.y + bumpBasis[2] * bump.z;
tanNormal = normalize(tanNormal);

Original:

For those who don't know, Self-Shadowed Bump maps were originally developed by Valve for use with their Radiosity Normal Mapping technology. After I decided to make the switch to a renderer built around pre-computed data, this was one of the first things I decided to try out. If you wish to read more about the technique, the following links have provided me with most of my information on the subject.

Links:

[1] Efficient Self-Shadowed Radiosity Normal Mapping

[2] Surface Detail Maps with Soft Self-Shadowing

[3] Half-Life 2 / Source Shading

[4] Shading in Valve's Source Engine

[5] SSBump Generator (used to make the maps)

 

Overview:

During the course of my experiments, I have verified all the benefits that Valve described in their papers. However, I have also discovered a few drawbacks that they didn't mention. Keeping that in mind, I have pooled and summarized my findings from all the papers and my own experiments.

Benefits:

  1. Directional Occlusion

  2. Correct filtering

  3. Detail mapping

  4. Recovers bent normals

  5. Better use of byte precision

  6. Faster than tangent-space normal maps

    • NOTE: Only for RNM, not for general diffuse lighting

Drawbacks:

  1. Diffuse Lighting expense

    • In order to get dynamic lighting with directional occlusion, each light direction has to be projected onto the basis. This boils down to the same amount of math as a 3x3 matrix multiply, per light direction.

  2. Poor compression

    • DXTC causes artifacts at detail edges, and nasty blocky artifacts in specular/reflection

    • RGB5 is acceptable for diffuse lighting, but produces banding for specular/reflections. Also, this format is not supported by Direct3D 10/Xbox 360.

 

Visuals:

height normalMapRH bumpRH ss bumpRH (SS Bump) recovered tangent (SS Bump) no DO SS Bump (bumped) (SS Bump) reflection

Figure 1. 1, Height map; 2, Normal map; 3, SS Bump (no DO); 4, SS Bump (DO); 5, recovered tangent normals; 6, no DO; 7, DO; 8, reflection

 

Masking:

(10) Red,  Right (11) Green, Upper Left (12) Blue, Lower Left (13) Right (14) Upper Left (15) Lower Left (16) Right (17) Upper Left (18) Lower Left

Figure 2. 1-3, RGB channels; 4-6, lightmaps w/o masks; 7-9, lightmaps masked

I added these images to help visualize how these maps just store multiplicative masks for the lightmaps. Note how sides facing the light direction receive almost no darkening, while those that are occluded are darkened to give the impression of shadowing.

 

Detail Mapping:

(SS Bump) enhanced detail (SS Bump) detailed (9) Recovered normal 17 - VTF 2010-02-24 01-46-50-17

Figure 3. 1, SS Bump map; 2, Detail map; 3, combined with SS Bump; 4, recovered normal; 5, diffuse lighting

This trick works since an SS Bump map is just a series of masks that get multiplied with the lightmaps. Since the lightmap data will be multiplied with the diffuse texture, we can effectively multiply the diffuse texture by the detail map if we just apply the detail map evenly to each color channel in the SS Bump map. This even weighting of each channel is what ensures that the recovered tangent normals are unaffected by the detail map.

 

Compression Artifacts:

(SS Bump) DXT1 (SS Bump) DXT1 diffuse (SS Bump) DXT1 reflection

Figure 4. 1, DXT1 SS Bump map; 2, diffuse lighting; 3, reflection


(SS Bump) RGB5 diffuse (SS Bump) RGB5 reflection

Figure 5. 1, RGB5 diffuse lighting; 2, reflection

 

Usage Tips:

Most tools that generate SS Bump maps will format them for the Source Engine, so they assume a left-handed coordinate system. This will cause issues with any programs that use a right-handed coordinate system. Fortunately, this issue can easily be fixed in a decent image editing program (Photoshop, Gimp, etc).

Tangent-Space normals:

Here, you just need to invert the contents of the green channel to flip the Y-axis.

normalMapLH normalMapRH

Figure 6. 1, normal LH; 2, normal RH

 

Self-Shadowed Bump maps:

Here, you have to swap the contents of the green and blue channels.

SS BumpLH ss bumpRH

Figure 7. 1, SS Bump LH; 2, SS Bump RH

 

Other than that, I thought I'd mention a problem I encountered while writing shader code to use these maps. The order of the bump basis vectors as Valve listed them in the paper can be a bit confusing, and will produce incorrect results that will have you scratching your head for days. To save you that trouble, here is how they should appear:

Code:

static half3 bumpBasis[3] =
{
    half3(sqrt(2.0) / sqrt(3.0),              0.0, 1.0 / sqrt(3.0)),
    half3(     -1.0 / sqrt(6.0),  1.0 / sqrt(2.0), 1.0 / sqrt(3.0)),
    half3(     -1.0 / sqrt(6.0), -1.0 / sqrt(2.0), 1.0 / sqrt(3.0))
};

 

Final Thoughts:

Despite the added storage and lighting cost, the benefits from using this technique are too enticing for me to pass up. So I have decided to integrate this technology into my new renderer for handling static objects. Dynamic objects, or anything that needs detail normal mapping, will still use Partial Derivative Normal maps for efficiency & flexibility. Between these two solutions, I should have a sufficiently versatile system for generating pleasing visuals.

 

Bonus:

Something I should have added a long time ago, there are two screenshots that have been sitting the in the comments section for some time now. They use a, SS Bump map from Valve's wiki, and really shows just how much depth this technology can add to even a flat surface. Check them out! ;)

(SS Bump) detailed 1(SS Bump) detailed 2

SS Bump map from Valve's wiki, "$ssbump"

Figure 8. 1, 0 degrees; 2, 90 degrees