├── .gitattributes
├── ConeSphereOcclusionLUT.exe
├── ConeSphereOcclusionLUT.sln
├── ConeSphereOcclusionLUT.vcxproj
├── README.md
├── cone_sphere_occlusion_lut.tga
└── main.cpp
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/ConeSphereOcclusionLUT.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/knarkowicz/ConeSphereOcclusionLUT/cc329868d7b4fb689f5c4a0c9e917351f6d06757/ConeSphereOcclusionLUT.exe
--------------------------------------------------------------------------------
/ConeSphereOcclusionLUT.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConeSphereOcclusionLUT", "ConeSphereOcclusionLUT.vcxproj", "{59AA66D1-11A7-41D9-86D8-32ABB1308D1A}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Win32 = Debug|Win32
11 | Release|Win32 = Release|Win32
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {59AA66D1-11A7-41D9-86D8-32ABB1308D1A}.Debug|Win32.ActiveCfg = Debug|Win32
15 | {59AA66D1-11A7-41D9-86D8-32ABB1308D1A}.Debug|Win32.Build.0 = Debug|Win32
16 | {59AA66D1-11A7-41D9-86D8-32ABB1308D1A}.Release|Win32.ActiveCfg = Release|Win32
17 | {59AA66D1-11A7-41D9-86D8-32ABB1308D1A}.Release|Win32.Build.0 = Release|Win32
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/ConeSphereOcclusionLUT.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 |
14 | {59AA66D1-11A7-41D9-86D8-32ABB1308D1A}
15 | ConeSphereOcclusionLUT
16 |
17 |
18 |
19 | Application
20 | true
21 | v120
22 | MultiByte
23 |
24 |
25 | Application
26 | false
27 | v120
28 | true
29 | MultiByte
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Level3
45 | Disabled
46 | true
47 |
48 |
49 | true
50 |
51 |
52 |
53 |
54 | Level3
55 | MaxSpeed
56 | true
57 | true
58 | true
59 |
60 |
61 | true
62 | true
63 | true
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ConeSphereOcclusionLUT
2 | =======
3 |
4 | ConeSphereOcclusionLUT generates a cone sphere occlusion LUT to be used with TLoU style capsule AO shadows. For details see page 26 of ["Lighting Technology Of "The Last Of Us""](http://miciwan.com/SIGGRAPH2013/Lighting%20Technology%20of%20The%20Last%20Of%20Us.pdf) talk by Michał Iwanicki . This slick technique was originally created for SPU, but it perfectly works with compute shaders.
5 |
--------------------------------------------------------------------------------
/cone_sphere_occlusion_lut.tga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/knarkowicz/ConeSphereOcclusionLUT/cc329868d7b4fb689f5c4a0c9e917351f6d06757/cone_sphere_occlusion_lut.tga
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | float const MATH_PI = 3.14159265359f;
8 | unsigned const SAMPLE_NUM = 10000;
9 |
10 | struct Vec3
11 | {
12 | float x;
13 | float y;
14 | float z;
15 | };
16 |
17 | float dot( Vec3 a, Vec3 b )
18 | {
19 | return a.x * b.x + a.y * b.y + a.z * b.z;
20 | }
21 |
22 | void SaveTGA( char const* path, unsigned width, unsigned height, void const* data )
23 | {
24 | #pragma pack( push, 1 )
25 | struct STGAHeader
26 | {
27 | char idlength;
28 | char colourmaptype;
29 | char datatypecode;
30 | short int colourmaporigin;
31 | short int colourmaplength;
32 | char colourmapdepth;
33 | short int x_origin;
34 | short int y_origin;
35 | short width;
36 | short height;
37 | char bitsperpixel;
38 | char imagedescriptor;
39 | };
40 | #pragma pack( pop )
41 |
42 |
43 | FILE* f = nullptr;
44 | fopen_s( &f, path, "wb" );
45 | if ( !f )
46 | {
47 | return;
48 | }
49 |
50 | STGAHeader header;
51 | memset( &header, 0, sizeof( header ) );
52 | header.width = width;
53 | header.height = height;
54 | header.datatypecode = 2;
55 | header.bitsperpixel = 24;
56 | header.imagedescriptor = 1 << 5;
57 | fwrite( &header, sizeof( header ), 1, f );
58 |
59 | fwrite( data, width * height * 3, 1, f );
60 |
61 | fclose( f );
62 | }
63 |
64 | Vec3 RandomConeRays[ SAMPLE_NUM ];
65 |
66 | void GenerateRandomConeRays( float coneAngle )
67 | {
68 | float const cosConeAngle = cosf( 0.5f * ( coneAngle * MATH_PI / 180.0f ) );
69 | for ( unsigned iSample = 0; iSample < SAMPLE_NUM; ++iSample )
70 | {
71 | float cosTheta = ( (float) rand() / RAND_MAX ) * ( 1.0f - cosConeAngle ) + cosConeAngle;
72 | float sinTheta = sqrtf( 1.0f - cosTheta * cosTheta );
73 | float phi = MATH_PI * ( (float) rand() / RAND_MAX ) * 2.0f - 1.0f;
74 | float cosPhi = cosf( phi );
75 | float sinPhi = sinf( phi );
76 |
77 | RandomConeRays[ iSample ] = { sinTheta * cosPhi, sinTheta * sinPhi, cosTheta };
78 | }
79 | }
80 |
81 | float Occlusion( float occluderAngleSin, float occluderToBeamAngleCos )
82 | {
83 | float const occluderToBeamAngleSin = sqrtf( 1.0f - occluderToBeamAngleCos * occluderToBeamAngleCos );
84 | float const occluderAngleCos = sqrtf( 1.0f - occluderAngleSin * occluderAngleSin );
85 | Vec3 const occluderDir = { occluderToBeamAngleSin, 0.0f, occluderToBeamAngleCos };
86 |
87 | unsigned hitNum = 0;
88 | for ( unsigned iSample = 0; iSample < SAMPLE_NUM; ++iSample )
89 | {
90 | if ( dot( occluderDir, RandomConeRays[ iSample ] ) > occluderAngleCos )
91 | {
92 | ++hitNum;
93 | }
94 | }
95 |
96 | return 1.0f - hitNum / (float) SAMPLE_NUM;
97 | }
98 |
99 | int main( int argc, char** argv )
100 | {
101 | if ( argc < 4 )
102 | {
103 | printf( "Incorrect params\n" );
104 | printf( "Usage: ConeSphereOcclusionLUT.exe lut_width lut_height cone_angle_in_degress\n" );
105 | printf( "ConeSphereOcclusionLUT.exe 128 64 30\n" );
106 | return 1;
107 | }
108 |
109 | float coneAngle = 30.0f;
110 | unsigned lutWidth = 128;
111 | unsigned lutHeight = 64;
112 | sscanf_s( argv[ 1 ], "%u", &lutWidth );
113 | sscanf_s( argv[ 2 ], "%u", &lutHeight );
114 | sscanf_s( argv[ 3 ], "%f", &coneAngle );
115 |
116 | uint8_t* lutData = new uint8_t[ lutWidth * lutHeight * 3 ];
117 | GenerateRandomConeRays( coneAngle );
118 |
119 | for ( unsigned iSinTheta = 0; iSinTheta < lutHeight; ++iSinTheta ) // angle subtended by the occluder [0;1]
120 | {
121 | float const sinTheta = iSinTheta / ( lutHeight - 1.0f );
122 |
123 | for ( unsigned iCosPhi = 0; iCosPhi < lutWidth; ++iCosPhi ) // angle between the cone axis and the vector pointing towards the occluder (sphere) center [-1;1]
124 | {
125 | float const cosPhi = 2.0f * ( iCosPhi / ( lutWidth - 1.0f ) ) - 1.0f;
126 | float const sampleValue = Occlusion( sinTheta, cosPhi );
127 |
128 | uint8_t sampleU8 = uint8_t( sampleValue * 255.0f + 0.5f );
129 | lutData[ iCosPhi * 3 + iSinTheta * lutWidth * 3 + 0 ] = sampleU8;
130 | lutData[ iCosPhi * 3 + iSinTheta * lutWidth * 3 + 1 ] = sampleU8;
131 | lutData[ iCosPhi * 3 + iSinTheta * lutWidth * 3 + 2 ] = sampleU8;
132 | }
133 | }
134 |
135 | SaveTGA( "cone_sphere_occlusion_lut.tga", lutWidth, lutHeight, lutData );
136 | delete[] lutData;
137 |
138 | return 0;
139 | }
--------------------------------------------------------------------------------