Projective Textures & Shadow Mapping Prof. Aaron Lanterman School of Electrical and Computer Engineering Georgia Institute of Technology
What is projective texturing? An intuition for projective texturing The slide projector analogy Source: Wolfgang Heidrich [99] From Stanford CS448A: Real-Time Graphics Architectures lecture 11; see graphics.stanford.edu/courses/cs448a-01-fall 2
Slide projector - different locations Images from C. Everitt, Projective Texture Mapping, http://www.nvidia.com/object/projective_texture_mapping.html 3
4 Texture matrix s t r q " # % & = 1 2 0 0 1 2 0 1 2 0 1 2 0 0 1 2 1 2 0 0 0 1 " # % & Light Frustrum ( projection) Matrix " # % & Light View (lookat) Matrix " # % & Modeling Matrix " # % & x 0 y 0 z 0 w 0 " # % & From The Cg Tutorial, p. 252.
ProjectTexture setup Shader "GPUXX/ProjectTexture" {! Properties {! _BaseTex ("Base RGB) Gloss (A)", 2D) = "white" {}! _ProjTex ("Base RGB)", 2D) = "white" {}! _SpotPower ("Spotlightiness", Range(0.01,1)) = 0.7! }!!!!... uniform sampler2d _BaseTex;! uniform float4 _BaseTex_ST;! uniform sampler2d _ProjTex;! uniform float _SpotPower;!! uniform float4x4 _myprojectormatrix;! uniform float3 _spotlightdir;!
ProjectTexture structures struct a2v {! float4 v: POSITION;! float3 n: NORMAL;! float2 tc: TEXCOORD0;! };!! struct v2f {! float4 sv: SV_POSITION;! float2 tc: TEXCOORD0;! float3 vworldpos: TEXCOORD1;! float3 nworld: TEXCOORD2;! float4 vprojected: TEXCOORD3;! };!
ProjectTexture vertex program v2f vert_projecttexture(a2v input) {! v2f output;! output.sv = mul(unity_matrix_mvp, input.v);! output.vworldpos = mul(_object2world, input.v).xyz;! // To transform normals, we want to use the inverse! // transpose of upper left 3x3! // Putting input.n in first argument is like! // doing trans((float3x3)_world2object) * input.n;! output.nworld =! normalize(mul(input.n, (float3x3) _World2Object));! output.vprojected = mul(_myprojectormatrix,! float4(output.vworldpos,1));! output.tc = TRANSFORM_TEX(input.tc, _BaseTex);! return output;! }!
ProjectTexture fragment program float4 frag_projecttexture(v2f input) : COLOR {! // Only use this shader with a point light! float3 lightdir = normalize(_worldspacelightpos0.xyz - input.vworldpos * _WorldSpaceLightPos0.w);! float3 eyedir =! normalize(_worldspacecamerapos.xyz - input.vworldpos);! // Renormalizing because the GPUs interpolator! // doesnt know this is a unit vector! float3 n = normalize(input.nworld);! float3 diff_almost =! unity_lightcolor0.rgb * max(0, dot(n, lightdir));! float spotlighteffect =! pow(dot(normalize(_spotlightdir), -lightdir),_spotpower * 128.0);! diff_almost *= spotlighteffect;! diff_almost *= tex2dproj(_projtex,input.vprojected);!! float4 base = tex2d(_basetex, input.tc);! float3 output =! (diff_almost + UNITY_LIGHTMODEL_AMBIENT.rgb) * base.rgb;! return(float4(output,1));! }!
C# script to set up projector matrix using UnityEngine;! using System.Collections;!! [ExecuteInEditMode]!! public class SetupTextureProjection : MonoBehviour {!! private Matrix4x4 projectormatrix;! private Matrix4x4 offsetmatrix;! private Camera mycamera;!! void Start () {! Vector3 halfs = 0.5f * Vector3.one;! offsetmatrix = Matrix4x4.TRS(halfs, Quaternion.identity, halfs);! mycamera = GetComponent<Camera> ();! }!! void Update () {! projectormatrix = offsetmatrix * mycamera.projectionmatrix *! mycamera.worldtocameramatrix;! // Quick & dirty; it would generally be better to set properties! // in specific materials! Shader.SetGlobalMatrix("_MyProjectorMatrix", projectormatrix);! Shader.SetGlobalVector("_spotlightDir", transform.forward);! }! }!
Watch out for reverse projection! Images from C. Everitt, Projective Texture Mapping, developer.nvidia.com/object/projective_texture_mapping.html 10
Dramatic shadow in 2K Games BioShock From www.wired.com/gaming/gamingreviews/multimedia/2007/08/pl_bioshock?slide=16&slideview=6 11
The shadow mapping concept (1) Depth testing from the light s point-of-view Two pass algorithm First, render depth buffer from the light s point-of-view The result is a depth map or shadow map Essentially a 2D function indicating the depth of the closest pixels to the light This depth map is used in the second pass 12
The shadow mapping concept (2) Shadow determination with the depth map Second, render scene from the eye s point-of-view For each rasterized fragment Determine fragment s XYZ position relative to the light This light position should be setup to match the frustum used to create the depth map Compare the depth value at light position XY in the depth map to fragment s light position Z 13
The shadow mapping concept (3) The Shadow Map Comparison Two values A = Z value from depth map at fragment s light XY position B = Z value of fragment s XYZ light position If B is greater than A, then there must be something closer to the light than the fragment, implies fragment is shadowed If A and B are approximately equal, implies fragment is lit 14
Shadow mapping: 2D illustration (1) The A < B shadowed fragment case depth map image plane light source depth map Z = A eye position fragments light Z = B eye view image plane, a.k.a. the frame buffer 15
Shadow mapping: 2D illustration (2) The A B unshadowed fragment case depth map image plane light source depth map Z = A eye position fragments light Z = B eye view image plane, a.k.a. the frame buffer 16
Shadow mapping: 2D illustration (3) Note image precision mismatch! The depth map could be at a different resolution from the framebuffer This mismatch can lead to artifacts 17
Visualizing shadow mapping (1) A fairly complex scene with shadows the point light source 18
Visualizing shadow mapping (2) Compare with and without shadows with shadows without shadows 19
Visualizing shadow mapping (3) The scene from the light s point-of-view FYI: from the eyes point-of-view again 20
Visualizing shadow mapping (4) The depth buffer from the light s point-of-view FYI: from the lights point-of-view again 21
Visualizing shadow mapping (5) Projecting the depth map onto the eye s view FYI: depth map for light s point-of-view again 22
Visualizing shadow mapping (6) Projecting light s planar distance onto eye s view 23
Visualizing shadow mapping (7) Comparing light distance to light depth map Green is where the light planar distance and the light depth map are approximately equal Non-green is where shadows should be 24
Visualizing shadow mapping (8) Scene with shadows Notice how specular highlights never appear in shadows Notice how curved surfaces cast shadows on each other 25
Depth map bias issues Too little bias, everything begins to shadow Too much bias, shadow starts too far back Just right 26
Shadow mapping: filtering example GL_NEAREST: blocky GL_LINEAR: antialiased edges Low shadow map resolution used to heighten filtering artifacts 27
Projective texturing with spotlight shadows Use a spotlight-style projected texture to give shadow maps a spotlight falloff 28