Click here to Skip to main content
Click here to Skip to main content

The GDI magic - Rendering reflections and smooth shadows

, 21 Feb 2007
Rate this:
Please Sign up or sign in to vote.
An article on rendering reflections and shadows using Windows GDI.
Screenshot - screenshot.png

Introduction

This article is about a simple approach to rendering reflections and smooth shadows of 3D objects using just Windows GDI. There are no true 3D objects on the screen. We will just play with bitmaps and a few calls to the BitBlt() and PlgBlt() Win32 API functions.

Background

I have always liked how people use CPU power to simulate real-world behavior of objects. In the 3D games available today, I have seen whole virtual worlds created just for one purpose - to have fun and to play. Since I was not a 3D modeling expert, but I wanted to create something that looked real in a scene, I used the only weapon I have at the moment: Windows GDI. I have built a demo scene to show people who wonder how to do things like this. It was more than easy, but took some time to create. Here is how it was done...

The scene background

The background of the scene is a flat polygon with a texture. It is easy to do with a simple call to the PlgBlt() method. It takes as arguments the HDC of the destination, polygon vertices, the HDC of the source bitmap loaded with a simple LoadBitmap() method call, offsets and dimensions of the loaded bitmap, and some masking arguments, which are set to NULL here. See the code below:

// Drawing textured polygon
CBitmap bgBitmap;
bgBitmap.LoadBitmap(IDB_BITMAP_BACKGROUND);
BITMAP bmp;
bgBitmap.GetBitmap(&bmp);
POINT pBgBitmapPoints[3] = {{50, 250}, {380, 250}, {200, 400}};
PlqBlt(hDestDC, pBgBitmapPoints, hSrcDC, 0, 0, bmp.bmWidth, bmp.bmHeight, NULL, 0, 0);

The exact source code can be found in the DrawBackground() method in the demo project.

The object reflection

Now comes the most interesting part: how can we render the reflection of the object so that the surface the object stands on can be seen as shiny and smooth (like a glass surface)? Solution: we will render the same object upside-down on that surface, but using a small trick. First, we render just the sides of the object that can have a reflection. Second, we will do a "decreasing alpha blend" technique while rendering those sides, so that we get a realistic effect. Here is the algorithm:

For each side that has a reflection:

  • Blit a part of the screen which is covered with this side using BitBlt() method on the first bitmap
  • Blit inversed side using PlgBlt() method on the second bitmap
  • Merge these two bitmaps using a decreasing alpha blending technique as you move along each row
  • The result is in the second bitmap now
  • Blit this second bitmap on the screen again using BitBlt() method

The exact source code can be found in the DrawReflectedBox() method in the demo project.

The object shadows

Rendering of the shadow can be done in simple way or a complex one - it's all up to you. I have decided to use a simple technique called "rendering a shadow using ground transformation on the z=0 plane", and I made it even more simple. I didn't use exact math in this example because it is not so important, but even then the shadow still looks real. The light source is at infinity, so the light rays are parallel. This means that the projection of the object on the ground (z=0 plane) keeps the dimensions of the object itself. Knowing that, I did the following:

  • Blit the part of the screen that is covered with this shadow using the BitBlt() method on the first bitmap
  • Blit the part of the screen that is covered with this shadow using the BitBlt() method on the second bitmap
  • Filter the second bitmap using a simple blur filtering technique (the filter size is up to you)
  • Merge these two bitmaps using a constant alpha blending technique as you move along each row
  • The result is in the second bitmap now
  • Blit this second bitmap onto the screen again using the BitBlt() method

The exact source code can be found in the DrawShadow() method in the demo project.

The main object

The main object was rendered similarly to the scene background. It is a box with 3 sides (polygons) with different textures each. It is rendered at the end, as the last object on the scene.

The exact source code can be found in the DrawOriginalBox() method in the demo project.

Question about the speed of rendering

Please understand that this demo is just a simple example that does not try to break any speed record with GDI. It just shows that some things can be done, not that they should be done in this way at all. Please, refer to DirectX/OpenGL documentation for high quality 3D graphics rendering on the Windows platforms.

Points of Interest

I have learned while doing this example that it is possible to create a high quality real-world scene just by using simple Win32 API calls for GDI rendering. So, there is something that can be done (and look nice) with GDI, which has no default support for any of the DirectX/OpenGL advanced rendering modes: antialiasing, shadowing, reflections, etc.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

darkoman
Software Developer (Senior) Elektromehanika d.o.o. Nis
Serbia Serbia
He has a master degree in Computer Science at Faculty of Electronics in Nis (Serbia), and works as a C++/C# application developer for Windows platforms since 2001. He likes traveling, reading and meeting new people and cultures.

Comments and Discussions

 
GeneralVersion PinmemberMember 16077879-Nov-08 4:50 
GeneralI loved It!! PinmemberKelly Cristina Mara1-Mar-08 5:58 
GeneralDemo exe Pinmember.dan.g.21-Feb-07 13:03 
GeneralRe: Demo exe PineditorJ. Dunlap21-Feb-07 18:31 
AnswerRe: Demo exe Pinmemberdarkoman22-Feb-07 21:41 
Generalaway goes c-- Pinmember852y3agnna21-Feb-07 8:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 21 Feb 2007
Article Copyright 2007 by darkoman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid