A Simple CAD program
CS490 Spring 1998
by Hubert Siu
Introduction:
3D graphics has gained a lot of importance in the past
few years, especially in design, modelling, and gaming. The purpose
of this project is to make use of OpenGL libraries and MFC (Microsoft Foundation
Class) libraries to create a 3D graphics application--a simple CAD program.
This application allows a user to design a house in a 2D space, while able
to view the 3D model on another window at the same time.
Process:
Before starting on the project, I went through a few
tutorials on MFC and OpenGL. A good tutorial for starting with MFC
is the Scribble tutorial that comes with Visual C++. OpenGL tutorials
could be found online, and I went through the tutorials that can be found
at DevCentral. These
tutorials and sample programs gave me a good idea on a lot of essential
part of the project: setting up the device context for OpenGL graphics,
drawing 3D objects with lighting effects, setting up camera view on the
3D model, setting up multiple views for a single-document-application,
etc.
After deciding to use a link list as the data structure
for storing information, I started to modify the skeleton code generated
by MFC AppWizard. The
first task I planned to achieve was to edit the code so that I can only
have a single document open at a time while have 2 different views, with
one for designing and one for displaying the 3D model. The next thing
I had to do was to set up the drawable area (which is the base for the
design) with the grid lines on the design view and display the 3D object
in the model view. Mouse control was added afterwards so users can
rotate the base in the model view. At this point, the camera in the model
view is fixed at the origin with the up vector = (0, 1, 0), with viewing
angle = 30 degrees.
The next step was to enable users to draw their
own design. The first element that was implemented was the room. The
room is derived from a base class called CElement, which is derived from
CObject (defined by Microsoft). The purpose of using CObject as the
base class was because its member function Serialize reads and saves the
document data upon slight modification. A draw member function is
added to CElement for drawing the object in the design view, and the coordinates
are stored in a new element in a pointer array. The device context
object (CDC) provides member functions for drawing, such as LineTo and
Rectangle, and these functions were used to draw objects on the design
view. Different kinds of pen can be chosen to color the object.
While draggin, the pen style was set to PS_DOT and was set to PS_SOLID
when an element is created so that dotted lines and solid lines can be
drawn depending on the condition. Once the design frame was setup
for drawing rooms, I started to work on the model view. The coordinates
for each rooms are stored under an array inside the document, and the model
view loads the values once the user has defined a new room. 8 polygons
are used for each room. Lighting position were adjusted so that the
shades are obvious to the user. Restrictions are applied so that
a room cannot overlap another room. The height of the room is also
fixed.
Door and window are the next two elements that were
added. Their sizes are fixed, because for rendering same objects
in OpenGL, display
lists can be used to improve performance. Both door and window elements
also have CElement as their base class. 2 polygons are used for each
element. The window and door drawing functions for the design view
were added, as well as their own Serialize member function. The pointer
array that stores the room element is also used to store new door and window
elements. When creating a door or a window, a small box with dotted
line appears when the left mouse buttons is down. A door or window
will not be created if that box does not intersect any of the room element
in the link list, nor it will be created if the element intersects with
a door/window element in the list. If the element selected is successfully
created in the design view, it should also appear in the model view instantly.
Before addding the roof component, a transparent
function for the 3D model was added. This was done by changing the
alpha component
in the glColor function to a value smaller than 1 and enabling blending.
The color of a pixel is the combination of source color based on the alpha
value and the destination color based on the value of (1 - alpha value).
Transparency will not show up until the program enables the blending function.
The screen shot on the right was taken when the camera was located on the
bottom of the model, below the base. A button on the tool bar allows
the user to toggle between on and off for transparency. The speed
will be decreased when transparency is on, since more calculation has to
be performed. Note that there is a difference in performance between
turning off the blending function and setting the alpha value of 1.
The next element that was added to the program was
the roof. Before a roof element was inserted, the program would go
through the
link list and make sure that a room was located right underneath the current
location of the roof. If the program found a room under its current
location, a dialog would pop up and asked the user to pick one of the 12
types of roof. When creating the roofs in the model view, the normal
for the top of the roof are all different, therefore each normal has to
be calculated. This was done by finding the maximum value between
the length and the height of the roof, and used this value to normalize
the normal vector so that it will always have a magnitude of 1. This
would provide correct lighting and shading for the roofs.
At this point, only the last element inserted into
the design could be deleted. A delete function was implemented so
that whenever the user selects an element with the cursor, the element
can be deleted. All elements can be deleted by selecting them and
hit the delete button except for the room, which the user has to make sure
that there are no other elements, such as doors, windows, or roofs, associated
to it. A search on the link list will be performed to ensure that the room
is not connected to any of these components.
Another model viewing mode was added after the implementation
of delete, and that is virtual walk-through. The camera can now be
moved around
in 3D space, with the up-vector always pointing up. When the walk-through
mode is enabled, user can move forward, backward, turn right, left, up
and down. The restriction is that the user can only move towards
the direction that he/she is looking at. At this point, there is
no restriction on where the camera could be. It can therefore travel
through walls and windows, and clipping might occur. Also, the current
viewing angle is set to 30, so a slight fisheye effect exists.
After I was done with the walk-through mode, I started
optimizing the code. A lot of floating point calculations were reduced
after optimization, and I used the command glHint to optimized the speed
of rendering. The difference was quite obvious, especially when the
window size is large.
Help files were the last part that I worked on.
I experienced problem compiling the help file initially because the help
compiler is 16-bit and it has problem reading the afxcore.rtf file.
This problem can be fixed by obtaining a 32 bit compiler or converting
the rtf file into 16-bit format. These programs are available online
and could be found on www.shareware.com.
Result:
The program has been tested and all functions seem to work
properly. Here are some basic instructions for designing a model:
-
To select an existing element on the design view, click on the
button on the toolbar. Click on any element within the design view
with the left mouse button.
-
To create a room, click on the
button on the toolbar. With the left mouse button down, drag on the
grid and release the button when the desired size is achieved.
-
To create a door, click on the
button on the toolbar. A dotted box would appear when left mouse
button is held down. Drag the box to a place where it intersects
with one side of a room; then release the mouse button.
-
To create a window, click on the
button on the toolbar. Follow the same steps as in creating a door.
-
To create a roof, click on the
button on the toolbar. Follow the same instructions as in creating
a room, except that the final rectangle must intersect with a room.
A slope dialog would pop up. Select 1 of the 12 different slope directions.
-
To enable transparency, click on the
button on the toolbar.
-
To change to normal mode in the model view, click on the
button on the toolbar.
-
To change to walk-through mode in the model view, click on the
button on the toolbar.
-
To rotate the model in normal mode, hold down the left mouse button and
move around.
-
To move around the model in the walk-through mode, use 5 for forward, 0
for backward, 4 for left, 6 for right, 8 for up and 6 for down.
The program didn't turn out to have a lot of big problems,
though minor problems exist. One problem with the design view was
that when the user needs to draw a room that has a larger size than the
viewable area, the screen will not scroll down automatically.
Another problem with the design view was that random
dots appear on the screen once in a while during dragging operations.
This rarely happens, but it is a little annoying to users. I was
examining my code and tried to find out what I did wrong, but I did not
find any major problem with my code. I then tried to drag rectangles
on the desktop and in other windows, and I noticed that the same problem
occur. My conclusion for this problem is that this might be a bug
in windows.
The main problem for the model view was clipping
when the user is in the walk-through mode. Some algorithms could
be applied to eliminate this problem, but I haven't come up with a good
solution at this point.
Texture mapping was originally added to the program.
Users were allowed to define a wallpaper for ther rooms. The fucntion
was taken off after transparency was added due to the effect on rendering
speed. When both texture mapping and transparency was on, the rendering
speed was extremely slow. Since this is a design program, the ability
to see all the rooms seems to have a higher priority then making them nice,
therefore texture mapping option was taken off.
The program is fully functional, but improvements
can be made. First of all, a resizing function should be added so
that the size of the roof and room can be altered. Another improvement
is to allow designs to have multiple stories. This will include 2
extra elements, at least, which will be stairs and floor. A better
version of walk-through will be only allowing the user to walk from one
room to another through a door, instead of going through walls, windows
and roofs. The ability to allow users to define their own door and
window size or style would also be a nice feature.
A copy of the program with help
and the source code are available here.
Please send all comments and suggestions to hys2@cornell.edu.
Thanks! |