Secrets of CryENGINE 3 Graphics Technology


Published on

In this talk, the authors will describe an overview of a different method for deferred lighting approach used in CryENGINE 3, along with an in-depth description of the many techniques used. Original file and videos at

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Show intro video
  • Extensive tests for all platforms, many combos researched. From interleaved lighting storage, RG11B10 and other formats, diferent space storage (like inv exponential or sRGB), diferent encoding types. Simplest solutions turned out the most efficient, cleanest, most robust and general ones. Slim G-Buffer A8B8G8R8 Normals + glossiness Readback D24S8 Depth + stencil magic 2x A2B10G10R10F_EDRAM for Diffuse and Specular buffers X360: No FP10 tex format, resolved to A2B10G10R10 instead (XDK) PS3: 2x A8B8G8R8 encoded in RGBK Encoding <=> No HW blending possible. Workaround: r/w from dst RT A2B10G10R10F_EDRAM for scene target PC: A16B16G16R16F PS3: A8B8G8R8 RGBK encoded for opaque, FP16 for transparents
  • Add GI [7] (add blend) Apply SSDO (mul blend) and RLR (alpha blend) Add light sources Normalized Blinn-Phong For C2, only projectors and point lights Limited shadow casters count on consoles - go bananas on PC Resolve/restore requirement for Xbox 360 Lights rendering depends on couple heuristics FS quads with stencil volumes pre-passes: for global lights or when viewer is inside of light source Else convex light volumes or even 2D quads + depth bounds when coverage not significant Light frustum volumes are reconstructed in vertex shader Special geometry of tessellated unit cubes and frustum projection matrix
  • Base idea: reuse diffuse lighting accumulation No redundant work as in vanila UV space approach Concept also expandeable to UV space approach Aproximate Sub-Surface Scattering in screen space Poisson distribution for taps, straighforward bilateral blur using depth for discarding samples. Best bits: No aditional memory requirements for atlas Cost proportional to screen area coverage VS fixed cost per surface update Plus Zcull is your biggest friend. What happens when a face covers entire screen? Exactly. Sharing is the keyword here
  • Super simple trick/approximation. Ray cast along screen space light vector Have macro self-shadowing details, even on consoles Important visual hint, visible at diferent distances Cost proportional to how big surface gets on screen Unless a cutscene, its very rare Used for skin, hair and eyes
  • The usual alpha blending troubles issues: fog volumes, shadows, sorting, refraction. Efficient hair rendering is a pain on this HW generation Hair is a particular case of alpha blending, albeit a very important case for characters look Avoid it ? Alpha test looks very circa 1999 ATOC doens’t look so good and requires HW MSAA One solution: smooth hair geometry along screen space tangent vector Cost proportional to how big geometry on screen
  • Re-projection + velocity buffer We got rid of our old approach of using the sphere around camera approach has it mainly worked for camera rotations For static geometry, straighforward to compute how much a pixel moved compared to previous frame, by using depth and previous view projection matrix can compute previous frame pixel location and compute delta (velocity) to current frame. Handle dynamic geometry by outputting velocity Full resolution means at least ~3 ms spent. Not much can do for speeding up (for worst case scenario) Use half resolution instead Inspired by KZ2 approach [5] To save BW, we ended up storing 2 rgba8 targets – one rgbk encoded with final result, and the other with the composition mask. On pc just straighforward FP16, with mask on alpha Object velocity buffer dilation Avoid unpleasant sharp silhouettes -> Dilate slightly velocity buffer Done on the fly, on same pass as when applying motion blur Good enough and no aditional passes/resolves Do it in HDR, before Tone Mapping Physically correctness Bright streaks are kept and propagated [1] Looks great on bright particles For console specs we used 9 taps and clamping to a maximum range to avoid noticeable undersampling. PC hi specs, 24 taps.
  • Just another blur kernel Taps offsets are Disk shaped Kernel size scaled based on Circle of Confusion term Reused same 9 taps for consoles. 24 taps for higher pc specs
  • Go Bananas: Render a Quad/Sprite per pixel Scale quads by CoC factor Accumulate results into intermediate targets Sort Quads by layers: Front/Back Alpha stores quad count Dithering to minimize noticeable precision loss Composite with final scene Divide layers result by layer alpha Quality can’t get better than this (and slower!) And slower.. > 100 ms for large defocus at 1080p 
  • Video
  • Video
  • Idea is simply to extrude quads along motion direction Waiting for hardware to catch up
  • Particularly important for deferred lighting.. Can minimize light range clipping (notice brights highlights being clipped by dark alpha blended surface) or any alpha blending case on top of bright surface, like decals, fog volumes, darker smoke particles and such. Minimize precision artefacts on darker regions of image. Allows for physically based post processes – Motion Blur, Depth of Field (and others) should be done before tone mapping. This final image would be almost impossible to achieve in LDR. And most importantly, it improves the art workflow significantly – as it minimizes the amount of time artists have to waste workaround such issues on more old fashioned engines. Linear Correctness All math in linear space: L inear space lighting, Linear correct blending Used HW sRGB Precision!
  • Code for computing of VPos basis for position reconstruction cam is view camera camMatrix is simple camera’s orientation ortho-normal matrix. vStereoShift is shift for computing reconstruction for the stereo rendering (we use Off-Center perspective projection) mShadowTexGen – can represent any kind of homogeneous transformation or be Identity matrix
  • Can’t afford on consoles each light casting shadows Clip Boxes / Volumes Tool for lighting artists to eliminate light bleeding Artist created convex volumes + regular types ( Cone, boxes, etc)
  • Secrets of CryENGINE 3 Graphics Technology

    1. 2. Secrets of CryENGINE 3 Graphics Technology <ul><li>Contents: </li></ul><ul><ul><li>Rendering Pipeline </li></ul></ul><ul><ul><li>Position Reconstruction </li></ul></ul><ul><ul><li>Coverage Buffer </li></ul></ul><ul><ul><li>Deferred Lighting </li></ul></ul><ul><ul><li>Shadows </li></ul></ul><ul><ul><li>Screen Space Techniques </li></ul></ul><ul><ul><li>Deferred Techniques </li></ul></ul><ul><ul><li>Batched HDR Post Processing </li></ul></ul><ul><ul><li>Stereo Rendering </li></ul></ul>
    2. 3. Secrets of CryENGINE 3 Graphics Technology Nickolay Kasyan Nicolas Schulz Tiago Sousa Senior Graphics Engineer Senior Graphics Engineer Principal Graphics Engineer Crytek
    3. 4. <ul><ul><li>Linear Correct HDR Rendering [Gritz 2008] [Reinhard 2010] </li></ul></ul><ul><ul><li>Minimal G-Buffer: Depth and Normals </li></ul></ul><ul><ul><li>Opaque, decals, def. decals,terrain layers </li></ul></ul><ul><li>Deferred Lighting </li></ul><ul><ul><li>Ambient, env. lighting probes </li></ul></ul><ul><ul><li>GI, SSDO, RLR, Lights </li></ul></ul><ul><ul><li>Physically based shading </li></ul></ul><ul><li>Opaque / Transparent passes </li></ul><ul><li>HDR / LDR Posts </li></ul>Physically Based Rendering
    4. 5. <ul><ul><li>Slim G-Buffer </li></ul></ul><ul><ul><ul><li>A8B8G8R8 World Space BF Normals + Glossiness </li></ul></ul></ul><ul><ul><ul><li>Readback D24S8 Depth + Stencil bits for tagging indoor surfaces </li></ul></ul></ul><ul><ul><li>2x A2B10G10R10F_EDRAM for Diffuse and Specular buffers </li></ul></ul><ul><ul><ul><li>X360: Resolved to A2B10G10R10 [Cook 2008] </li></ul></ul></ul><ul><ul><ul><li>PS3: 2x A8B8G8R8 encoded in RGBM </li></ul></ul></ul><ul><ul><ul><ul><li>Encoding <=> No HW blending possible. Workaround: r/w from dst RT </li></ul></ul></ul></ul><ul><ul><ul><li>PC: 2x A16B16G16R16F (most general format) </li></ul></ul></ul><ul><ul><li>A2B10G10R10F_EDRAM for scene target </li></ul></ul><ul><ul><ul><li>PS3: A8B8G8R8 RGBM encoded for opaque, FP16 for transparents </li></ul></ul></ul><ul><ul><ul><li>PC: A16B16G16R16F </li></ul></ul></ul>G-Buffer/L-Buffers/Scene Targets
    5. 6. <ul><ul><li>Hyperbolic distribution </li></ul></ul><ul><ul><ul><li>Needs conversion to linear space before using in shaders </li></ul></ul></ul><ul><ul><li>Problem: First person view objects </li></ul></ul><ul><ul><ul><li>Depth buffer is used to prevent overlapping FPV objects with the rest of the scene </li></ul></ul></ul><ul><ul><ul><li>Different FOV and near/far plane (art specific choice) </li></ul></ul></ul><ul><ul><ul><li>Different depth range to prevent actual overlapping </li></ul></ul></ul><ul><ul><ul><li>=> Deferred techniques don’t work 100% for such objects </li></ul></ul></ul>Z-Buffer Depth Caveats <ul><ul><ul><li>//Constants </li></ul></ul></ul><ul><ul><ul><li>g_ ProjRatio.xy = float2 ( zfar / (zfar-znear), znear / (znear-zfar) ); </li></ul></ul></ul><ul><ul><ul><li>//HLSL function </li></ul></ul></ul><ul><ul><ul><li>float GetLinearDepth( float fDevDepth) </li></ul></ul></ul><ul><ul><ul><li>{ return g_ProjRatio.y/(fDevDepth-g_ProjRatio.x);} </li></ul></ul></ul>
    6. 7. <ul><ul><li>Our final solution: </li></ul></ul><ul><ul><ul><li>Modifying depth reconstruction function </li></ul></ul></ul><ul><ul><ul><li>Convert hardware depth to linear one </li></ul></ul></ul><ul><ul><ul><li>Different depth scale for first person view object </li></ul></ul></ul><ul><ul><ul><li>Selecting based on depth </li></ul></ul></ul>Addressing First Person View Objects <ul><li>float GetLinearDepth( float fDevDepth) { </li></ul><ul><ul><li> float bNearDepth = step (fDevDepth, g_PS_DepthRangeThreshold); </li></ul></ul><ul><ul><li> float2 ProjRatio.xy = lerp (g_PS_ProjRatio.xy, g_PS_NearestScaled.xy, bNearDepth); </li></ul></ul><ul><ul><li> return ProjRatio.y/(fDevDepth-ProjRatio.x); </li></ul></ul><ul><ul><li>} </li></ul></ul>
    7. 8. <ul><ul><li>Idea: linearly transform VPOS from screen space S directly to target homogeneous space W (shadow space or world space) </li></ul></ul><ul><ul><li>Direct transformation from screen clip space to homogeneous matrix </li></ul></ul><ul><ul><li>VPOS is simplest way to render deferred light volumes </li></ul></ul><ul><ul><li>Separate adjustment for s3D </li></ul></ul>Reconstructing Position from Depth <ul><ul><li>Geometrical Meaning of Reconstruction </li></ul></ul>X = vStoWBasisX Y = vStoWBasisY Z = vStoWBasisZ <ul><ul><li>float4 HPos = (vStoWBasisZ + (vStoWBasisX*VPos.x)+(vStoWBasisY*VPos.y) ) * fSceneDepth; </li></ul></ul><ul><ul><li>HPos += vCamPos.xyzw; </li></ul></ul>
    8. 9. Coverage Buffer <ul><li>Mostly outdoors for Crysis2 </li></ul><ul><ul><li>Approximately 70% </li></ul></ul><ul><ul><li>Portals or PVS not efficient there </li></ul></ul><ul><li>Coverage Buffer as main occlusion culling system </li></ul><ul><ul><li>Essentially low resolution depth buffer </li></ul></ul><ul><ul><li>Coarse CPU rasterization of object AABBs/OBBs for visibility z-tests </li></ul></ul><ul><li>Too slow to prepare fully detailed C-Buffer on CPU </li></ul><ul><ul><li>Huge computation cost </li></ul></ul><ul><ul><li>Full rendering pipeline has to be duplicated in software to obtain all details for C-Buffer </li></ul></ul>
    9. 10. Coverage Buffer <ul><li>Read-back of previous frame’s GPU depth buffer on CPU </li></ul><ul><ul><li>Downscaling ZBuffer on GPU (max filter) after G-Buffer pass </li></ul></ul><ul><ul><li>Culling done by rasterizing BBoxes in a separate CPU thread </li></ul></ul>Original: 1920x1080 Downscaled: 256x128
    10. 11. Coverage Buffer <ul><li>Used on X360/PS3 and DX11 HW </li></ul><ul><ul><li>Consoles perfect for this (1 frame latency) </li></ul></ul><ul><ul><li>Read-back latency on PC is higher but still acceptable (up to 4 frames) </li></ul></ul><ul><ul><li>C-Buffer size limited to 256x128 in Crysis 2 on consoles </li></ul></ul><ul><ul><li>Problem: Mismatch between previous/current frame cameras </li></ul></ul><ul><ul><ul><li>Results in wrong visibility tests </li></ul></ul></ul>
    11. 12. Coverage Buffer Reprojection <ul><li>Ended up using C-Buffer CPU reprojection from prev. frame camera </li></ul><ul><ul><li>Point splatting of reprojected fragments </li></ul></ul><ul><ul><li>Camera info is encoded into the c-buffer data </li></ul></ul><ul><li>CPU readback and reprojection in separate thread </li></ul><ul><ul><li>~2ms on SPU, ~3-4ms on Xbox 360 with vectorized code </li></ul></ul><ul><li>Stitching of holes inside C-Buffer after reprojection </li></ul><ul><ul><li>3x3 dilation pass </li></ul></ul><ul><ul><li>Remaining C-Buffer holes: we assume objects are visible </li></ul></ul><ul><li>Reprojection improved culling efficiency greatly </li></ul><ul><ul><li>Solved all kind of occlusion test artifacts, detected invalid areas </li></ul></ul><ul><ul><li>Works more efficiently with higher framerate </li></ul></ul>Remaining C-Buffer holes after reprojection
    12. 13. <ul><ul><li>Outdoor / Indoor </li></ul></ul><ul><ul><ul><li>Stencil tagged regions in G-Buffer passes </li></ul></ul></ul><ul><ul><ul><li>FS Quad and indoor volume BBox </li></ul></ul></ul><ul><ul><ul><li>Additive blended </li></ul></ul></ul>Deferred Lighting: Ambient
    13. 14. <ul><ul><li>Accurate diffuse lighting and specular lighting </li></ul></ul><ul><ul><ul><li>Artist pick important sampling locations </li></ul></ul></ul><ul><ul><ul><li>HDR encoded (RGBM) </li></ul></ul></ul><ul><ul><ul><li>Linear blending for diffuse and specular cube map </li></ul></ul></ul><ul><ul><ul><li>Spherical light volume </li></ul></ul></ul><ul><ul><li>G-Buffer material glossiness used for picking mip level </li></ul></ul><ul><ul><ul><li>Consistent specular behaviour between IBL and regular lights </li></ul></ul></ul><ul><ul><li>Alpha blended passes? Pick nearest probe </li></ul></ul>Deferred Lighting: Environment Probes
    14. 15. Deferred Lighting: Environment Probes
    15. 16. <ul><ul><li>Add GI [Kaplanyan 2010] (add blend) </li></ul></ul><ul><ul><li>Apply SSDO (mul blend) and RLR (alpha blend) </li></ul></ul><ul><ul><li>Add light sources </li></ul></ul><ul><ul><ul><li>Lights rendering depends on screen coverage heuristics </li></ul></ul></ul><ul><ul><ul><ul><li>FS quads with stencil volumes pre-passes, convex light volumes or 2D quads </li></ul></ul></ul></ul><ul><ul><ul><li>Normalized Blinn-Phong [Hoffman 2010] </li></ul></ul></ul><ul><ul><ul><li>For C2, only projectors and point lights </li></ul></ul></ul><ul><ul><ul><li>Limited shadow casters count on consoles - go bananas on PC </li></ul></ul></ul>Deferred Lighting: GI, SSDO, RLR, Lights
    16. 17. Shadows
    17. 18. <ul><li>Shadow mask for sun </li></ul><ul><ul><li>Special render target to accumulate shadow occlusion </li></ul></ul><ul><ul><li>Shadow mask combines multiple shadowing technique on top on each other before using with actual shading </li></ul></ul><ul><li>Point light shadows rendered directly to the light buffer </li></ul>Deferred Shadows 10+ shadow casting lights Sun shadow mask
    18. 19. Cascaded Shadows Maps <ul><li>Cascaded shadow maps used since Crysis 1 </li></ul><ul><li>Cascades Splitting Scheme </li></ul><ul><ul><li>Approximate Logarithmic texel density distribution </li></ul></ul><ul><ul><li>Shadow frustums adjusted to cover camera view frustum conservatively </li></ul></ul><ul><ul><li>Orientation for shadow frustums is fixed in world space </li></ul></ul><ul><li>More cascades allow </li></ul><ul><ul><li>Improved texel density, reduced acne and improved self-shadowing for wider shadow range due to better approximation of the logarithmical distribution </li></ul></ul><ul><li>For each cascade snap the shadow frustum to the SM’s texel grid </li></ul>
    19. 20. <ul><ul><li>Shadow passes for cascades/point lights rendered in deferred way </li></ul></ul><ul><ul><li>Potential shadow receiving areas tagged in stencil buffer by rendering frustum volumes </li></ul></ul><ul><ul><ul><li>Allows to have more sophisticated splitting into cascade </li></ul></ul></ul><ul><ul><ul><li>Pick a cascade with the highest resolution in overlapping regions </li></ul></ul></ul><ul><ul><ul><li>Avoids wasting of shadow map space </li></ul></ul></ul>Deferred Shadow Passes
    20. 21. <ul><ul><li>Not all the cascades are updated during a single frame </li></ul></ul><ul><ul><li>Update cost distributed across several frames </li></ul></ul><ul><ul><li>Performance reasons (PS3 particularly) </li></ul></ul><ul><li>Allows us to have more cascades – better shadow map density distribution </li></ul><ul><li>Cached Shadow Maps use cached Shadow Matrices </li></ul><ul><li>Distant cascades are updated less frequently </li></ul><ul><li>Last cascade uses VSM and blends additively with the shadow mask </li></ul><ul><ul><li>Allows to have large penumbras from huge distant objects </li></ul></ul>Shadow Cascades Caching
    21. 22. <ul><ul><li>We always split omni-directional lights into six independent projectors </li></ul></ul><ul><ul><li>Shadow map for each projector is scaled separately </li></ul></ul><ul><ul><ul><li>Based on the shadow projection coverage </li></ul></ul></ul><ul><ul><ul><li>Final scale is a result of logarithmic shadow map density distribution function, which uses the coverage as a parameter </li></ul></ul></ul><ul><ul><li>Big texture atlas to pack all shadow maps each frame after scaling </li></ul></ul><ul><ul><ul><li>Texture atlas is allocated permanently to avoid memory fragmentation </li></ul></ul></ul><ul><ul><ul><li>Size on consoles: 1024x1024 (4 MB) </li></ul></ul></ul><ul><ul><li>Receiving area tagged by stencil </li></ul></ul>Point Light Shadows Shadow atlas
    22. 23. Soft Shadows Approximation
    23. 24. Soft Shadows Approximation <ul><ul><li>We use Poisson PCF taps with randomized rotations in shadow space </li></ul></ul><ul><li>Adjusting the kernel size at runtime allows to have a good approximation of soft shadows with variable penumbra </li></ul><ul><li>Soft shadows idea: Estimate average distance ratio to shadow casters </li></ul><ul><ul><li>Similar to Percentage-Closer Soft Shadows [Randima2005] </li></ul></ul>
    24. 25. <ul><ul><li>Basic Algorithm: </li></ul></ul><ul><ul><ul><li>Poisson distributed taps are presorted by distance from the kernel center </li></ul></ul></ul><ul><ul><ul><li>Initial kernel radius set to match maximum range (= biggest/longest penumbra) </li></ul></ul></ul><ul><ul><ul><li>Use this kernel to estimate the average distance ratio </li></ul></ul></ul><ul><ul><ul><li>The number of samples is reduced proportionally to the avg. distance ratio </li></ul></ul></ul><ul><ul><ul><ul><li>This affects the radius of the kernel since the taps are sorted </li></ul></ul></ul></ul><ul><ul><ul><li>Use only the reduced number of samples for final shadow computation </li></ul></ul></ul><ul><ul><li>Cascade shadow maps need custom kernel scale adjustment to handle transitions between cascades </li></ul></ul><ul><ul><li>Compute Shader option: fetch all taps to CS shared memory and reuse them for both distance estimation and shadow computation </li></ul></ul>Soft Shadows Approximation
    25. 26. <ul><ul><li>For alpha blended shadow receivers </li></ul></ul><ul><ul><ul><li>Forward passes to apply shadows </li></ul></ul></ul><ul><ul><li>For transparent shadow casters we accumulate the alpha values of the casters </li></ul></ul><ul><ul><ul><li>Stored in 8-bit render target </li></ul></ul></ul>Shadows & Transparency
    26. 27. <ul><ul><li>Translucency map generation: </li></ul></ul><ul><ul><ul><li>Depth testing using depth buffer from regular opaque shadow map to avoid back projection/leaking </li></ul></ul></ul><ul><ul><ul><li>Alpha blended shadow generation pass to accumulate translucency alpha (sorted back to front) </li></ul></ul></ul><ul><ul><ul><li>In case of cascaded shadow maps, generate translucency map for each cascade </li></ul></ul></ul><ul><ul><ul><li>Shadow terms from shadow map and translucency map are both combined during deferred shadow passes with max() operation </li></ul></ul></ul>Shadows & Transparency
    27. 28. Shadows Video
    28. 29. Real Time Local Reflections
    29. 30. <ul><ul><li>Reflections are expensive with rasterization </li></ul></ul><ul><ul><ul><li>Usually planar reflections or cubemaps </li></ul></ul></ul><ul><ul><ul><li>Require re-rendering of scene </li></ul></ul></ul><ul><ul><li>Standard reflections limited </li></ul></ul><ul><ul><ul><li>Either planar surface </li></ul></ul></ul><ul><ul><ul><li>Tiny area for cube maps </li></ul></ul></ul><ul><ul><ul><li>Usually no curved surfaces </li></ul></ul></ul><ul><ul><li>Reflections straightforward with raytracing </li></ul></ul><ul><ul><ul><li>Raytracing in screen space to approximate local reflections </li></ul></ul></ul><ul><ul><ul><li>First iteration was demonstrated at GDC 09 </li></ul></ul></ul>Real Time Local Reflections
    30. 31. <ul><ul><li>Basic Algorithm </li></ul></ul><ul><ul><ul><li>Compute reflection vector for each pixel </li></ul></ul></ul><ul><ul><ul><ul><li>Uses deferred normal and depth targets </li></ul></ul></ul></ul><ul><ul><ul><li>Raymarch along reflection vector </li></ul></ul></ul><ul><ul><ul><li>Sample depth and check if ray depth is within threshold to scene depth </li></ul></ul></ul><ul><ul><ul><li>If hit, reproject into framebuffer of previous frame and sample color </li></ul></ul></ul><ul><ul><li>Results </li></ul></ul><ul><ul><ul><li>Relatively cheap </li></ul></ul></ul><ul><ul><ul><li>Local reflections everywhere (even on complex surfaces) </li></ul></ul></ul><ul><ul><ul><li>Very cool where it works  </li></ul></ul></ul><ul><ul><ul><li>Plenty of problematic cases due to limited data in screen space </li></ul></ul></ul>Real Time Local Reflections (RLR)
    31. 32. <ul><ul><li>Implementation Tips </li></ul></ul><ul><ul><ul><li>Very limited screen space data </li></ul></ul></ul><ul><ul><ul><ul><li>Rather no reflections than broken looking ones </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Smoothly fade out if reflection vector faces viewer as no data is available in that case </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Smoothly fade out reflection samples at screen edges </li></ul></ul></ul></ul><ul><ul><ul><li>Add jittering to step size to hide noticeable step artifacts </li></ul></ul></ul><ul><ul><ul><li>HDR color target sampled in Crysis 2 </li></ul></ul></ul><ul><ul><ul><li>Jitter or blur based on surface glossiness </li></ul></ul></ul>Real Time Local Reflections (RLR)
    32. 33. <ul><ul><li>Core idea same as SSDO [Ritschel 2010] </li></ul></ul><ul><ul><ul><li>Modulate lighting with computed screen space occlusion </li></ul></ul></ul><ul><ul><ul><li>Produces soft contact shadows </li></ul></ul></ul><ul><ul><ul><li>Can also hide shadow bias issues </li></ul></ul></ul><ul><ul><ul><li>Considerable quality gain over just SSAO </li></ul></ul></ul><ul><ul><li>However, directional occlusion info accessible in a deferred way </li></ul></ul><ul><ul><ul><li>Fits better into existing lighting pipeline </li></ul></ul></ul><ul><ul><ul><li>Can be applied efficiently to every light source </li></ul></ul></ul>Contact Shadows
    33. 34. Contact Shadows
    34. 35. <ul><ul><li>Occlusion info generation </li></ul></ul><ul><ul><ul><li>Compute and store bent normal N' during SSAO pass </li></ul></ul></ul><ul><ul><ul><ul><li>Bent normal is average unoccluded direction </li></ul></ul></ul></ul><ul><ul><ul><li>Requires clean SSAO without any self-occlusion and relatively wide radius </li></ul></ul></ul><ul><ul><li>For each light </li></ul></ul><ul><ul><ul><li>Compute N dot L as usual </li></ul></ul></ul><ul><ul><ul><li>Compute N' dot L </li></ul></ul></ul><ul><ul><ul><li>Attenuate lighting by occlusion amount multiplied with clamped difference between the two dot products </li></ul></ul></ul>Contact Shadows
    35. 36. <ul><ul><li>Main Idea: Reuse diffuse lighting accumulation </li></ul></ul><ul><ul><ul><li>Proof of concept since beginning of project (early 2008) </li></ul></ul></ul><ul><ul><li>Subsurface scattering in screen space </li></ul></ul><ul><ul><ul><li>Gather lighting taps during geometry pass </li></ul></ul></ul><ul><ul><ul><li>Used a Poisson distribution </li></ul></ul></ul><ul><ul><li>Best bits </li></ul></ul><ul><ul><ul><li>No additional memory requirements for atlas </li></ul></ul></ul><ul><ul><ul><li>No redundant work </li></ul></ul></ul><ul><ul><ul><li>Concept expandable to UV space [Borshukov 2001] </li></ul></ul></ul><ul><ul><ul><li>Cost proportional to screen area coverage </li></ul></ul></ul>Deferred Skin Shading <ul><ul><li>Head model courtesy of Infinite-Realities </li></ul></ul>
    36. 37. <ul><ul><li>Couldn’t afford per-character shadow map (memory) </li></ul></ul><ul><ul><ul><li>How to workaround lack of memory on consoles ? </li></ul></ul></ul><ul><ul><li>Simple trick/approximation </li></ul></ul><ul><ul><ul><li>Ray march along screen space light vector </li></ul></ul></ul><ul><ul><ul><li>Macro self-shadowing details for all characters, even on consoles </li></ul></ul></ul>Screen Space Self-Shadowing
    37. 38. <ul><ul><li>Efficient hair rendering is a pain on this hardware generation </li></ul></ul><ul><ul><li>Robust solutions: </li></ul></ul><ul><ul><ul><li>Alpha test looks very 1999. >= 4x SSAA ? Not yet for consumer HW </li></ul></ul></ul><ul><ul><ul><li>ATOC doesn’t look so good and requires hardware MSAA </li></ul></ul></ul><ul><ul><ul><li>Stippling + filtering ? Kind of works, but half res’ish look </li></ul></ul></ul><ul><ul><li>Idea: Post process for anti-aliasing the alpha test look </li></ul></ul><ul><ul><ul><li>Another oldie from beginning of project (early 2008) </li></ul></ul></ul><ul><ul><ul><li>Directional blur (8 taps) along Tangent vector in Screen Space </li></ul></ul></ul><ul><ul><ul><li>Visual hint for transparency and smooth hair look </li></ul></ul></ul><ul><ul><ul><li>Additional Hair geometry pass </li></ul></ul></ul><ul><ul><li>Fur rendering? Directional blur along Normal vector in SS </li></ul></ul>Soft Alpha-Test
    38. 39. Soft Alpha-Test
    39. 40. Batched HDR Post Processing
    40. 41. <ul><ul><li>Re-projection for static + velocity buffer for dynamic obj. </li></ul></ul><ul><ul><ul><li>Full resolution means at least ~3 ms spent (consoles) </li></ul></ul></ul><ul><ul><li>Half resolution and RGBM encoded </li></ul></ul><ul><ul><ul><li>Total 16 x less BW versus full res and fat formats </li></ul></ul></ul><ul><ul><li>Composition mask for blending with full resolution </li></ul></ul><ul><ul><li>Object velocity buffer dilation [Sousa 2008] on the fly </li></ul></ul><ul><ul><li>All done in linear space before tone mapping </li></ul></ul><ul><ul><ul><li>Bright streaks are kept and propagated [Debevec 1998] </li></ul></ul></ul><ul><ul><ul><li>Consoles: 9 taps; PCs higher specs: 24 taps </li></ul></ul></ul>Camera & Object Motion Blur
    41. 42. Camera & Object Motion Blur Camera & Objects V RT1:Composite Mask RT0: Blurred Target (RGBM) Half-Res linear input (RGBM)
    42. 43. Bokeh DOF: Another Kernel and Weights CoC Half-Res linear input (RGBM) RT1:Composite Mask RT0: Blurred Target (RGBM)
    43. 44. <ul><ul><li>It’s just a blur we really want </li></ul></ul><ul><ul><ul><li>How to reuse all taps/bw, share all gpu work ? </li></ul></ul></ul><ul><ul><li>Idea: Offsets morphing based on blur type </li></ul></ul><ul><ul><ul><li>Camera/Objects moving? Directional versus disk kernel </li></ul></ul></ul><ul><ul><ul><li>More uses: masked blur, radial blur, etc </li></ul></ul></ul><ul><ul><li>Final composite done directly in tone mapping pass </li></ul></ul><ul><ul><li>1 ms on consoles. Super fast on PC at 1080p </li></ul></ul><ul><ul><ul><li>Almost 10x faster than doing all posts individually (at fullres) </li></ul></ul></ul>Maximum Batching
    44. 45. <ul><ul><li>Single pass at full screen resolution </li></ul></ul><ul><ul><ul><li>12 taps + clamp maximum range to limit undersampling </li></ul></ul></ul><ul><ul><ul><li>Alpha channel stores objects ID </li></ul></ul></ul><ul><ul><li>Blur masking scheme based on velocity and ID </li></ul></ul><ul><ul><ul><li>||V|| > threshold ? Allow bleeding, else reject tap </li></ul></ul></ul><ul><ul><ul><li>Early out if ||V|| < threshold </li></ul></ul></ul>Ultra Specs: Motion Blur
    45. 46. <ul><ul><li>Go Bananas: Render a Quad/Sprite per pixel [Cyril 2005] </li></ul></ul><ul><ul><ul><li>GS to scale quads by CoC factor </li></ul></ul></ul><ul><ul><li>Accumulate results into Foreground/Background targets </li></ul></ul><ul><ul><ul><li>Masking by sorting quads per layers </li></ul></ul></ul><ul><ul><ul><li>Alpha channel stores quad count </li></ul></ul></ul><ul><ul><ul><li>Dithering to minimize precision loss </li></ul></ul></ul><ul><ul><li>Composite with final scene </li></ul></ul><ul><ul><ul><li>Divide layers result by layer alpha </li></ul></ul></ul><ul><ul><li>Great Quality ! (but very slow) </li></ul></ul>Ultra Specs: Bokeh DOF
    46. 47. <ul><ul><li>Making it fast </li></ul></ul><ul><ul><ul><li>Render Half Res </li></ul></ul></ul><ul><ul><ul><li>Reject Quads in interleaved pattern </li></ul></ul></ul><ul><ul><ul><li>Early out for VS/PS </li></ul></ul></ul><ul><ul><ul><li>Spherical aperture using ALU </li></ul></ul></ul><ul><ul><ul><li>Future: avoid geometry shader usage </li></ul></ul></ul><ul><ul><li>Composite with final scene </li></ul></ul><ul><ul><ul><li>Back layer composited using </li></ul></ul></ul><ul><ul><ul><li>full resolution CoC </li></ul></ul></ul><ul><ul><ul><li>Front layer is ok to bleed anyway </li></ul></ul></ul>Ultra Specs: Bokeh DOF
    47. 48. Ultra Specs Post Processes Video
    48. 49. What if…
    49. 50. S3D Image Generation
    50. 51. <ul><ul><li>Standard approach: Render scene two times </li></ul></ul><ul><ul><ul><li>Great quality, pretty straightforward </li></ul></ul></ul><ul><ul><ul><li>Problematic for GPU heavy games </li></ul></ul></ul><ul><ul><ul><ul><li>Often means half the framerate </li></ul></ul></ul></ul><ul><ul><ul><li>Would require heavy quality reduction for C2 </li></ul></ul></ul><ul><ul><ul><ul><li>Resolution, LODs, view distance, effect quality/amount </li></ul></ul></ul></ul><ul><ul><li>Image space approach: Reprojection </li></ul></ul><ul><ul><ul><li>Reconstruct view/world space position of pixel and project into space of left/right eye cameras </li></ul></ul></ul><ul><ul><ul><li>Basically point splatting </li></ul></ul></ul><ul><ul><ul><li>Scattering not efficiently possible on D3D9/10 GPUs </li></ul></ul></ul><ul><ul><ul><li>Requires second hole filling pass </li></ul></ul></ul>S3D Image Generation
    51. 52. <ul><ul><li>Image offsetting in Pixel Shader </li></ul></ul><ul><ul><ul><li>Gather based approach </li></ul></ul></ul><ul><ul><ul><li>For each pixel, compute disparity from depth buffer </li></ul></ul></ul><ul><ul><ul><li>Sample backbuffer with positive/negative disparity as offset to generate warped image (using bilinear filtering) </li></ul></ul></ul>S3D Image Generation <ul><ul><li>Disparity computed using Thales Theorem </li></ul></ul><ul><ul><li>Disparity : distance between projected positions of point in left/right views </li></ul></ul><ul><ul><li>MS : maximum separation (e.g. 3% of screen) </li></ul></ul><ul><ul><li>ZPD : zero parallax plane distance </li></ul></ul><ul><ul><li>Disparity = MS * (1 – ZPD / Depth) </li></ul></ul>
    52. 53. <ul><ul><li>Algorithm samples backbuffer with offset </li></ul></ul><ul><ul><ul><li>Issues due to missing data in main view </li></ul></ul></ul><ul><ul><li>Problem: Occlusion </li></ul></ul><ul><ul><ul><li>Background should be sampled but foreground object is in image </li></ul></ul></ul><ul><ul><ul><li>Easy to find by checking for closer depth, replicate background instead </li></ul></ul></ul><ul><ul><ul><li>Our solution: Find minimum depth and use it for computing disparity </li></ul></ul></ul><ul><ul><ul><ul><li>Small depth means small offset as well </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Adds some randomization to the replication </li></ul></ul></ul></ul>S3D Image Generation
    53. 54. <ul><ul><li>const float samples[3] = { 0.5, 0.66, 1 }; </li></ul></ul><ul><ul><li>float minDepthL = 1.0, minDepthR = 1.0; </li></ul></ul><ul><ul><li>float2 uv = 0; </li></ul></ul><ul><ul><li>for ( int i = 0; i < 3; ++i ) { </li></ul></ul><ul><ul><li>uv.x = samples[i] * MaxSeparation; </li></ul></ul><ul><ul><li>minDepthL = min ( minDepthL, GetDepth( baseUV + uv ) ); </li></ul></ul><ul><ul><li>minDepthR = min ( minDepthR, GetDepth( baseUV - uv ) ); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>float parallaxL = MaxSeparation * (1 – ZPD / minDepthL ); </li></ul></ul><ul><ul><li>float parallaxR = MaxSeparation * (1 – ZPD / minDepthR ); </li></ul></ul><ul><ul><li>left = tex2D ( backBuf, baseUV + float2 ( parallaxL, 0 ) ); </li></ul></ul><ul><ul><li>right = tex2D ( backBuf, baseUV - float2 ( parallaxR, 0 ) ); </li></ul></ul>S3D Image Generation: Shader Sample
    54. 55. <ul><ul><li>Simple and very efficient, about 1 ms on consoles </li></ul></ul><ul><ul><ul><li>Works with standard stereo parameters, negative and positive parallax </li></ul></ul></ul><ul><ul><ul><li>Overall results very similar to rendering two times </li></ul></ul></ul><ul><ul><li>Does not handle disocclusion </li></ul></ul><ul><ul><ul><li>Works well enough for scenes with sparse silhouettes (e.g. city scene with huge buildings) and carefully chosen stereo parameters </li></ul></ul></ul><ul><ul><ul><li>More problematic for very close objects like FP weapon </li></ul></ul></ul><ul><ul><ul><ul><li>Huger area with missing information </li></ul></ul></ul></ul><ul><ul><ul><ul><li>See slight halos around objects (replicated background) </li></ul></ul></ul></ul><ul><ul><li>Does not work for transparent objects (not in depth buffer) </li></ul></ul><ul><ul><ul><li>They get separation of background (somehow acceptable if overall scene depth is limited) </li></ul></ul></ul><ul><ul><li>Left/right screen edges need special consideration </li></ul></ul><ul><ul><ul><li>For example cropping image </li></ul></ul></ul>S3D Image Generation
    55. 56. <ul><ul><li>Conclusion </li></ul></ul><ul><ul><ul><li>Technique is far from being perfect </li></ul></ul></ul><ul><ul><ul><ul><li>Many potential issues </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Good amount of tweaking required </li></ul></ul></ul></ul><ul><ul><ul><li>Very well received for Crysis 2, especially on consoles </li></ul></ul></ul><ul><ul><ul><ul><li>No loss of visual fidelity in s3D </li></ul></ul></ul></ul><ul><ul><ul><li>Can be an option if you can live with some artifacts and limited depth range </li></ul></ul></ul>S3D Image Generation
    56. 57. <ul><ul><li>Respecting some rules is essential to create a comfortable experience </li></ul></ul><ul><ul><ul><li>Everything goes into the screen in Crysis 2 </li></ul></ul></ul><ul><ul><ul><ul><li>No window violation possible </li></ul></ul></ul></ul><ul><ul><ul><ul><li>No extreme refocusing required </li></ul></ul></ul></ul><ul><ul><ul><li>Avoiding depth conflicts </li></ul></ul></ul><ul><ul><ul><ul><li>Perceived 3D depth does not match rendering </li></ul></ul></ul></ul><ul><ul><ul><ul><li>E.g. crosshair is deeper than wall but rendered in front of it </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Very annoying, causes unpleasant side effects for viewers </li></ul></ul></ul></ul>S3D Image Generation
    57. 58. <ul><ul><li>3D HUD </li></ul></ul><ul><ul><ul><li>Core elements placed carefully in 3D space to avoid intersections with world </li></ul></ul></ul><ul><ul><li>Crosshair </li></ul></ul><ul><ul><ul><li>Pushed into the world to be in front of player </li></ul></ul></ul><ul><ul><ul><li>Can often cause depth conflicts </li></ul></ul></ul><ul><ul><ul><li>Cast ray into world, check for intersection </li></ul></ul></ul><ul><ul><ul><li>Adapt position smoothly in case of intersection </li></ul></ul></ul>S3D Image Generation
    58. 59. <ul><ul><li>Certain ZPD required to get acceptable parallax distribution </li></ul></ul><ul><ul><ul><li>Problematic for FPS games </li></ul></ul></ul><ul><ul><ul><li>Weapon would come out of screen </li></ul></ul></ul><ul><ul><li>Solution </li></ul></ul><ul><ul><ul><li>Weapon pushed into screen during stereo image generation </li></ul></ul></ul><ul><ul><ul><li>However, can cause depth conflicts when close to wall </li></ul></ul></ul><ul><ul><ul><li>To avoid this, check for close objects and reduce ZPD to fade out stereo effect smoothly </li></ul></ul></ul>S3D Image Generation
    59. 60. <ul><ul><li>3.5 years  immense amount of work </li></ul></ul><ul><ul><ul><li>We only covered here a very small sub-set  </li></ul></ul></ul><ul><ul><li>Whats next for CryENGIN E ? </li></ul></ul><ul><ul><ul><li>Bigger, better, faster. Avatar Quality in Realtime ? </li></ul></ul></ul><ul><ul><ul><ul><li>Not that crazy, with properly done assets for realtime </li></ul></ul></ul></ul><ul><ul><ul><li>We need faster consoles for a BIG “next gen” step: </li></ul></ul></ul><ul><ul><ul><ul><li>Big = huge visual step, as in Far Cry to Crysis 1 </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Insane amount of GPU Power (4x NV 590)  </li></ul></ul></ul></ul><ul><ul><ul><ul><li>Insane amount of memory (>= 8 GB) </li></ul></ul></ul></ul>Conclusion
    60. 61. <ul><ul><li>Vaclav Kyba, Michael Kopietz, Carsten Wenzel, Vladimir Kajalin, Andrey Konich, Anton Knyazyev, Ivo Zoltan Frey, Ivo Herzeg </li></ul></ul><ul><ul><li>Marco Corbetta, Christopher Evans, Chris Auty </li></ul></ul><ul><ul><li>Magnus Larbrant, Pierre-Ives Donzallaz, Chris North </li></ul></ul><ul><ul><li>Natalya Tatarchuk </li></ul></ul><ul><ul><li>And to the entire Crytek Team </li></ul></ul>Special Thanks
    61. 62. <ul><ul><li>Gritz, L. “The Importance of Being Linear”, 2008 </li></ul></ul><ul><ul><li>Debevec, P. “Recovering High Dynamic Range Radiance Maps from Photographs”, 1998 </li></ul></ul><ul><ul><li>Tchou, C. “HDR The Bungie Way”, 2008 </li></ul></ul><ul><ul><li>Vlachos, A. “Post Processing in The Orange Box”, 2008 </li></ul></ul><ul><ul><li>Cook, D. “Xbox Textures – Formats, Conversion, Fetching and Performance”, 2008 </li></ul></ul><ul><ul><li>Valient, M. “The Rendering Technology of Killzone 2“, 2008 </li></ul></ul><ul><ul><li>Kaplanyan, A. “Real-time Diffuse Global Illumination in CryENGINE 3”, 2009 </li></ul></ul><ul><ul><li>Sousa, T. “Crysis Next Gen Effects”, 2008 </li></ul></ul><ul><ul><li>Reinhard, E. et al. “High Dynamic Range Imaging” , 2010 </li></ul></ul><ul><ul><li>Hoffman, N. et al. “Physically-Based Shading Models in Film and Game Production”, 2010 </li></ul></ul><ul><ul><li>Sousa, T. “CryENGINE 3 Rendering Techniques”, 2011 </li></ul></ul><ul><ul><li>Grosch T. and Ritschel T. “Screen-Space Directional Occlusion”. GPU Pro, 2010 </li></ul></ul><ul><ul><li>Randima, F “Percentage Closer Soft-Shadows”, 2005 </li></ul></ul><ul><ul><li>Krassnigg, J “A Deferred Decal Rendering Technique”, Game Engine Gems 1, 2011 </li></ul></ul><ul><ul><li>Cyril, P. et al.”Photographic Depth of Field Rendering”, 2005 </li></ul></ul><ul><ul><li>Borshukov, G. and Lewis, J.P “Realistic Human Face Rendering for “The Matrix Reloaded””, 2001 </li></ul></ul>References
    62. 63. <ul><ul><li>[email_address] / Twitter: Crytek_Tiago </li></ul></ul><ul><ul><li>[email_address] </li></ul></ul><ul><ul><li>[email_address] </li></ul></ul>Questions
    63. 64. <ul><ul><li>Bonus Slides </li></ul></ul>
    64. 65. <ul><ul><li>HDR [Reinhard 2010] </li></ul></ul><ul><ul><ul><li>Precision, range </li></ul></ul></ul><ul><ul><ul><li>Physically based post processing </li></ul></ul></ul>HDR & Linear Correctness <ul><li>Linear Correctness [Gritz 2008] </li></ul><ul><ul><li>All computations in exact same space </li></ul></ul>
    65. 66. Computing VPOS warp basis <ul><li>float fProjectionRatio = fViewWidth/fViewHeight; // projection ratio </li></ul><ul><li>//all values are in camera space </li></ul><ul><li>float fFar = cam.GetFarPlane(); </li></ul><ul><li>float fNear = cam.GetNearPlane(); </li></ul><ul><li>float fWorldHeightDiv2 = fNear * cry_tanf(cam.GetFov()*0.5f); </li></ul><ul><li>float fWorldWidthDiv2 = fWorldHeightDiv2 * fProjectionRatio; </li></ul><ul><li>float k = fFar/fNear; </li></ul><ul><li>Vec3 vStereoShift = camMatrix.GetColumn0().GetNormalized() * cam.GetAsymL(); </li></ul><ul><li>//apply matrix orientation </li></ul><ul><li>Vec3 vZ = (camMatrix.GetColumn1() * fNear + vStereoShift)* k; // size of vZ is the distance from camera pos to near plane </li></ul><ul><li>Vec3 vX = camMatrix.GetColumn0() * fWorldWidthDiv2 * k; </li></ul><ul><li>Vec3 vY = camMatrix.GetColumn2() * fWorldHeightDiv2 * k; </li></ul><ul><li>vZ = vZ - vX; </li></ul><ul><li>vX *= (2.0f/fViewWidth); </li></ul><ul><li>vZ = vZ + vY; </li></ul><ul><li>vY *= -(2.0f/fViewHeight); </li></ul><ul><li>//Transform basis to any local space (shadow space here) </li></ul><ul><li>vWBasisX = mShadowTexGen * Vec4 (vX, 0.0f); </li></ul><ul><li>vWBasisY = mShadowTexGen * Vec4 (vY, 0.0f); </li></ul><ul><li>vWBasisZ = mShadowTexGen * Vec4 (vZ, 0.0f); </li></ul><ul><li>vCamPos = mShadowTexGen * Vec4 (cam.GetPosition(), 1.0f); </li></ul>
    66. 67. Geometrical Meaning of Reconstruction
    67. 68. <ul><ul><li>Two main reasons </li></ul></ul><ul><ul><ul><li>Low shadow map texel density </li></ul></ul></ul><ul><ul><ul><li>Precision of depth buffers </li></ul></ul></ul><ul><ul><li>Different scenarios to overcome acne </li></ul></ul><ul><ul><ul><li>Sun shadows: front faces rendered with slope-scaled depth bias </li></ul></ul></ul><ul><ul><ul><li>Point light shadows: back face rendering, works better for indoors scenes </li></ul></ul></ul><ul><ul><ul><li>Variance shadows for distant LODs - render both faces to shadow maps </li></ul></ul></ul><ul><ul><li>Constant depth bias during deferred shadow passes to overcome depth buffer precision </li></ul></ul>Shadow Acne
    68. 69. <ul><ul><li>Can’t afford each light casting shadows on consoles </li></ul></ul><ul><ul><li>Clip Boxes / Volumes </li></ul></ul><ul><ul><ul><li>Tool for lighting artists to eliminate light bleeding using stencil culling </li></ul></ul></ul><ul><ul><ul><li>Each deferred light doesn’t need to have fully generated shadow maps </li></ul></ul></ul><ul><ul><ul><li>Artist can create arbitrary convex volumes or use default primitives </li></ul></ul></ul>Minimizing Light Bleeding
    69. 70. <ul><li>Forward Decals have quite some issues </li></ul><ul><ul><li>Additional memory, mesh re-allocations causing memory fragmentation, CPU time for dynamic mesh creation, etc </li></ul></ul><ul><li>Deferred decals to the rescue! [14] </li></ul><ul><ul><li>Rendered as a decal box volume, very similar to deferred lights </li></ul></ul><ul><ul><li>Separate diffuse layer + normal map buffer blending </li></ul></ul><ul><ul><li>Fetching diffuse texture and computing attenuation for shading </li></ul></ul><ul><ul><li>No lighting/shading computed here </li></ul></ul><ul><ul><li>Applied to static geometry only </li></ul></ul>Deferred Decals
    70. 71. Deferred Decals Initial scene Decals diffuse layer Road Decals Final scene
    71. 72. <ul><li>Problems </li></ul><ul><ul><li>In case decals have normal maps results in tangent space mismatch with the regular decals </li></ul></ul><ul><ul><li>Leaking of deferred decals </li></ul></ul>Deferred Decals
    72. 73. <ul><li>Solutions for leaking </li></ul><ul><ul><li>Adjustable decal volume and decal attenuation function </li></ul></ul><ul><ul><li>Dot product between Scene Normals and Decal Tangent Space Normal </li></ul></ul><ul><ul><ul><li>Problematic if decal uses normal maps itself </li></ul></ul></ul><ul><ul><ul><li>X360: render to EDRAM and always have separate copy in the resolved Scene Normals texture </li></ul></ul></ul><ul><ul><ul><li>PS3 : render target read/write during convex volume’s rasterization </li></ul></ul></ul>Deferred Decals