Catalin's profileCatalin 's BlogBlogLists Tools Help

Blog


    February 09

    New Site Online!

     

    I am moving my blog / site to a new location: www.catalinzima.com

    There you will find all my samples and tutorials, and all new stuff will be hosted there.

    The site has different sections containing tutorials, samples and other miscellaneous downloads. Also, it begins its existence with a new goal: 12 months, 12 samples. You can read about what this means, in my welcome post, here. I hope you enjoy the site.

    Thank you,
    Catalin Zima

    P.S. This blog will remain alive, for announcements and whatever else it will be needed for.

    January 22

    HLSL Learning Resources

    In response to some people asking me how to start learning shader programming, I made a list of some resources that could prove helpful when learning HLSL:

    The Shader Series, found on creators.xna.com are a very good set of articles and samples, that explain the basic knowledge needed to understand and write shaders in HLSL.

    Riemer Grootjans also has a series of tutorials on HLSL, which can be found on his site.

    A very good book on shaders (in my opinion, the best book on shaders I've read) is The Microsoft DirectX 9 Programmable Graphics Pipeline by Kris Gray. I found this book extremely useful, with very good explanations, and nicely structured. The code samples, however, are in C/C++, but for most people that shouldn't be a problem.

    After mastering the basics, you can explore other samples and articles, which can be found on www.ziggyware.com and creators.xna.com.

    Another good place to find information on shaders are the web pages of the two big GPU manufacturers, NVIDIA and ATI. Each site has a section devoted to developers, which are great places for everyone, beginners are advanced users alike. Both sites provide code samples, documentation, tools and SDK's. Out of these, my favorites are NVIDIA Shader Library, NVIDIA SDK and ATI SDK. Most important, these site contains lots of articles and presentations from various conferences, which explain a wide range of effects and techniques, and how they are achieved on the GPU. Admittedly, most of them do not provide HLSL code, but the idea and algorithm is almost always more important than the code itself.

    For advanced effects and usages of the GPU, I recommend the GPU Gems series and the ShaderX series.

    Finally, as a recommendations for those who want to learn HLSL, try to examine as many samples as possible, and play with the HLSL code to see what happens when changing values, until you understand why things happen the way they do. Don't start by doing HDR Lighting, or Relief Mapping. Start with the small tutorials, and understand what happens and why before going on to the more spectacular samples. Last, but not least, don't be afraid to look at C/C++ samples. The DirectX SDK contains some very good samples of HLSL. I know, they're written in C/C++, but the shader code stays the same when going from C++ to XNA.

    January 19

    XNA 2D Pie Sample

     

    After I've seen some people asking how to do this on the forums, I decided to make a small class that allows us to draw Pies in 2D in XNA.

    To use it, just create a new Pie2D object. The constructor receives parameters for the radius, angle and tessellation. These can also be modified at runtime, and the shape will be altered appropriately.

    I made a sample that shows how to use this class. You can download it here: Pie2DSample.zip

    Pie2DSample 2008-01-19 02-50-16-17

    A pie could be useful in 2D games for various effects, like enemy visibility area, flashlights, shields, etc.

    January 17

    Model Manipulation using the Mouse

     

        A friend of mine asked me about a small XNA sample where he could manipulate a model using the mouse. I made something up quick. It is not much, but I though I'd share it with the community, maybe someone will find it useful.

    Controls:

    • Left Mouse Button + Drag to rotate the model around the Y axis
    • Right Mouse Button + Drag to scale the model

    You can download it here: MouseManipulator.zip

    January 14

    Ziggyware XNA Holiday Contest winners announced!

     

    I happily announce that I have again won Ziggyware's XNA Holiday Contest

    The three winning articles are:

    1. Deferred Shading in XNA - Catalin Zima

    2. Depth of Field - Kyle Schouviller

    3. Shadow Mapping - Andrew Joll

    I'd like to congratulate all who entered, and thank Ziggyware for organizing the contest.

    December 31

    Deferred Rendering tutorial online

     

    My article just went online on www.ziggyware.com. You can read it here.

    I hope everyone enjoys it!

    December 24

    New tutorial Coming Soon...

     

    Sorry for the lack of posts recently, but I've been very busy with school and other stuff. Anyway, since XNA 2.0 came out, and Ziggyware has a new contest, I've decided to put some more time into XNA, and try something new.

    One of the new things in XNA 2.0 is the support for Multiple Render Targets on the Xbox. Now that this became available I had the opportunity to try one of my older desires: implementing a deferred renderer. So, my next tutorial will cover implementing a deferred renderer in XNA 2.0.

    Here are some screenshots from what will come soon:

    DefferedRendering 2007-11-29 08-17-37-76

     DefferedRendering 2007-11-29 08-18-13-19

    Lizard drawn with normal mapping, and about 16 moving point lights.

      pointlight

    One point light moving around a ship

      manylights

    Over 20 lights lighting the ship

     Stay tuned for more...

    November 20

    XNA Game Studio 2.0 beta released!

     

    Ok, so I know lots of other sites will have this announced, and if you frequent creators.xna.com you already know this, but I can't not announce this too:

    The beta version of XNA Game Studio 2.0 has been released.

    It's been told that the final version will come pretty soon also, but until then you can experiment with new features included in the beta: multiplayer, virtualised device, project management, etc.

    Go get it HERE.

    November 04

    XNA Achievements (sort of)

    John Wells released a nice little component, which allows us to display messages similar to the Achievement notices on the Xbox 360. Of course, it will not alter your gamerscore, but it adds a very cool touch to a game.

    Here's how it looks in action:

    acheivementtoast-001
    It is nicely packed as a .dll file, together with a couple of content files. You can download it here.

    October 27

    PieMenu Component

     

    For the people who want some UI stuff in XNA, here's a small sample that contains a Pie Menu Component, attached to a cursor. If you don't know what a pie menu is, read about it on wikipedia.

    Now, about the sample.

    My PieMenu supports deep menus, as seen in the sample. Currently it is just a quick version, made in two days. Because of this, the graphics are not spectacular, and some things may not be extremely flexible right now (the parameters passed to delegates).

    But as it is, each menu entry has associated with it an image, a text description, and a delegate, for the action that should be performed. The PieMenu also supports submenus, as seen in this sample.

    The cursor can operate in two modes: mouse-friendly and gamepad friendly. In the mouse friendly mode, the menu options are selected with the cursor, while in gamepad friendly mode, they are selected with the left thumbstick.

    The current sample contains the following menus:

    • Change Gamerpic: allows navigation through a series of submenus, to select a gamerpic that will be displayed in the window
    • Change Background Color: randomly chooses a new background color
    • Toggle Input Mode: toggles between the mouse and gamepad friendly input modes. Default is mouse, so if you don't have a gamepad, don't worry.
    • Exit : exits the sample.

    This is just as an example. The menu can be easily customized. Also, the Cursor.ShowPieMenu() function has an overload that allows you to specify the menu that will be shown. This allows for different menus, depending on the selected object (this is NOT illustrated in this sample)

    Controls:

    • Gamepad A or Mouse Click : open menu, or selected submenu
    • Gamepad B, or Mouse Click when no submenu selected: return to upper menu / exit menu

    You can find the sample here. You can use the code as you see fit, with one exception. If you're working on an entry for the Imagine Cup 2008 competition, and you plan to use it, please give me credit :)

    Comments? Suggestions? (Besides "the graphics suck, make them better")

    October 16

    Mass Effect review in GameInformer

    www.xbox360fanboy.com informs us that GameInformer made a review of Mass Effect, and it received an amazin 9.75
    Here's the review for those interested.
     
    I'm proud to be a fan of this game ;)
     
    October 14

    Tutorial Contest Winner!

    Ziggyware just announced the winners of the XNA Tutorial Contest, and the first place goes to....

    ME! Hurraaaay! Party!!!!

    I'm extremely happy about this, and I want to thank everyone who supported me, who voted for me, and who somehow contributed to this. Also, I want to congratulate all other contestants for their good tutorials!

    Special thanks go to:

    Michael Morton, for organizing the contest!

    Lidia, for every little thing she does, and for her support, understanding, caring and love.

    Nick Gravelyn, for helping Michael with putting my article online

    All my voters :)

    All of the XNA Community

    The XNA Team

    Thank you! I'll do my best to continue providing tutorials and help to the community.

    Gamefest 2007 slides available

     

    Let's Kill Dave has posted the list of Gamefest presentations what will have slides and recordings available for them. Since most of the links were not posted right, Leaf made the needed corrections. You can now find all the links here.

    The titles sound extremely interesting, and I can't wait to devour them.

    I wish you all Happy Reading / Listening :)

    September 22

    Running the VTF Tutorial samples on ATI or SM 2.0 cards

     

            I was talking to Michael Morton (Ziggyware owner) about the possibility of making my code run on ATI cards, and I told him that someone else tried using R2VB in XNA and failed. In that moment, an idea came to me: "Let's simulate R2VB on the CPU". Yes, I know, this sound crazy, but let's analyze a little.

            In my tutorials, because I wanted to use vertex textures, I had to store lots of data in textures and do simulations in textures. Examples of these are: the particle systems, the deformation map creation, applying the deformation map to the displacement map, etc. These were, in a way, secondary effects of using VTF, which actually proved to increase the performance. So, rather than doing everything on the CPU, we will still do these texture manipulations on the GPU.

            First, let me explain how R2VB works. For the most part, the operations I did in the tutorials are exactly the same: use some pixel shader for simulations and deformations. The difference between VTF and R2VB comes on play when you finally have a texture, and you want to use the information from this texture to alter the vertices. As we saw in the tutorial, VTF reads from this texture inside the vertex shader. On the other hand, R2VB takes that information and draws it in a "texture". That "texture" is at the same GPU memory address as a Vertex Buffer, so, when writing to the texture, the information is actually written to the vertex buffer. Hence, the name Render To Vertex Buffer.

            We will emulate this behavior in software, on the CPU. So all the performance gained by doing the simulations using pixel shaders and render-to-texture remains.

            We take the second tutorial, the one with morphing terrain. Let's see what needs to be done. Open Grid.cs, and add the following function.

    Single[] textureData;
    public void DrawCPUSingle(Texture2D displacementTexture)
    { 
                
            displacementTexture.GetData<Single>(textureData);
            for (int i = 0; i < displacementTexture.Height; i++)
            {
                    for (int j = 0; j < displacementTexture.Width; j++)
                            vertices[i * displacementTexture.Width + j].Position.Y = textureData[j * displacementTexture.Height + i];
            }
     
            IGraphicsDeviceService igs = (IGraphicsDeviceService)game.Services.GetService(typeof(IGraphicsDeviceService));
            device = igs.GraphicsDevice;
            device.VertexDeclaration = vertexDecl;
            device.Indices = ib;
            device.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, 2 * dimension * dimension);
    }
     
    public void LoadGraphicsContent()
    {
            textureData = new Single[(dimension + 1) * (dimension + 1)];
            [...]
    }
     

    As you can see, we take as input the texture that would be used as a displacement texture, then we use GetData() on it, and we write that data to our vertex array. The index array is the same as before. After this, instead of using a dynamic vertex buffer, we use the DrawUserIndexedPrimitives.

            Now, we need to modify the VTFDisplacement.fx effect file. The modifications appear in the vertex shader:

    VS_OUTPUT TransformCPU(VS_INPUT In)
    {
            VS_OUTPUT Out = (VS_OUTPUT)0;
            float4x4 viewProj = mul(view, proj);
            float4x4 worldViewProj= mul(world, viewProj);
     
            // we don't read from the texture anymore
            float height = In.position.y;
            In.position.y = height * maxHeight;
            
            Out.worldPos = mul(In.position, world);
            Out.position = mul( In.position , worldViewProj);
            Out.uv = In.uv;
            float4 TexWeights = 0;
        
            TexWeights.x = saturate( 1.0f - abs(height - 0) / 0.2f);
            TexWeights.y = saturate( 1.0f - abs(height - 0.3) / 0.25f);
            TexWeights.z = saturate( 1.0f - abs(height - 0.6) / 0.25f);
            TexWeights.w = saturate( 1.0f - abs(height - 0.9) / 0.25f);
            float totalWeight = TexWeights.x + TexWeights.y + TexWeights.z + TexWeights.w;
            TexWeights /=totalWeight;
             Out.textureWeights = TexWeights;
            return Out;
    }
     
    [...] //pixe shader remains the same
     
    technique GridDrawCPU
    {
        pass P0
        {
            //we can use SM 2.0
            vertexShader = compile vs_2_0 TransformCPU();
            pixelShader  = compile ps_2_0 PixelShader();
        }
    }
     

    The final modifications are done in the Draw function in Game1.cs

    foreach (EffectPass pass in gridEffect.CurrentTechnique.Passes)
         {
                    pass.Begin();
                    grid.DrawCPUSingle(morphRenderTarget.GetTexture());
                    pass.End();
         }

    That's all. The Steps in Snow sample is converted in exactly the same way.

    For the particle system sample, we have the following modifications. In the vertex shader of the file Particle.fx, change the line

    float4 realPosition = tex2Dlod ( positionSampler, 
                              float4(In.vertexData.x, In.vertexData.y,0,0));

    into

    float4 realPosition = In.vertexData;

    In Game1.cs, modify the following code:

     

    Vector4[] textureData;
    protected override void LoadGraphicsContent(bool loadAllContent)
    {
            if (loadAllContent)
            {
                    textureData = new Vector4[particleCount * particleCount];
                    [...]
            }
            [...]
    }
     
    protected override void Draw(GameTime gameTime)
    {
            graphics.GraphicsDevice.Clear(Color.Black);
     
            Render2TextureMorph((float)Math.Sin(gameTime.TotalGameTime.TotalSeconds) * 0.5f + 0.5f);
            Render2TextureNormalCompute();
     
            SimulateParticles(gameTime);
     
            graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            [...]
            graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;           
     
            Texture2D positionTexture = positionRT.GetTexture();
            positionTexture.GetData<Vector4>(textureData);
            for (int i = 0; i < positionTexture.Height; i++)
            {
                    for (int j = 0; j < positionTexture.Width; j++)
                   {
                            vertices[i * positionTexture.Width + j].Position.X = textureData[j * positionTexture.Height + i].X;
                            vertices[i * positionTexture.Width + j].Position.Y = textureData[j * positionTexture.Height + i].Y;
                            vertices[i * positionTexture.Width + j].Position.Z = textureData[j * positionTexture.Height + i].Z;
                   }
            }
            using (VertexDeclaration decl = new VertexDeclaration(
                       graphics.GraphicsDevice, VertexPositionColor.VertexElements))
            {
            graphics.GraphicsDevice.VertexDeclaration = decl;
            renderParticleEffect.Begin();
            renderParticleEffect.CurrentTechnique.Passes[0].Begin();
            graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList, vertices, 0, particleCount * particleCount);
            renderParticleEffect.CurrentTechnique.Passes[0].End();
            renderParticleEffect.End();
            }
            [...]
     

            Same technique used here: process the data on the GPU, in the textures, and then just GetData from the texture, and use it in to draw the particles.

            The problem of performance: here are some experiments I did:

     

    Sample Framerate with vertex textures framerate with GetData()
    Morphing Terrain, with Bilinear Filtering in VTF 100 FPS 65 FPS
    Morphing Terrain, without Biliner Filtering 155 FPS 69 FPS
    Particle System (65536 particles) Terrain Collision, no terrain rendered 130 FPS 65 FPS
    Steps in Snow 260 FPS 80 FPS

            The system this was ran on is Intel Core2 6300 (1.87Ghz), 1 GB RAM, GeForce 7600 GS 256MB

            Some care still has to be taken. Grid.Dimension has to be of size power-of-two-minus-one (255,511, etc). This is just because of my code. By doing this on the CPU, we loose the billinear filtering done in the vertex shader, so the Dimension of the grid has to be the same as the dimension of the displacement texture. (actually, that size minus one, as explained earlier). So, for a heightmap of 256*256, the grid's dimension has to be 255. The bilinear filtering can of course be done on the CPU also, but you'll have to see if it is worth it. These are the only restrictions I can think of.

            I hope this made some of you (ATI owners) more happy about my tutorial :) 

            The source code for the modified chapters is found here: Chapter2CPU.zip, Chapter3CPU.zip and Chapter4CPU.zip

    Vertex Textures tutorial online!

    My article was just posted online on www.ziggyware.com . You can read it HERE.

    Lots of thanks go to Michael Morton and Nick Gravelyn who formatted the article and put it online. Thank you guys very much!

    Please post any comments either on the article's site, or here.

    September 21

    Four uses of Vertex Textures

            I have finished writing my tutorial on vertex textures, and I have submitted it to Ziggyware's XNA Tutorial Contest. It's now in the process of being formatted and arranged, and it will soon be put online.

            The tutorial will cover four ways in which you can use Vertex Textures. The four effects covered will begin with basic operations, and will gradually increase in difficulty, touching different techniques that can be used together with vertex textures. Some chapters may contain a Bonus  section, in which I will shortly explain how to apply certain additional techniques to the effects.

     Here's screenshots from the four chapters, and the downloadable code for them:

    Chapter I: Terrain Rendering Using Heightmaps

     simpleTerrain largeTerrain

    bilinear textured

    Chapter II: Terrain Morphing

    morph normals

    Chapter III: Particle System on the GPU

    particles particlesCollision

    Chapter IV: Steps In Snow

    tough3 trail

    September 12

    Fog of War Sample

    By semi-popular request (I heard one person asking for it, and thought it was an interesting idea :) ), I've put together a quick sample that shows a way to implement Fog Of War in XNA, for a 3D game. As a word of warning, this is put together in a couple of hours, so it may be hacky in some parts.

    The idea is to have the Fog Of War in a texture. The texture represents a view from above, covering all terrain. Using render to texture, I draw a white gradient disk in this texture for each friendly unit of the player, using additive blending.

    After this, I draw the scene normally, and when drawing the enemies, the pixel shader gets, based on its position, the corresponding pixel from the Fog of War Texture. Using this information, it sets the alpha value of the output. This way, when the enemy unit is close to the friendly unit, you can see it, at the borders it fades away, and when out of range, it is invisible.

    The controls are similar to the ones in SkinnedModel Sample.

    If you use this for any project, please send me a screenshot. The sample can be found here. (Thanks again Kyle, for hosting my files)

    And some pictures:

    1 4

    September 11

    Bloxorz

    I found this absolutely great game. It's a game with blocks. Fortunately, it only has 33 stages, and I already reached stage 25. I say fortunately because it's so addictive that I can't let it out of my hands. Hopefully, the last 8 levels won't be too difficult, so I can get back to coding soon.

    Oh, almost forgot: the game can be found here.

    Now back to block rotations!

    Converting Displacement Maps into Normal Maps in HLSL

    Working on my VTF tutorial, I came across the need to apply lighting to a terrain. For lighting, we need normals, of course, but I only had heightmaps available.

    When the terrain is static, this poses no problems at all. All we have to de is generate a normal map from the heightmaps with whatever tools we want. For example, NVIDIA has a Photoshop plugin for this here.

    However, when we have dynamic terrain, with real time deformation, this is no longer an option. This is especially the case when we make the deformations on the displacement map. After lots of reading and searching, I've come across the Sobel Filter, and a sample from ATI that uses it to compute normal maps.

    As a result, I made a pixel shader that takes as input the displacement map and outputs the normal map. I believe this could be used for static terrain, and computed in a Content Processor, but I'm not very experienced with Content Processors, so I didn't try it.

    At runtime, after modifying the displacement map, I apply this shader and put the result into a render target. This result is then used when drawing the terrain, when computing lighting in the pixel shader.

    So here's the HLSL code:

    float textureSize = 256.0f;
    float texelSize =  1.0f / textureSize ; //size of one texel;
    float normalStrength = 8;
     
    float4 ComputeNormalsPS(in float2 uv:TEXCOORD0) : COLOR
        {
        float tl = abs(tex2D (displacementSampler, uv + texelSize * float2(-1, -1)).x);   // top left
        float  l = abs(tex2D (displacementSampler, uv + texelSize * float2(-1,  0)).x);   // left
        float bl = abs(tex2D (displacementSampler, uv + texelSize * float2(-1,  1)).x);   // bottom left
        float  t = abs(tex2D (displacementSampler, uv + texelSize * float2( 0, -1)).x);   // top
        float  b = abs(tex2D (displacementSampler, uv + texelSize * float2( 0,  1)).x);   // bottom
        float tr = abs(tex2D (displacementSampler, uv + texelSize * float2( 1, -1)).x);   // top right
        float  r = abs(tex2D (displacementSampler, uv + texelSize * float2( 1,  0)).x);   // right
        float br = abs(tex2D (displacementSampler, uv + texelSize * float2( 1,  1)).x);   // bottom right
     
        // Compute dx using Sobel:
        //           -1 0 1 
        //           -2 0 2
        //           -1 0 1
        float dX = tr + 2*r + br -tl - 2*l - bl;
     
        // Compute dy using Sobel:
        //           -1 -2 -1 
        //            0  0  0
        //            1  2  1
        float dY = bl + 2*b + br -tl - 2*t - tr;
     
        // Build the normalized normal
        float4 N = float4(normalize(float3(dX, 1.0f / normalStrength, dY)), 1.0f);
     
        //convert (-1.0 , 1.0) to (0.0 , 1.0), if needed
        return N * 0.5f + 0.5f;
    }

    You should tweak normalStrength until the result you get is satisfactory.

    And here is the result of applying that code to two heightmaps, and some terrain lit using a normal map generated by this shader.

    displacement normals

    Until next time, Happy Coding!

    September 04

    Vertex Texture Fetch Tutorial Teaser!

     

    Here's some screenshots from the upcoming VTF tutorial.

    The code is mostly done, and now I'm writing the tutorial itself.

    textured morph

    particles snow steps