<div dir="ltr"><div dir="ltr"><p class="MsoNormal">MY EXPERIENCE IMPLEMENTING SHADOWMAPS IN FREEWRL<span></span></p><p class="MsoNormal">-Doug Sanden</p>

<p class="MsoNormal">A. LIGHT SHADOWS<span></span></p>

<p class="MsoNormal">We already had GeneratedCubeMapTexture and TextureProject
implemented, and I started with fuzzy notion to combine code snippets from each
to generate shadow maps and project them, and I would start with PointLight
which needs a cubemap for shadow casting like GeneratedCubeMapTexture provides.
After a few days of trying to make sense of stale spaghetti code and opengl
errors regarding mixing of cubemaps and texture2D, I started over fresh with SpotLight
shadow.<span></span></p>

<p class="MsoNormal">Spotlight shadow - made the frustum angle match the outer
cone angle, and shadowmap rendering frustum fardistance match the light radius.<span></span></p>

<p class="MsoNormal">DirectionalLight shadow - made the extent match the scene if
global, or the parent extent if local<span></span></p>

<p class="MsoNormal">Concept: USEs - a light can be DEF/USEd multiple times, from
different world locations, and each USE instance needs a separate entry sent to
shader. That applies also to shadow maps, and so combined the per-frame USE
list to include both USE instance of light and shadowmap <span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_SpotLight_DEF_USE.x3dv">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_SpotLight_DEF_USE.x3dv</a><span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_SpotLight_DEF_USE_screenshot.png">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_SpotLight_DEF_USE_screenshot.png</a><span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_Directional_DEF_USE.x3dv">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_Directional_DEF_USE.x3dv</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_Directional_DEF_USE_screenshot.png">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_Directional_DEF_USE_screenshot.png</a><span></span></p>

<p class="MsoNormal">For PointLight I found old code in freewrl was still initializing
cubemaps as GL_TEXTURE2D, so I paused to update cubemap code around freewrl
first, before tackling PointLight shadow as a cubemap.<span></span></p>

<p class="MsoNormal">A design goal: to treat cubemaps as textures, including
allowing a MultiTexture to mix Texture2D and CubeMapTextures<span></span></p>

<p class="MsoNormal">Step 1. get all CubeMapTexture nodes using GL_TEXTURE_CUBE_MAP<span></span></p>

<p class="MsoNormal">Step 2. change main CPU/GPU multitexturing to allow
intermingling of cubemaps and texture2d<span></span></p>

<p class="MsoNormal">a) texture transforms and coordinates<span></span></p>

<p class="MsoNormal">I found GeneratedTextureCoordinates only applies to IFS IndexedFaceSet
nodes in freewrl, and to reach other builtin geometry to apply something
similar, I created a new node type GeneratedTextureTransform which has the same
fields.<span></span></p>

<p class="MsoNormal">In freewrl on CPU side we pair
(TextureTransform,TextureCoordinates) by indexes, and send the indexes of the
pairings to vertex shader, and it does the multiplying of whatever combination
of TextureTransform and TextureCoordinates the pairing specifies. Then the frag
shader uses the pair index to get the right TexCoord for a texture or
multitexture stage. So whether using GeneratedTextureCoordinate or
GeneratedTextureTransform for cubemap didn't seem to matter, since the one
entry either way was equivalent to a pairing.<span></span></p>

<p class="MsoNormal">x in the process I found freewrl didn't have all the GeneratedTextureCoordinate
methods implemented, such as NOISE, and didn't find an x3d browser that did to
use as benchmark, so guessed at what noise meant.<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/cubemap_ttrans_teapot_screenshot.png">http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/cubemap_ttrans_teapot_screenshot.png</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/cubemap_ttrans_teapot.x3dv">http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/cubemap_ttrans_teapot.x3dv</a>
<span></span></p>

<p class="MsoNormal">b) frag shader - it needs to know which sampler type and we
send it a samplr = 0 for texture2D and 1 for textureCubeMap and so it looks in
a different sampler array with the index given:<span></span></p>

<p class="MsoNormal">if(samplr == 1)<span></span></p>

<p class="MsoNormal">  color =
texture(textureUnitCube[tindex],TexCoord[cindex]);<span></span></p>

<p class="MsoNormal">else<span></span></p>

<p class="MsoNormal">  color =
texture2D(texturUnit[tindex],TexCoord[cindex].xy);<span></span></p>

<p class="MsoNormal">Getting the CPU-side pairing code to generate good defaults
when mixing 2D and cube and giving no Texture Transform or GeneratedTextureTransform
list was fiddly to express the notions needed, but worked:<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/ImageCubeMap_multitex_mixed_2D_cube.mp4">http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/ImageCubeMap_multitex_mixed_2D_cube.mp4</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/ImageCubeMap_multitex_mixed_%202D_cube.x3dv">http://dug9.users.sourceforge.net/web3d/tests/CubeMapTexture/ImageCubeMap_multitex_mixed_%202D_cube.x3dv</a>
<span></span></p>

<p class="MsoNormal">- the beachball texture on the left is 2D and defaults to 2D
diffuse texture mapping, the texture on the right is cubemap, and defaults to
reflection texture, so they should move differently relative to each other as
the sphere is examined.<span></span></p>

<p class="MsoNormal"><span> </span></p>

<p class="MsoNormal">Having warmed up with cubemap improvements, another attempt
at PointLight with cubemap shadowmap got results<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_PointlLight_DEF_USE.x3dv">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_PointlLight_DEF_USE.x3dv</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_PointLight_DEF_USE_screenshot.png">http://dug9.users.sourceforge.net/web3d/tests/Lights/shadow_PointLight_DEF_USE_screenshot.png</a><span></span></p>

<p class="MsoNormal">B. TEXTURE PROJECTOR SHADOWS<span></span></p>

<p class="MsoNormal">Existential nausea - I thought I knew lights and textures
were different, but texture projectors blur the lines. What is a projector, something
like a mapping between fragment space and texture space, or excuse me with
color and intensity, and shadows, it could be called a MaterialProjector or
LightProjector. And mappings are like our (TexCoords, TextureTransform)
pairings, which also map between fragment and texture space.<span></span></p>

<p class="MsoNormal">After getting past the nausea, it seemed like the analogy
between Lights and Projectors was and using Lights as an analogy, much of the
infrastructure I could copy from Lights including depth texture sampling.<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Spot.x3dv">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Spot.x3dv</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_spot.png">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_spot.png</a>  <span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Parallel.x3dv">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Parallel.x3dv</a><span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Parallel.png">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Parallel.png</a>
<span></span></p>

<p class="MsoNormal"><span> </span></p>

<p class="MsoNormal">Using Lights as an analogy, there seemed to be one node missing
from TextureProjectors: ProjectorPoint.<span></span></p>

<p class="MsoNormal">So created that node type TextureProjectorPoint<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point.x3dv">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point.x3dv</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point.png">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point.png</a>
<span></span></p>

<p class="MsoNormal">And a fun test scene with disco ball rotating ProjectorPoint:<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point_disco.x3dv">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point_disco.x3dv</a>
<span></span></p>

<p class="MsoNormal"><a href="http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point_disco.mp4">http://dug9.users.sourceforge.net/web3d/tests/PTM/PTM_shadow_Point_disco.mp4</a>
<span></span></p>

<p class="MsoNormal"><span> </span></p>

<p class="MsoNormal">SUMMARY <span></span></p>

<p class="MsoNormal">- 3 months of refactoring / fixing and generalizing old spaghetti
code<span></span></p>

<p class="MsoNormal">- NOT DONE: ComposedBackground, EnvironmentLight<span></span></p>

<p class="MsoNormal"><span> </span></p>

<p class="MsoNormal">/MY EXPERIENCE<span></span></p></div></div>