Requirements
- Add
ambient light to your scene
- Ambient
light should be specified entirely by a single color. That color should
be added to the diffuse light (i.e. before the diffuse light is combined
with the diffuse color), so that there is always some diffuse
light.
- Add
falloff/attentuation to your pointlight
- The
specified intensity in your scene file should now refer to the intensity
at its position, and that intensity should now decrease as the distance
between the point light and the fragment increases
- Any values you use to calculate the attenuation should come from the scene file
- Create
a new Effect that calculates specular lighting in addition to diffuse
lighting
- It
should be able to use the same vertex shader that you already have
created, but you will need to write a new fragment shader
- You
will need to add an expected uniform parameter to the Effect, so that
different specular exponents can be set by different Materials
- This
particular uniform will be a float, but update your file format so that
you could also handle a uniform float2 parameters, uniform float3
parameters, and uniform float4 parameters
- Add
a floor plane to your scene
- This
should be made of two triangles that form a plane in the XZ axis
- Its
height in Y should be fairly close to the bottom of the boxes
- If
you have followed the previous assignments' instructions, putting the
plane at -1 in Y should work
- Alternatively,
you could put it at 0 in Y and then raise the boxes' positions
- You
may use either the Diffuse or the Diffuse+Specular Effect
- Add
enough boxes to satisfy the following requirements
- You
must use both of your Effects
- In
other words, some boxes must use only diffuse lighting, and some must
use diffuse and specular lighting
- For
each effect at least two different materials must be used
- Each
material should use a different diffuse texture
- The
materials with specular lighting should use different specular exponents
- For
each material, at least two boxes must be drawn with that material
- To
be clear, this means you must draw at least 8 boxes
- (BONUS)
This isn't required, but if you're interested it would be a good exercise
to also create a new Mesh file, so that you have a box with square
normals and one with round normals, and to use these different Meshes for
the two Entity boxes that use the same material
- Sort
your draw calls so that the following is true:
- Every
draw call using the same Effect is grouped together
- Specifically,
all four boxes using only Diffuse should be drawn in a row, and all four
boxes using Diffuse and Specular should be drawn in a row. (It doesn't
matter which Effect is drawn first or second.)
- Within
an Effect, every draw call using the same Material is grouped together
- Specifically,
the two boxes using the same Material should be drawn in a row. (It
doesn't matter which Material is drawn first or second.)
- You
should minimize changes between draw calls so that the following is true:
- You
should only set new shaders when different Effects are drawn.
- This
means that you should only set shaders twice each
frame. (You will have to set two different fragment shaders. It is
perfectly fine to also set the vertex shader twice, although you can
only set it once if you want to be clever and add a way to keep track of
whether it's the same or not. I would advise for this assignment to not
worry about the individual shader programs, and to always set every
shader when a new Effect must be drawn.)
- You
should only set textures and uniform parameters when different Materials
are drawn.
- This
means that when you draw two boxes that use the same Material you should
only set the textures and uniform parameters before you
draw anything. You shouldn't set any new state between
the two calls to draw the boxes except for the model-to-world
transformations. (Can you figure out why those must be set for
every draw call?)
- You
should add PIX events to your code to make the sorting and state change
optimizations clear
- You
are free to add extra events to organize things even more (like I showed
in class), but the following eventsmust exist so I can see
that you did the assignment properly:
- Every
new Effect should have its own event
- Every
new Material should have its own event
- Every
Entity should have its own event
- As
an example, your PIX events may look something like this:
- Effect
- Material
- Entity
- Entity
- Material
- Entity
- Entity
- Effect
- Material
- Entity
- Entity
- Material
- Entity
- Entity
- Your
code should only add PIX events in a debug configuration. It must not add
them in release mode. I strongly advise #defining preprocessor macros to make this
easier to manage. If you don't know how to do this, please ask the mailing
list and I will be glad to help :)
- Your
writeup must include a screenshot of the PIX events
- (BONUS)
This isn't required, but you might consider adding an Entity that
represents your point light so that it's easier to visualize how it's
working. If you do this, you should make a new Effect with a fragment
shader that doesn't get lit. Instead, the color of each
fragment should just be the color of the point light.
- (BONUS
BONUS) If you used the attenuation function that takes a radius, can you
figure out how to make the size of the box reflect this?
Details
Ambient Light
- The
color of ambient light should be quite dark. You probably shouldn't have
any individual RGB value above 0.2
Point Light Attenuation
- Light
in real life obeys an inverse square law, meaning the intensity is
proportional to 1/(d^2), where d is the distance from the light to the
fragment.
- In
games a linear falloff is also often used, meaning the intensity is
proportional to 1/d.
- The
obvious thing to do is to choose some constant k for your point light, and
then use k/(d^2) or k/d, but this has some problems. The attenuation
should only decrease the base intensity, and there is the risk of dividing
by zero.
- An
equation that keeps the same simple spirit of the one above is to use
either 1/(1 + k(d^2)) or 1/(1 + kd).
- One
interesting variation on the above you may want to try is 1/(1 +
(d/r))^2, where r is the radius of the light (in other words, a
spherical light with a bigger radius will be brighter than one with a
small radius). Choosing a radius may be more intuitive for you than
choosing an arbitrary constant "k" value. The equation above is
from here, and I would encourage you to read
that link to get a bit more insight into it and point light attenuation in
general.
- There
are many variations off attenuation function. I would
recommend choosing one of the ones I've listed here in bold, but feel free
to try other things if you have time and interest. (If you have neither
time nor interest, choose the recommended one here that seems the easiest
:)
Specular LIghting
- We
will do classic Phong specularity in our class. The algorithm is something
like:
- Calculate
the specular lighting
- Get
the normalized light direction L
- Get
the normal N
- Calculate
the reflected light direction R
- The
easiest way is with the HLSL instruction:
- R
= reflect(L, N)
- You
can also calculate this yourself:
- R
= L - (2 * N * dot(L, N) )
- Note
that L in this case is the vector from the light to the surface; if you
have the other direction calculated remember that you can just use -L
in either of the above equations
- Calculate
the normalized view direction V
- This
is the vector from the fragment to the camera
- V
= normalize(-g_transform_worldToView[3].xyz - position_world)
- (Can
you figure out why that's the position of the camera?)
- Calculate
how parallel the reflected light is to the viewer
- dotProduct
= saturate( dot(R, V) )
- Raise
that to the specular exponent to change the highlight based on how
rough/smooth the material is
- specularLighting
= pow( dotProduct, g_specular_exponent )
- Just
like diffuse light, there shouldn't be any specular light when the
surface normal is pointing away from the light
- specularLighting
*= dot(L, N)
- (Or
dot(-L, N), depending on what L is. Remember what you're doing
conceptually, rather than just copying and pasting this code!)
- Specular
lighting should be affected by the light's intensity,
but not by its color
- specularLighting
*= lightIntensity
- Add
the specular lighting to the fragment after the diffuse
lighting has been combined with the diffuse color:
- litFragment
= ( diffuseColor * diffuseLighting ) + specularLighting
PIX Events
- Use
D3DPERF_BeginEvent() to start a new nested event
- Use
D3DPERF_EndEvent() to end a nested event
- Each
BeginEvent() call must be paired with an EndEvent() call
- The
documentation for these is hard to find... Microsoft seems to have erased
it online, but it is still in the regular DirectX documentation (not in
the specialized Graphics documentation like everything else we've used in
class)
- BeginEvent()
asks for a color, which allegedly will color-code the event in PIX. I
don't think this works, so you can just use a 0 for the D3DCOLOR.
- BeginEvent()
also wants a string for the label of the event, but this is a _wide_
string. The easiest way to do this is to preface string literals with a
capital L, like so:
- D3DPERF_BeginEvent( 0, L"My Cool Event" );
No comments:
Post a Comment