Requirements
- Create
a new Effect that computes Environment Mapping using a cube map
- The
environment map used must be data-driven and come from one of your files
- It
is probably best to specify a single one for your scene
- It
is also acceptable to specify different ones on a per-material basis
- There
must be a reflectivity uniform parameter that you set per-material
- A
value of 1 would mean that you only see the reflection
(i.e. you would never see the diffuse map)
- A
value of 0 would mean that you don't see the reflection at all when your
viewing angle is parallel with the normal. (However, you will still see
the reflection at glancing angles because of the fresnel effect)
- Your
shader must compute the fresnel effect for environment
mapping using Schlick's approximation:
- fresnelModifier
= ( 1 - saturate( dot( normal_world, viewDirection ) ) )^5
- reflectedAmount
= reflectance + ( ( 1 - reflectance ) * fresnelModifier )
- There
are two options for mixing the reflections with the diffuse color (as discussed
in class):
- You
may combine it with the diffuse color before lighting
- You
may combine it with the diffuse color after lighting (but before adding
specularity)
- The
way to "combine" it will look something like this:
- diffuse
= lerp( diffuse, reflectedColor, reflectedAmount )
- You
will have to create a new EnvironmentMap asset type
- (In
a real game you probably wouldn't do this, but since we kept our asset
build process simple we need to do this to support the new DDS file
extension we'll use for cube maps.)
- You
will need to create a new EnvironmentMapBuilder tool
- It
should just copy the cube maps, just like the other TextureBuilder
- Don't
forget to set up your project dependencies correctly!
- Your
ground plane must use environment mapping so that I can
move the camera up and down and verify that the fresnel effect is working
properly
- You
must have a sphere in your scene that also uses environment mapping
- Render
your Opaque bucket into a texture
- Copy
the Opaque bucket texture into the back buffer
- Render
your Alpha bucket into the back buffer
- Create
a new Effect that uses the Opaque bucket texture as input
- You
should do some kind of manipulation on what has already been rendered
that you couldn't do using standard alpha blending
- Using
some kind of sine wave is always a good idea if you don't have any
others; you can make the back ground wobble around
- Just
manipulating the transparency is not acceptable (we've
already done that with standard alpha blending)
- Just
manipulating the color is not acceptable (we've done
something similar with our additive shader)
- Think
of ways that you can actually move the drawn pixels around using texture
coordinates; this is something that isimpossible to do with
alpha blending
- You
must have at least one Entity that uses your specialty Effect that
manipulates the Opaque bucket texture
- It
must be towards the foreground of the scene, so that I can easily move
the camera around and verify that it is,indeed,
manipulating what has been rendered behind it
- Your
writeup must include a screenshot from PIX of your Opaque bucket render
target used as a texture. You can find this the same way that you would
look at any other SetTexture() call, and it should look something like this example.
Details
Environment Mapping
- Microsoft has
provided a good cube map that you can use (this is the one I used in class
as an example). You can find it at:
- ($DXSDK_DIR)\Samples\C++\Direct3D\StateManager\Media\skybox02.dds
- (Optional) You may also try your hand at creating your own using
the DirectX Texture Tool that I showed in class
- Using a cube map in C++ code has the following differences from the
2D textures we've used so far:
- IDirect3DCubeTexture9
- D3DXCreateCubeTextureFromFile()
- Using a cube map in HLSL code has the following differences from
the 2D samplers we've used so far:
- samplerCUBE
- texCUBE( sampler, someFloat3 )
- The float3 that you use as a texture coordinate in a cube map is
interpreted by the hardware as a direction from the origin of the cube map
(for example, using (1,0,0) as the second parameter to texCUBE() will
sample the very center of the +X face of the cube map). To compute a
reflected color do the following:
- Calculate the view direction the same way we did for specularity
- Make sure you use the correct camera position rather than the
wrong way I originally taught :(
- Calculate how the view direction will reflect at the fragment
position given the fragment's normal
- When using the reflect() function make sure that the view
direction is pointing in the direction that the function expects. You
may need to use -viewDirection depending on how you calculated it
- Use that reflected view direction to sample your environment map
- You should then be able to calculate the reflectivity given the
material's reflectivity and the fresnel equation, and then combine the
reflected color with the diffuse color using that reflectivity (as
discussed in the requirements section above)
Rendering to a texture
- To
set up your Opaque buffer texture:
- You
will need an IDirect3DTexture9*, just like for any other 2D texture
- Instead
of creating the texture from a file, though, just use the plain
CreateTexture() function
- The
width and height should be the same as what your real back buffer uses
- You
can use UserSettings::GetWidth() and UserSettings::GetHeight()
- No
mipmaps should be created, because we'll be rendering to this every
frame
- The
usage must be D3DUSAGE_RENDERTARGET
- This
tells Direct3D that we will be rendering to it
- The
format should be the same as the back buffer
- We
will need to get what Microsoft calls
a "surface" from this texture in order to use it as a render
target
- Call
IDirect3DTexture9::GetSurfaceLevel(), asking for level 0
- The
resulting IDirect3DSurface9* is what you'll use to set the texture as a
render target
- Before
setting the Opaque buffer texture as a render target, you need to get a
pointer to the real back buffer:
- Use
IDirect3DDevice9::GetRenderTarget(), asking for render target 0
- The
resulting IDirect3DSurface9* is the real back buffer that was created
according to your specifications
- (You
can make this call as soon as your CreateDevice() call succeeds in your
initialization code)
- Now,
when rendering your two different buckets, you can switch your render
target between these two surfaces:
- To
render your Opaque bucket:
- Set
your Opaque bucket texture as the current render target using:
- IDirect3DDevice9::SetRenderTarget()
- Clear
the target like you always have
- Any
rendering calls you make now will apply to the current render target
- This
means that you're clearing your Opaque texture, and not the real back
buffer
- Call
BeginScene()
- Make
all of your draw calls, just like you have in previous assignments
- Call
EndScene()
- To
render your Translucent bucket:
- Set
the real back buffer as the current render target using:
- IDirect3DDevice9::SetRenderTarget()
- Instead
of clearing like we did with the Opaque bucket, we want to start this
bucket with everything we've done in the Opaque bucket so far, so we
need to copy its contents to the back buffer. Use:
- IDirect3DDevice9::StretchRect()
- You
will be copying the entire surface
- The
sizes should be the same (because you set it up that way), so no
filtering needs to be done. Use D3DTEXF_NONE
- Call
BeginScene()
- Now
you can make all of the draw calls, just like you have in previous assignments
- The
one extra step you have to make is to set the Opaque bucket texture so
that it's available to any shaders that use it. This is exactly the
same as using any other 2D texture.
- Call
EndScene()
- When
you're done, call IDirect3DDevice9::Present() just like you've always
done.
If things aren't working
make sure to use PIX to help. It will show you the calls to SetRenderTarget(),
and so you should be able to follow each of the steps and make sure that things
look like you would expect in the Render tab (You can also open Surface tabs
for each Surface and make sure that things are drawing in each at the right
time).
No comments:
Post a Comment