![Page 1: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/1.jpg)
The Technology behind
Jarosław PleskotSenior Engine Programmer
Flying Wild Hog
2014
![Page 2: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/2.jpg)
Facts about Shadow Warrior
published by Devolver Digital 18 months production time team ~35 people (2 tech programmers, 6 total) modified Hard Reset’s engine (Roadhog)
![Page 3: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/3.jpg)
Presentation overview
Act I, Skinned decals generation and rendering
Act II, Foliage authoring and rendering
Act III, Seawater rendering
![Page 4: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/4.jpg)
Act I, Skinned decals
![Page 5: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/5.jpg)
Skinned decals – entry point
In Hard Reset decals only on non-skinned geometry (static or movable) Characters destruction by showing/hiding parts of a model or by changing texture Lot of blood and gore in Shadow Warrior, must have skinned decals
![Page 6: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/6.jpg)
Skinned decals – two techniques
1. Deffered decals [1][2]+ mesh generation not needed
+ small amount of data to store and pass to graphics card
- decal floats when mesh is animated
- can be projected on other surfaces, need to mask out (additional gbuffer usage or additional passes)
Source: http://broniac.blogspot.com/2011/06/deferred-decals.html
![Page 7: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/7.jpg)
Skinned decals – two techniques
2. Geometry based [3]+ stable result when animating mesh
+ cover only desired surface
- mesh generation: time and memory
- additional input data required to generate a decal
![Page 8: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/8.jpg)
Skinned decals – two techniques
2. Geometry based [3]+ stable result when animating mesh
+ cover only desired surface
- mesh generation: time and memory
- additional input data required to generate a decal
![Page 9: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/9.jpg)
Skinned decals – input data
Load vertex buffer into CPU memory Generating adjacency per each triangle in mesh 3 adjacent triangles Mesh can consist of many isolated elements => adjacency groups (store first triangle index of each adjacency group)
struct STriangleAdjacency
{ UInt32 m_adj0; UInt32 m_adj1; UInt32 m_adj2; UInt32 m_group;};
![Page 10: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/10.jpg)
Skinned decals – generation
Asynchronous (job based) Copy decal parameters and skinning matrices to job
Basic algorithm
for all adjacency groups{ find triangle closest to hit point expand decal by adding adjacent triangles until size reached
and calculate UVs and TBN for each new triangle}
![Page 11: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/11.jpg)
Skinned decals – generation
1. Find triangle closest to hit point
Don't want to process entire mesh Skeleton and weights == skinned mesh is naturally divided In preprocess step create triangle list for every bone Iterate through selected and adjacent bones' lists Use skinning matrices to get worldspace positions
![Page 12: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/12.jpg)
Skinned decals – generation
2. Expand decal
add hit triangle to “open” listwhile open list not empty{ pop front and calculate its vertices’ positions if any inside decal (bounding box test, sizeZ = max( sizeX,
sizeY )) { add triangle to the output list with new UVs and TBN add adjacent triangles to “open” list if not already
processed }}
![Page 13: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/13.jpg)
Skinned decals – generation
2. Expand decal
add hit triangle to “open” listwhile open list not empty{ pop front and calculate its vertices’ positions if any inside decal (bounding box test, sizeZ = max( sizeX,
sizeY )) { add triangle to the output list with new UVs and TBN add adjacent triangles to “open” list if not already
processed }}
Special case for first triangle:
If triangle field > decal field always pass bounding box test
![Page 14: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/14.jpg)
Skinned decals – dismemberment
Character dismemberment implemented Decals must be split, how?
![Page 15: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/15.jpg)
Skinned decals – dismemberment
First version
Store decal spawn info, recompute on destruction
- additional CPU time
(5 enemies destroyed at once can produce 50 jobs)
- cannot show anything until recomputed decal arrive == blink
![Page 16: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/16.jpg)
Skinned decals – dismemberment
Second version Character dismemberment is hand- made by creating separate meshes Modify spawn algorithm – create separate decal chunks for every visible mesh Input: adjacency per chunk On cutting create new decals that references initial decal geometry Render proper decal chunks
![Page 17: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/17.jpg)
Skinned decals – dismemberment
Second version
+ no recomputation
+ split decals available instantly
- more draws for initial decal (merge on render)Modified algorithm
for all visible chunks{ for all adjacency groups { find triangle closest to hit point expand decal chunk by adding adjacent triangles until size
reached and calculate UVs and TBN for each new triangle
}}
![Page 18: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/18.jpg)
Skinned decals – rendering
Rendered through dynamic vertex buffers One pass (compose) or 2 passes (normal+compose) Possible animation through alpha test level shifting (lower alpha test reference value == bigger decal)
![Page 19: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/19.jpg)
Skinned decals – details
Decal size hard limit: 10k vertices Decal count limit: 100 decals (FIFO) Vertex memory: 30 MB total, in pool Typical bullet decal (500 triangles) spawn time
around 0.5 ms on Intel core i7 (async, still can do better) Big decals == skinned geometry rendered multiple times, avoid them, use other techniques, e.g. texture layering Use „clamp to border color” with alpha 0.0
![Page 20: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/20.jpg)
Act II, Foliage system
![Page 21: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/21.jpg)
Foliage system – entry point
• In Hard Reset vegetation only in one area of one DLC level
• In Shadow Warrior many open levels: forests, villages, towns, etc.
• Vegetation made as level geometry == no LoD, no instancing, hard to create and control (overdraw)
![Page 22: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/22.jpg)
Foliage system – entry point
Requirements:● Instancing● Specific LoD system● Easy to plant (levels created in 3dsmax,
gameplay in game editor)
![Page 23: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/23.jpg)
Foliage system – entry point
Requirements:● Instancing● Specific LoD system● Easy to plant (levels created in
3dsmax, gameplay in game editor)
Spawn meshes – meshes with relative
foliage density stored as vertex color
![Page 24: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/24.jpg)
Foliage system – planting
Spawn meshes for level 2 in 3ds Max
![Page 25: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/25.jpg)
Foliage system – planting
• Render spawn meshes in top-down view to an image (density, position.z and normal)
• In 50x50cm blocks generate random plant positions (ρ = ρmesh * ρblock, pos.z interpolated)
• Set random yaw
• Optionally align with normal vector
• Store packed matrix
All random values are static!
![Page 26: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/26.jpg)
Foliage system – planting
Many levels of foliage possible by splitting spawn meshes to separate 3dsmax objects
![Page 27: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/27.jpg)
Foliage system – editor
![Page 28: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/28.jpg)
Foliage system – storage
Initially one quad tree per map, batch index and LoD level stored with transformation
Changed to multi resolution grids (2 levels: 4x4 and 64x64 meters, one grid per batch)
![Page 29: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/29.jpg)
Foliage system – storage
Grid node contains min/max Z coord and object ranges for low and high density arrays
Transformation packed into 32 bytesstruct SObject{ Half4 m_plane0; // 8 Half4 m_plane1; // 16 Half4 m_plane2; // 24 Vec3Packed64 m_position;// 32};
![Page 30: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/30.jpg)
Foliage system – storagetypedef UInt64 Vec3Packed64;
#define POSITION_PACKED_PACK_SCALE 200.0f#define POSITION_PACKED_UNPACK_SCALE ( 1.0f / POSITION_PACKED_PACK_SCALE )
// 21 bit max#define VEC3PACKED64_MASK 0x00000000001fffff#define VEC3PACKED64_SIGN_RECOVER_SHIFT 11
inline Vec3Packed64 Vec3Packed64Pack( const Vec3& vec, Float packScale ){ return ( ( UInt64( vec.X * packScale ) & VEC3PACKED64_MASK ) << 42 ) | ( ( UInt64( vec.Y * packScale ) & VEC3PACKED64_MASK ) << 21 ) | ( UInt64( vec.Z * packScale ) & VEC3PACKED64_MASK );}
21 bits per component
± 5,2km with 2 mm resolution
![Page 31: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/31.jpg)
Foliage system – storageinline Vec3 Vec3Packed64Unpack( const Vec3Packed64 vecPacked, Float unpackScale ){ Vec3 result; { Int32 value = Int32( vecPacked & VEC3PACKED64_MASK ); value <<= VEC3PACKED64_SIGN_RECOVER_SHIFT; value >>= VEC3PACKED64_SIGN_RECOVER_SHIFT; result.Z = Float( value ) * unpackScale; } { Int32 value = Int32( ( vecPacked >> 21 ) & VEC3PACKED64_MASK ); value <<= VEC3PACKED64_SIGN_RECOVER_SHIFT; value >>= VEC3PACKED64_SIGN_RECOVER_SHIFT; result.Y = Float( value ) * unpackScale; }
{ Int32 value = Int32( ( vecPacked >> 42 ) & VEC3PACKED64_MASK ); value <<= VEC3PACKED64_SIGN_RECOVER_SHIFT; value >>= VEC3PACKED64_SIGN_RECOVER_SHIFT; result.X = Float( value ) * unpackScale; }
return result;}
Shift arithmetic
right!
![Page 32: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/32.jpg)
Foliage system – rendering
• Dynamic vertex buffer, 8192 instances max
• Several batches (one batch == all visible objects with the same mesh and materials)
• LoD levels:Low – 20% density, range multiplier x1
High – 100% density, range multiplier x1
Ultra – 100% density, range multiplier x2
• Gather with Z range ±15 meters
• Dissolve out on last 5 meters
![Page 33: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/33.jpg)
Foliage system – details
• Gather time for 8192 instances in 9 batches: 0.41 ms on Intel core i7 3.4 GHz
• GPU time: 1.22 ms (0.89 normal + 0.33 compose, 730k + 470k PSPixelsOut) on Radeon R9 270, 1920x1080
• Memory usage: from 0.7 to 10 MB per level
![Page 34: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/34.jpg)
Foliage system – results
~4200 instances gathered
![Page 35: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/35.jpg)
Foliage system – results
~6400 instances gathered
![Page 36: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/36.jpg)
Foliage system – results
Not only plants. Our artists are very creative!
![Page 37: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/37.jpg)
Act III, Seawater
![Page 38: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/38.jpg)
Seawater – entry point
• Docks location with stormy weather planned in Shadow Warrior
• DX9 renderer (no hw tesselation)
• Dedicated translucent water shader used in Hard Reset (simple waves, refraction, water fog, foam)
![Page 39: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/39.jpg)
Seawater – mesh
• 3 LoD levels (quad size: 0.5 x 0.5, 2x2, 8x8 meters, LoD 0 dims: 48x48 meters)
• Edge vertices stretched beyond camera far Z
• 33k tris total
• Mesh moved with camera, snapped to integer world coordinates (constant sampling positions)
• Stencil test
![Page 40: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/40.jpg)
Seawater – vertex shader
Position processing
Distortion Filter Asymmetry Choppiness Add vertex texture
Flatten edges
Distortionderivative
Filter Flatten edges
Modulate
Normals
Distortionderivative
w. phase offset
Filter Bias and modulate
Foam multiplier
Affect and orthogonalize
TBN
![Page 41: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/41.jpg)
Seawater – distortionfloat4 fWaterGeomWave0; // xy - frequency, z - speed, w – amplitude…
float DistortionFunc( float arg, float4 params ){
float modBase = 0.5 + sin( arg * params.x ) * 0.5;float modArg = modBase * params.y - params.y;float modAmp = modBase * params.z - params.z;return sin( arg * ( 1.0 + modArg ) ) * ( 1.0 + modAmp );
}
float DistortionDerivativeFunc( float arg, float4 params ){
float modBase = 0.5 + sin( arg * params.x ) * 0.5;float modArg = modBase * params.y - params.y;float modAmp = modBase * params.z - params.z;return cos( arg * ( 1.0 + modArg ) ) * ( 1.0 + modAmp );
}
#define DISTORTION_0( arg ) DistortionFunc( arg, fWaterGeomWave0FunctionParam )…#define D_DISTORTION_0( arg ) DistortionDerivativeFunc( arg, fWaterGeomWave0FunctionParam )…float arg0 = dot( posWS.xy, fWaterGeomWave0.xy ) + time * fWaterGeomWave0.z;…
Randomize waves
reusing wave parameters
(HACK)
![Page 42: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/42.jpg)
Seawater – waves
• Sea waves are the signal, mesh is a sampling mechanism
• Nyquist theroem: sampling frequency must be at least 2 times higher than peak signal frequency to avoid aliasing
• Different LoD == different sampling frequencies
![Page 43: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/43.jpg)
Seawater – waves
Solution:
• Calculate cuttoff frequency for each vertex
• Pass it to a shader as a vertex attribute
• Filter waves generated in vertex shader using this frequency limitstruct WaterVertex
{ Vec3 m_pos; Half2 m_uv0; Half2 m_uv1; Float m_geomSoftness; Float m_waveFreqLimit;};
![Page 44: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/44.jpg)
Seawater – filter
Diagonal direction has lowest sampling frequency
Lerp cutoff frequencies on LoD boundaries
Only fc0 and fc1 used in practice
![Page 45: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/45.jpg)
Seawater – filter
float DistortionFilter( vert_in i, float2 waveFreq ){
float waveFreqEff = length( waveFreq.xy );float val = -2.5 / i.m_waveFreqLimit * ( waveFreqEff -
i.m_waveFreqLimit * 0.8 );float filter = saturate( 0.5 + 0.5 * val );return filter;
}
![Page 46: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/46.jpg)
Seawater – filter
float DistortionFilter( vert_in i, float2 waveFreq ){
float waveFreqEff = length( waveFreq.xy );float val = -2.5 / i.m_waveFreqLimit * ( waveFreqEff -
i.m_waveFreqLimit * 0.8 );float filter = saturate( 0.5 + 0.5 * val );return filter;
}
#define CALC_FILTER_0 float filter0 = DistortionFilter( i, fWaterGeomWave0.xy )#define CALC_FILTER_1 float filter1 = DistortionFilter( i, fWaterGeomWave1.xy )#define CALC_FILTER_2 float filter2 = DistortionFilter( i, fWaterGeomWave2.xy )#define CALC_FILTER_3 float filter3 = DistortionFilter( i, fWaterGeomWave3.xy )
#define FILTER_0( val ) filter0*val#define FILTER_1( val ) filter1*val#define FILTER_2( val ) filter2*val#define FILTER_3( val ) filter3*val
![Page 47: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/47.jpg)
Seawater – wave asymmetry
float distort = 0.0;distort += FILTER_0( DISTORTION_0( arg0 ) * fWaterGeomWave0.w );…// FLATTENING STAGEposWS.z += distort * i.m_geomSoftness;
// NORMAL DISTORTION CODE NEEDED TO AFFECT POSITIONfloat cos0 = FILTER_0( D_DISTORTION_0( arg0 ) );float2 diff0 = i.m_geomSoftness * normalize( fWaterGeomWave0.xy ) * cos0 );…
// ASYMMETRY AND CHOPPINESS#define ASYMMETRY( arg, power ) ( arg > 0.0 ? power * arg*arg : 1.0 )
posWS.xy += diff0 * fWaterGeomWaveChoppiness.x *ASYMMETRY( cos0, fWaterGeomWaveAsymmetry.x );
![Page 48: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/48.jpg)
Seawater – wave asymmetry
// ASYMMETRY AND CHOPPINESS#define ASYMMETRY( arg, power ) ( arg > 0.0 ? power * arg*arg : 1.0 )
posWS.xy += diff0 * fWaterGeomWaveChoppiness.x * ASYMMETRY( cos0, fWaterGeomWaveAsymmetry.x );
![Page 49: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/49.jpg)
Seawater – vertex texture
• Displace vertices with perlin noise to avoid wave tiling
• Only LoD 1 and LoD 2
• Calculate proper mip level to avoid aliasing
• 256x256 R32F vertex texture
• 1024x1024 normals (read in PS)
![Page 50: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/50.jpg)
Seawater – pixel shader
• Translucent at the begining, changed to opaque later on
• 2 x diffuse (water + foam)
• 2 sliding normals + perlin noise normal
• Environment map
• Deffered lighting
![Page 51: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/51.jpg)
Seawater – results
• GPU time 0.80 ms (0.02 ms mask, 0.25 ms normal, 0.53 ms compose) @ Radeon R9 270, 1920x1080
• 0 pixels draw (depth & stencil fail): 0.16 ms (0.00 ms mask, 0.07 ms normal,
0.09 ms compose)
• 0 pixels draw (stencil fail): 0.39 ms (0.00 ms mask, 0.30 ms normal,
0.09 ms compose)
![Page 52: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/52.jpg)
Special thanks
Łukasz Zdunowski – Lead Artist
Zbigniew Siatecki – Environment Artist
Dominik Misiurski – FX Artist
Artur Maksara – Producer
… and the rest of our team.
![Page 53: The Technology behind Shadow Warrior, ZTG 2014](https://reader035.vdocuments.us/reader035/viewer/2022062419/5583fc4cd8b42aa82c8b4bdf/html5/thumbnails/53.jpg)
References
1. http://broniac.blogspot.com/2011/06/deferred-decals.html
2. http://humus.name/index.php?page=3D&ID=83
3. “Character Animation with Direct3D”, Carl Granberg, Charles River Media, 2009
Questions?Contact:Email: jarek.pleskot AT flyingwildhog.comFacebook: Jarosław PleskotTwitter: @JaroslawPleskot