210 likes | 387 Views
10 . 2. HLSL Effects II. More advanced forms of effect. HLSL Effects : Refractoion. Refraction HLSL effect. Refraction. A refraction effect is the change in direction of a wave (e.g. light/sound) due to a change in speed (typically when moving from one medium to another).
E N D
10.2.HLSL Effects II More advanced forms of effect
HLSL Effects : Refractoion Refraction HLSL effect
Refraction A refraction effect is the change in direction of a wave (e.g. light/sound) due to a change in speed (typically when moving from one medium to another). The effect can be described using Snell's law which states that the angle of incidence (θ1) is related to the angle of refraction (θ2) based on the refractive index of each medium (n1, n2) as follows:
Refraction This particular implement will use three (full-screen) render targets: Refraction target – containing the source scene on which the refraction effect will be applied. Diffuse target – source texture (e.g. stained glass windows) that will be alpha combined within the refraction effect. Normal target – in order to simulate refraction we need to know the surface normal (held in this render target)
Refraction (definitions) GraphicsDeviceManager graphics; Texture2D scene; Texture2D refractionNormal; Texture2D refractionDiffuse; float refractionOpacity = .2f; float normalMapHeight = .05f; RenderTarget2D sceneTarget; RenderTarget2D refractionNormalTarget; RenderTarget2D refractionDiffuseTarget; sceneTarget = new RenderTarget2D( graphics.GraphicsDevice, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color ); refractionNormalTarget = // same as above refractionDiffuseTarget = // same as above In this example, a ‘mock’ scene is held within a texture as the refraction background Three render targets are defined to hold the rendered scene and any refraction normal+diffuse textures Each render target is constructed to be the same size as the screen. This is convenient, however it is inefficient if the refracted textures only covers a small bit of the screen. The fraction surface normals are defined alongside a diffuse image (e.g. stained glass windows) that will be alpha combined with the background scene). This specifies the alpha value to be used to combine the diffuse texture within the effect Height of each normal, controlling the strength of the refraction effect
Refraction (draw) protected override void Draw(GameTimegameTime) { RenderScene (); RenderRefractionDiffuseMap(); RenderRefractionNormalMap(); refractionEffect.Parameters[“refractionDiffuse"]. SetValue(refractionDiffuseTarget.GetTexture()); refractionEffect.Parameters[“refractionNormal"]. SetValue(refractionNormalTarget.GetTexture()); refractionEffect.Parameters[" refractionOpacity"]. SetValue(refractionOpacity); refractionEffect.Parameters["normalMapHeight"]. SetValue(normalMapHeight); batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None); refractionEffect.Begin(); refractionEffect.CurrentTechnique.Passes[0].Begin(); batch.Draw( sceneTarget.GetTexture(), new Rectangle( 0, 0, graphics.GraphicsDevice.PresentationParameters.BackBufferWidth, graphics.GraphicsDevice.PresentationParameters.BackBufferHeight), Color.White); refractionEffect.CurrentTechnique.Passes[0].End(); refractionEffect.End(); batch.End(); base.Draw(gameTime); } Draw the base scene into the reflection map Draw the generated scene texture to the screen, passing the texture through the refraction effect Define the regions that will be refracted alongside refactionnormals and diffuse textures Pass the relevant parameters into the effect in preparation for drawing
private void RenderScene () { graphics.GraphicsDevice. SetRenderTarget(0, sceneTarget); graphics.GraphicsDevice. Clear(Color.TransparentBlack); batch.Begin(); batch.Draw( scene, new Rectangle( 0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height), Color.White); batch.End(); graphics.GraphicsDevice. SetRenderTarget(0, null); } • Refraction (draw) Set the desired render target Ensure all pixels have a default alpha value of 0 The RenderScene, RenderRefractionDiffuseMap, and RenderRefractionNormalMapmethods all have the same structure and simply draw the relevant texture to the corresponding full-screen render target. Obviously the batch can be used to draw numerous images (either defining the background scene or using multiple refractive objects) Change the render target to the back buffer
float4 RefractionPixelShader( float2 texCoord : TEXCOORD0) : COLOR0 { float4 colour = 0; float4 texColour = tex2D(diffuseSampler, texCoord); if (texColour.a > 0) { float4 normal = tex2D(normalSampler, texCoord); float2 offset = normalMapHeight * normal.rg; float4 refractedColour = tex2D( sceneSampler , texCoord + offset); colour = (texColour * refractionOpacity) + (refractedColour * (1.0f - refractionOpacity)); } else { colour = tex2D(sceneSampler , texCoord); } return colour; } • Refraction (shader) sampler sceneSampler : register(s0); texture refractionDiffuse; sampler diffuseSampler = sampler_state { Texture = (refractionDiffuse); }; float refractionOpacity = .5; texture refractionNormal; sampler normalSampler = sampler_state { Texture = (refractionDiffuse); }; float normalMapHeight = .05; technique Refraction { pass Pass0 { PixelShader = compile ps_2_0 RefractionPixelShader(); } } Background scene sampler Define the output colour and retrieve the diffuse refraction colour for current pixel Diffuse refraction texture and alpha value Test to see if this pixel should be refracted (alpha value > 0) Extract the corresponding normal and transform into a texture lookup offset Normal refraction texture and normal height Determine the refracted colour Combine the refracted colour with the diffuse refraction colour Technique definition If alpha value = 0, it is assumed there is no refraction, i.e. just return normal colour
HLSL Effects : Shockwave Shockwave HLSL effect
Shockwave A shockwave effect is a wavelike effect that expands out from some centre point. A shockwave can be defined to have a wave front and wave tail. Typically the wave front is more ‘compressed’ than the wave tail. Wave front Wave tail Radius Centre
Shockwave (definitions) GraphicsDeviceManager graphics; SpriteBatch batch; Effect shockwaveEffect; Texture2D scene; RenderTarget2D renderTarget; double time; boolisAdditive; renderTarget = new RenderTarget2D(graphics.GraphicsDevice, graphics.GraphicsDevice, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color ); Core objects used to define and support the operation of the effect In this example, a ‘mock’ scene is held within a texture as the refraction background The render target is used to hold the shockwave (build using the scene texture), which is then recombined with the scene The shockwave time spans from 0 (just started) to 1 (maximum duration) The isAdditive flag determines if additive or normal alpha blending is employed.
protected override void Draw(GameTimegameTime) { graphics.GraphicsDevice. SetRenderTarget(0, renderTarget); batch.Begin(); batch.Draw( scene, new Rectangle( 0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height), Color.White); batch.End(); graphics.GraphicsDevice.SetRenderTarget(0, null); batch.Begin(); batch.Draw( renderTarget.GetTexture(), new Rectangle( 0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height), Color.White); batch.End(); // ... • Shockwave (update+draw) Setup the render target protected override void Update( GameTimegameTime) { time += gameTime. ElapsedGameTime.TotalSeconds; if (time > 1.0f) time = 0.0f; } Draw the base scene into the render target – typically lots of drawing Draw the rendered scene to the back buffer
Shockwave (draw) Generate the shockwave using the render target and draw to the back buffer. shockwaveEffect.Parameters["xcenter"].SetValue(0.5f); shockwaveEffect.Parameters["ycenter"].SetValue(0.5f); shockwaveEffect.Parameters["width"].SetValue((float) time * 0.75f); shockwaveEffect.Parameters["magnitude"].SetValue((1.0f - (float) time )); batch.Begin( Additive ? SpriteBlendMode.Additive : SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None); shockwaveEffect.Begin(); EffectPass pass = shockwaveEffect.CurrentTechnique.Passes[0]; pass.Begin(); batch.Draw(renderTarget.GetTexture(), new Rectangle( 0, 0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height), pass.End(); shockwaveEffect.End(); batch.End(); } Store the centre of the shockwave (in texture space, i.e. from 0 to 1) Set the current width and magnitude of the shockwave (expanding width and diminishing magnitude over time) Start the sprite batch with the correct blend mode Render the generated scene using the shockwave effect
float4 shockwave(float2 texCoord : TEXCOORD0) : COLOR0 { float4 colour; float xdif = texCoord.x - xcenter; float ydif = texCoord.y - ycenter; float distance = sqrt(xdif * xdif + ydif * ydif) - width; float offset = abs(d); if (distance < 0.1 && distance > -0.2) { if (distance < 0.0) offset = (0.2 - offset) / 2.0; else offset = (0.1 - offset); texCoord.x += -(xdif * offset * magnitude); texCoord.y += -(ydif * offset * magnitude); colour = tex2D(samplerState, texCoord ); colour.a = offset * 12.0; } else { colour.a = 0.0; } return colour; } Determine distance from centre of shockwave. Set initial texture lookup offset to abs(distance) • Shockwave (shader) sampler2D samplerState : register(s0); float xcenter; float ycenter; float magnitude; float width; technique shockwave { pass { pixelShader = compile ps_2_0 shockwave(); } } If pixel is within shockwave radius, then determine offset lookup (the front of the wave is more strongly ramped than the tail of the wave) Define the centre of the shockwave, alongside its current magnitude and width Determine the shockwave’s pixel colour Fade the shockwave out towards the edges of the wave If not part of the shockwave, then set the alpha value to zero
HLSL Effects : Point Sprites Using HLSL to draw point sprites
Point Sprites (particle effects with point sprites) If not using point sprites, each particle must be rendered using a screen aligned quad (i.e. two triangles sharing four vertices). Using point sprites, only one vertex need be sent per particle with any drawn texture automatically mapped and aligned towards the screen. The vertex/pixel shader can be used to update the particle effect (i.e. freeing up the CPU). Point sprites can be equally used within 2D and 3D games.
Point Sprites (defining a custom vertex) public structCustomVertexDefinition { public Vector3 Position; public float PointSize; public static intSizeInBytes = (3+1) * sizeof(float); public CustomVertexDefinition( Vector3 Position, float PointSize) { this.Position = Position; this.PointSize = PointSize; } public static VertexElement[] VertexElements = { new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement(0, sizeof(float)*3, VertexElementFormat.Single, VertexElementMethod.Default, VertexElementUsage.PointSize, 0) }; } The parameters needed to drive the point sprite effect should be defined here (ranging from a simple position, to a scale, alpha value, etc., etc. The total size of the vertex (in bytes) must be defined here. Currently four floats. Each vertex element is defined here. The second VertexElement parameter defines the offset for that element. The VertexElementUsage will enable the vertex element to be semantically mapped within the shader. CustomVertexDefinition[] spriteArray= new CustomVertexDefinition[numSprites]; VertexDeclarationcustomVertexDeclaration = new VertexDeclaration( graphics.GraphicsDevice, CustomVertexDefinition.VertexElements);
Point Sprites(world view projection matrix) MatrixwvpMatrix = worldMatrix * viewMatrix * projectionMatrix; How wide and far the camera can see The combined world-view-projection matrix Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView( fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance ); Matrix viewMatrix = Matrix.CreateLookAt( cameraPosition, cameraTarget, cameraUpVector ); Matrix worldMatrix = Matrix.Identity * Matrix.CreateTranslation( new Vector3( 0, 0, -5) ) ; What the camera is looking at The world location of the camera
Point Sprites(drawing point sprites) protected override void Draw(GameTimegameTime) { graphics.GraphicsDevice.RenderState.PointSpriteEnable = true; graphics.GraphicsDevice.VertexDeclaration = vertexPosColDecl; // ... pointSpritesEffect.Begin(); foreach (EffectPass pass in pointSpritesEffect.CurrentTechnique.Passes) { pass.Begin(); graphics.GraphicsDevice.DrawUserPrimitives<CustomVertexDefinition>( PrimitiveType.PointList, spriteArray, 0, spriteArray.Length); pass.End(); } pointSpritesEffect.End(); graphics.GraphicsDevice.RenderState.PointSpriteEnable = false; } Instruct the GPU to consider vertices as point sprites Specify the vertex format that will be used Store other shader parameters, e.g. wvp matrix, etc. Run the shader (e.g. particle effect) Pass the created point sprite verticies to the GPU Turn off point sprite drawing
Point Sprites(shader) Define the world-view-projection matrix float4 vertexShader( float4 position : POSITION0) : POSITION0 { // Vertex parameter transformation return mul(position, wvpMatrix); } float4 pixelShader( PixelShaderInput input) : COLOR0 { float4 colour = tex2D(pointSpriteSampler, input.texCoord.xy ); // Transform pixel colour return colour; } float4x4 wvpMatrix; texture pointSpriteTexture; sampler pointSpriteSampler = sampler_state { texture = <pointSpriteTexture>; }; structPixelShaderInput { #ifdef XBOX float2 texCoord : SPRITETEXCOORD; #else float2 texCoord : TEXCOORD0; #endif }; Define the point sprite texture Transform any vertex parameters if needed Translate world particle position to the on-screen position As the PC and XBox 360 use different input semantics when using point sprites, ensure a correct mapping Determine the base particle colour Transform the output colour if needed
Summary Today we explored: • Development of a refraction and shockwave shader effect • Exploration of point sprites and how they can be used for particle effects To do: • Complete Question Clinic • If using XNA, decide if you want to introduce custom effects into your game.