1 / 99

Illumination and Shading

Illumination and Shading. Lights Diffuse and Specular Illumination BasicEffect Setting and Animating Lights Shaders and HLSL Lambertian Illumination Pixel Shaders Textures. The XNA graphics pipeline. Multiply by World Matrix. Effect. Multiply by View Matrix. Vertex Shader.

signa
Télécharger la présentation

Illumination and Shading

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Illumination and Shading Lights Diffuse and Specular Illumination BasicEffect Setting and Animating Lights Shaders and HLSL Lambertian Illumination Pixel Shaders Textures

  2. The XNA graphics pipeline Multiply by World Matrix Effect Multiply by View Matrix Vertex Shader Compute Color Vertex position Vertex normal Texture coordinate Vertex color other stuff sometimes… Multiply by Projection Matrix Homogenize and Clip Shade Pixel Shader

  3. Some Terms Illumination – What gives a surface its color. This is what our effect will compute. Material – Description of the surface. Will include one or more colors. These are parameters set in the effect. Reflection – The reflection of light from a surface. This is what we will simulate to compute the illumination. Shading – Setting the pixels to the illumination We’ll often use reflection and illumination just about interchangeably.

  4. Effects/Shaders

  5. My First Effect: FirstEffect.fx float4x4 World; float4x4 View; float4x4 Projection; struct VertexShaderInput { float4 Position : POSITION0; }; struct VertexShaderOutput { float4 Position : POSITION0; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return float4(1, 0, 0, 1); } technique FirstShader { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } This is the default effect Visual Studio will create when you do New/Effect. It does nothing except set pixels to red.

  6. What this does Anywhere there is something to draw, it draws red Always something to draw other than through the window.

  7. How to use this… firstEffect = Content.Load<Effect>("FirstEffect"); foreach (ModelMesh mesh in Bedroom.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { part.Effect = firstEffect; } } Loading/Installing in LoadContent() Drawing protected void DrawModel(GraphicsDevice graphics, Camera camera, Model model, Matrix world) { Matrix[] transforms = new Matrix[model.Bones.Count]; model.CopyAbsoluteBoneTransformsTo(transforms); foreach (ModelMesh mesh in model.Meshes) { foreach (Effect effect in mesh.Effects) { effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] * world); effect.Parameters["View"].SetValue(camera.View); effect.Parameters["Projection"].SetValue(camera.Projection); } mesh.Draw(); } }

  8. What does what… effect.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] * world); effect.Parameters["View"].SetValue(camera.View); effect.Parameters["Projection"].SetValue(camera.Projection); Sets float4x4 World; float4x4 View; float4x4 Projection; Setting the effect parameter sets the equivalent value inside the effect.

  9. The process VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); return output; } The Vertex Shader runs first It converts object vertex coordinates into projected coordinates. The Pixel shader runs next. It computes the actual pixel color Once per vertex float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return float4(1, 0, 0, 1); } Once per pixel

  10. Adding a Material Property I added this line to the veretx shader And changed the pixel shader to this // This is the surface diffuse color float3 DiffuseColor = float3(0, 0, 0); float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return float4(DiffuseColor, 1); }

  11. Setting this Effect private void SetDiffuseColorEffect() { foreach (ModelMesh mesh in Bedroom.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { BasicEffect bEffect = part.Effect as BasicEffect; part.Effect = diffuseColorEffect.Clone(part.Effect.GraphicsDevice); part.Effect.Parameters["DiffuseColor"].SetValue(bEffect.DiffuseColor); } } } The default content processing supplied a BasicEffect object with the color set in it. We’re creating our own effect and setting the color to match what was loaded. Note the “Clone”. This makes a copy of the effect. Since we’re putting a material property into it, we need a unique copy here.

  12. What this does Each pixel is simply set to the material diffuse color. No lighting is included, yet.

  13. Now let’s do real lighting VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); float3 color = LightAmbient * DiffuseColor; output.Color = float4(color, 1); return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color; } technique FirstShader { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } float4x4 World; float4x4 View; float4x4 Projection; // This is the surface diffuse color float3 DiffuseColor = float3(0, 0, 0); // Light definition float3 LightAmbient = float3(0.07, 0.1, 0.1); struct VertexShaderInput { float4 Position : POSITION0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; }; I’ve moved our computation to the vertex shader (why?). Ambient illumination is simply the light ambient color times the surface diffuse color.

  14. Some Things VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); float3 color = LightAmbient * DiffuseColor; output.Color = float4(color, 1); return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color; } technique FirstShader { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } float4x4 World; float4x4 View; float4x4 Projection; // This is the surface diffuse color float3 DiffuseColor = float3(0, 0, 0); // Light definition float3 LightAmbient = float3(0.07, 0.1, 0.1); struct VertexShaderInput { float4 Position : POSITION0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; }; Note that the VertexShaderOutput now has a color. TT

  15. What this looks like Inset has brightness artificially increased in Photoshop

  16. Now for Diffuse Illumination • What we need to know • Light location in space • Light color float3 Light1Location = float3(5, 221, -19); float3 Light1Color = float3(1, 1, 1);

  17. HLSL code // Light definition float3 LightAmbient = float3(0.07, 0.1, 0.1); float3 Light1Location = float3(5, 221, -19); float3 Light1Color = float3(1, 1, 1); struct VertexShaderInput { float4 Position : POSITION0; float3 Normal : NORMAL0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; }; We need to know the normal

  18. Vertex Shader Light1Location VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; // We need the position and normal in world coordinates float4 position = mul(input.Position, World); float3 normal = normalize(mul(input.Normal, World)); // Ambient lighting hitting the location float3 color = LightAmbient; // Compute direction to the light float3 Light1Direction = normalize(Light1Location - position); // Add contribution due to this light color += saturate(dot(Light1Direction, normal)) * Light1Color; // Multiply by material color color *= DiffuseColor; output.Color = float4(color.x, color.y, color.z, 1); float4 viewPosition = mul(position, View); output.Position = mul(viewPosition, Projection); return output; } Light1Location - position Light1Direction normal position

  19. What this looks like What is missing?

  20. Texture Mapping Mapping a picture onto the surface of a triangle.

  21. HLSL – Adding a texture variable // The texture we use texture Texture; Not everything in our scene is texture mapped. If it is texture mapped, we use the texture color as the diffuse color. If not, we use the set diffuse color. We have two different ways we will compute the color. float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor, 1);; } I’ll move the multiplication by the Diffuse Color to the pixel shader.

  22. Slightly modified version, now. VertexShaderOutputVertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; // We need the position and normal in world coordinates float4 position = mul(input.Position, World); float3 normal = normalize(mul(input.Normal, World)); // Ambient lighting hitting the location float3 color = LightAmbient; // Compute direction to the light float3 Light1Direction = normalize(Light1Location - position); // Add contribution due to this light color += saturate(dot(Light1Direction, normal)) * Light1Color; // Multiply by material color color *= DiffuseColor; output.Color = float4(color, 1); float4 viewPosition = mul(position, View); output.Position = mul(viewPosition, Projection); return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor, 1); }

  23. We need something called a “sampler” sampler Sampler = sampler_state { Texture = <Texture>; MinFilter = LINEAR; MagFilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; This just parameterizes how we get pixels from our texture. Wrap means tiling will be used. LINEAR means linear interpolation. We’ll do some other options later.

  24. And, we need to have the texture coordinates struct VertexShaderInput { float4 Position : POSITION0; float3 Normal : NORMAL0; float2 TexCoord : TEXCOORD0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; And add this to the vertex shader function: output.TexCoord = input.TexCoord;

  25. Techniques We have two ways things will be treated. We could create two different effects. But, it’s easier to create one effect with two different “techniques”. float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor.x, DiffuseColor.y, DiffuseColor.z, 1); } technique NoTexture { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } Here is the technique we had before.

  26. Techniques float4 PixelShaderTexturedFunction(VertexShaderOutput input) : COLOR0 { return input.Color * tex2D(Sampler, input.TexCoord); } technique Textured { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderTexturedFunction(); } } This is the other technique

  27. float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor.x, DiffuseColor.y, DiffuseColor.z, 1); } float4 PixelShaderTexturedFunction(VertexShaderOutput input) : COLOR0 { return input.Color * tex2D(Sampler, input.TexCoord); } technique NoTexture { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } technique Textured { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderTexturedFunction(); } } All in one place so you can see it.

  28. Loading This Effect private void SetLambertianTextureEffect() { foreach (ModelMesh mesh in Bedroom.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { part.Effect = effectsOrig[part]; BasicEffect bEffect = part.Effect as BasicEffect; part.Effect = lambertianTextureEffect.Clone(part.Effect.GraphicsDevice); part.Effect.Parameters["DiffuseColor"].SetValue(bEffect.DiffuseColor); part.Effect.Parameters["Texture"].SetValue(bEffect.Texture); if (bEffect.Texture != null) { part.Effect.CurrentTechnique = part.Effect.Techniques["Textured"]; } else { part.Effect.CurrentTechnique = part.Effect.Techniques["NoTexture"]; } } } }

  29. What we get

  30. The complete effect – Variables and types float4x4 World; float4x4 View; float4x4 Projection; // This is the surface diffuse color float3 DiffuseColor = float3(0, 0, 0); texture Texture; // Light definition float3 LightAmbient = float3(0.07, 0.1, 0.1); float3 Light1Location = float3(5, 221, -19); float3 Light1Color = float3(1, 1, 1); struct VertexShaderInput { float4 Position : POSITION0; float3 Normal : NORMAL0; float2 TexCoord : TEXCOORD0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; sampler Sampler = sampler_state { Texture = <Texture>; MinFilter = LINEAR; MagFilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; };

  31. The complete effect – Vertex shader VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; output.TexCoord = input.TexCoord; // We need the position and normal in world coordinates float4 position = mul(input.Position, World); float3 normal = normalize(mul(input.Normal, World)); // Ambient lighting hitting the location float3 color = LightAmbient; // Compute direction to the light float3 Light1Direction = normalize(Light1Location - position); // Add contribution due to this light color += max(dot(Light1Direction, normal), 0) * Light1Color; output.Color = float4(color.x, color.y, color.z, 1); float4 viewPosition = mul(position, View); output.Position = mul(viewPosition, Projection); return output; }

  32. The complete effect = Pixel Shader and Techniques float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor.x, DiffuseColor.y, DiffuseColor.z, 1); } float4 PixelShaderTexturedFunction(VertexShaderOutput input) : COLOR0 { return input.Color * tex2D(Sampler, input.TexCoord); } technique NoTexture { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } } technique Textured { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderTexturedFunction(); } }

  33. Specular Illumination Specular Reflections Reflections from the surface of the material Generally a different color than the underlying material diffuse color

  34. More Specular Examples Specular Reflection makes things appear shiny The left Dalek has no specular illumination, the right does

  35. Previous lighting components Ambient Ia=Ambient part of illumination Md=Diffuse material color Ca=Light ambient color Diffuse Illumination Id=Diffuse part of illumination Md=Diffuse material color Ci=Color of light I Li=Vector pointing at light I N=Surface normal float3 color = LightAmbient; return input.Color * float4(DiffuseColor, 1); color += max(dot(Light1Direction, normal), 0) * Light1Color; return input.Color * float4(DiffuseColor, 1);

  36. Specular Component Specular Component Is=Specular part of illumination Ms=Specular material color Ci=Color of light I N=Surface normal H=“Half vector” n=Shininess or SpecularPower Basic HLSL code // Add specular contribution due to this light float3 V = normalize(Eye - position); float3 H = normalize(Light1Direction + V); scolor += pow(saturate(dot(normal, H)), Shininess) * Light1Color;

  37. Specular Reflection Highlight Coefficient • The term n is called the specular reflection highlight coefficient or “Shininess” or “Specular Power” • This effects how large the spectral highlight is. A larger value makes the highlight smaller and sharper. • This is the “shininess” factor in OpenGL, SpecularPower in XNA • Matte surfaces has smaller n. • Very shiny surfaces have large n. • A perfect mirror would have infinite n.

  38. Shininess Examples n=35 n=1 n=10 n=65 n=100

  39. // This is the surface diffuse color float3 DiffuseColor = float3(0, 0, 0); float3 SpecularColor = float3(0, 0, 0); float Shininess = 0; texture Texture; // Light definition float3 LightAmbient = float3(0.07, 0.1, 0.1); float3 Light1Location = float3(5, 221, -19); float3 Light1Color = float3(1, 1, 1); float3 Eye = float3(0, 0, 0); structVertexShaderInput { float4 Position : POSITION0; float3 Normal : NORMAL0; float2 TexCoord : TEXCOORD0; }; structVertexShaderOutput { float4 Position : POSITION0; float4 Color : COLOR0; float4 SColor : COLOR1; float2 TexCoord : TEXCOORD0; }; HLSL New shader variables

  40. Vertex Shader VertexShaderOutputVertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; output.TexCoord = input.TexCoord; float4 position = mul(input.Position, World); float3 normal = normalize(mul(input.Normal, World)); // Ambient lighting hitting the location float3 color = LightAmbient; float3 scolor = 0; // Compute direction to the light float3 Light1Direction = normalize(Light1Location - position); // Add diffuse contribution due to this light color += max(dot(Light1Direction, normal), 0) * Light1Color; // Add specular contribution due to this light float3 V = normalize(Eye - position); float3 H = normalize(Light1Direction + V); scolor += pow(saturate(dot(normal, H)), Shininess) * Light1Color; output.Color = float4(color, 1); output.SColor = float4(scolor, 1); float4 viewPosition = mul(position, View); output.Position = mul(viewPosition, Projection); return output; } Note that we send the specular illumination separate from the diffuse illumination. Any ideas why?

  41. Pixel Shaders float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.Color * float4(DiffuseColor, 1) + input.SColor * float4(SpecularColor, 1); } float4 PixelShaderTexturedFunction(VertexShaderOutput input) : COLOR0 { return input.Color * tex2D(Sampler, input.TexCoord) + input.SColor * float4(SpecularColor, 1); } Important: We only multiply the texture color by the diffuse illumination, not the specular illuminations. We can have another texture map for specular illumination sometimes.

  42. Those extra parameters Setting up the effect: BasicEffectbEffect = part.Effect as BasicEffect; part.Effect = diffuseSpecularEffect.Clone(part.Effect.GraphicsDevice); part.Effect.Parameters["DiffuseColor"].SetValue(bEffect.DiffuseColor); part.Effect.Parameters["SpecularColor"].SetValue(bEffect.SpecularColor); part.Effect.Parameters["Shininess"].SetValue(bEffect.SpecularPower); When you draw: effect.Parameters["Eye"].SetValue(camera.Eye);

  43. Phong Shading or Per-Pixel Lighting All of the methods we have used computed the lighting at the vertex and interpolated the color between the vertices. Phong Shading interpolates the normal over the surface and computes the color at every pixel. Will always look better and the only way to do some effects light spotlights, but can be costly!

  44. HLSL structVertexShaderOutput { float4 Position : POSITION0; float2 TexCoord : TEXCOORD0; float4 WorldPosition : TEXCOORD1; float3 Normal : TEXCOORD2; }; We put the world position and the normal into “texture coordinates” because these are interpolated for the pixel shader.

  45. Vertex Shader VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; // We need the position and normal in world coordinates output.TexCoord = input.TexCoord; output.WorldPosition = mul(input.Position, World); output.Normal = normalize(mul(input.Normal, World)); output.Position = mul(mul(output.WorldPosition, View), Projection); return output; } This does surprisingly little!

  46. Pixel Shader (no texture version) float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float3 normal = input.Normal; float4 position = input.WorldPosition; // Ambient lighting hitting the location float3 color = LightAmbient; float3 scolor = 0; // Compute direction to the light float3 Light1Direction = normalize(Light1Location - position); // Add diffuse contribution due to this light color += max(dot(Light1Direction, normal), 0) * Light1Color; // Add specular contribution due to this light float3 V = normalize(Eye - position); float3 H = normalize(Light1Direction + V); scolor += pow(saturate(dot(normal, H)), Shininess) * Light1Color; return float4(color * DiffuseColor + scolor * SpecularColor, 1); } Identical to Vertex Shader Version, just moved!

  47. Shader Models technique NoTexture { pass Pass1 { VertexShader = compile vs_2_0VertexShaderFunction(); PixelShader = compile ps_2_0PixelShaderFunction(); } } A “shader model” specifies the capabilities we require. 2.0 is required to support using the texture coordinates this way. You also needed 2.0 for the many matrices in the skinned model.

  48. Other extremes of efficiency Graphics systems such as Maya and 3DS Max can precompute the color for every vertex in advance and save it with the vertex data. We call this Vertex Lighting.

  49. Vertex Lighting VertexShaderOutputVertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; output.Position = mul(input.Position, Matrix); output.Color = input.Color; output.TexCoord = input.TexCoord; return output; } float4 PixelShaderTexture(PixelShaderInput input) : COLOR0 { float4 color = input.Color; float4 texColor = tex2D(Sampler, input.TexCoord); color.rgba *= texColor; return color; } float4 PixelShader(PixelShaderInput input) : COLOR0 { return input.Color; }

  50. The Ultimate Extreme float4 PixelShaderTexture(PixelShaderInput input) : COLOR0 { float4 color = input.Color; float4 texColor = tex2D(Sampler, input.TexCoord); color.rgba *= texColor; return color; } float4 PixelShader(PixelShaderInput input) : COLOR0 { return input.Color; } It’s possible to even avoid this bit of work and keeping the colors around. Instead, the graphics system creates a version of the texture with the lighting pre-multiplied into it. We call this Baked Textures.

More Related