| Task #1: launch Firefox |
|
Our game level intended to eventually be part of a game based on a program called CVE that some students and I wrote. CVE provides a multi-user 3D environment that looks something like the following image. The best 3D videogame level photographer and texture artist I've ever worked with was a Shoshone visiting summer student named Danny Leclaire. Some of his work is visible in this screenshot.
Our goal this week is not to spend it playing inside of CVE, our goal is to build a 3D model of Cramer Hall, and learn about data representation and textures. Now, let's look at a demo.
Task #2: download and extract the demo
|
|
|
cd ~/Downloads/cra2If you make it into the cra2 subdirectory successfully, and if we extracted the .zip file successfully, an "ls" command will show several files present, such as cra2.icn and cra2.json.
makeIf "make" works, it will create machine language executable files for several programs including cra2 and tnn.
unicon cra2 model
./cra2
From this little demo program, we could:
From the floor plan, every camper gets to do one "zone" of Cramer Hall. For this camp, a zone is a rectangle on one of the floor plans. In a 3D program it is a rectangular volume corresponding to part or all of a room or a hallway. I will also use the word "room" to mean the same thing as "zone".
For day #1 of camp, you will want to find your zone in Cramer Hall.

From this origin Y grows "up", X grows east, and Z grows south. Everything in Cramer (except below ground level, or "sticking out" to the north or west) will have small positive real xyz coordinates. I refer to this coordinate system as TNN world coordinates (TNN=Tom Nartker Normal). Tom Nartker was the founder of the NMT CS Department.
For each (x,y,z) or (w,h,l) that we need in our model, we have to figure out their value in meters using the TNN coordinates. Our options are to either
Example: I went outside and measured the distance from the NW corner of the building (0,0,0) to the outside entry that sticks out a bit north of that. According to the tape measure, it was 23'4" (23 1/3 feet == 7.1 meters). The entryway that sticks out north of the building was 58" (1.5 meters). How do these compare with the numbers I would get from the floor plans?
Another example: I measured the distance between the Cramer Hall 1st floor and the 2nd floor and it came out to 13'7" or 4.1 meters. I estimate the wall thickness outside room 228 to be ~18", or 0.5m. If those two numbers were accurate, the inside of Cramer 228 origin would begin at (0.5,4.1,0.5). Awesome, we have our first coordinate for this room.
My Name: ________________
My Zone: ________________
Zone Origin X: __________ (from tnn program)
Y: __________ (0.0 for 1st floor, 4.1 for 2nd floor)
Z: __________ (from tnn program)
Zone Width: __________ (X2-X1 from tnn program)
Height: __________ (MEASURE)
Length: __________ (Z2-Z1 from tnn program)
Adjacency North:
Zone Name: ________ Door/Opening (circle one)
Camper: ________
X: ________
Y: ________
Z: ________
W: ________
H: ________
Adjacency South:
Zone Name: ________ Door/Opening (circle one)
Camper: ________
X: ________
Y: ________
Z: ________
W: ________
H: ________
Adjacency East:
Zone Name: ________ Door/Opening (circle one)
Camper: ________
X: ________
Y: ________
Z: ________
W: ________
H: ________
Adjacency West:
Zone Name: ________ Door/Opening (circle one)
Camper: ________
X: ________
Y: ________
Z: ________
W: ________
H: ________
Cross out adjacencies if your zone has no door/opening in that direction.
Add adjacencies as needed if your zone has 2+ doors/openings in any one
direction.
Given all these coordinates and dimensions, how do we represent complex structured data on a computer? There is a standard data format that would do the job and make it easy for others to understand and use our data. That format is called JSON.
"hello", 3.14
["hello", 3.14, "universe", 42]
{"hello": 3.14, "universe": 42}
[["hello", 3.14], ["univers", 42]]
{"name": "Santa Fe", "latlong": [35.7, 105.9]}
./checkjson my.json
Now it is time to dive into details of representing our 3D Models in JSON.
{ "class": "Room",
"name": "corridor230",
"x": 28.8,
"y": 12.3,
"z": 15.23,
"w": 1.8,
"h": 3.5,
"l": 3
}
Rooms can have
textures to draw their walls, floor, and ceiling.
See examples in Section 4.6.
Jeffery decides to do his office. Tape measure says width = 3.35m, height = 3.6m (false ceiling hangs lower over most of it), and length = 6m.
Jeffery calculates x from 2nd floor floorplan, where 20' is ~90pixels and the x in the northwest corner of room is 308 pixels from the origin. 308/90*20 = 68.4' = 20.8m, so x is 20.8m. y was calculated at 4.1m. z = 0.5m thanks to outside wall thickness.
{ "class": "Room",
"name": "Cramer 230b",
"x": 20.8,
"y": 4.1,
"z": 0.5,
"w": 3.35,
"h": 3.6,
"l": 6
}
Except woops, when I try to run
./cra2 cra230b.jsonit dies with the message:
valid JSON, but not a model file: cra230b.jsonWhat could possibly be wrong?
unicon checkjson(this compiles checkjson.icn down to an executable named checkjson) and then type
./checkjson cramer228.jsonIf checkjson can't load your JSON, then the cra2 model viewer will surely not be able to load and view it.
If checkjson is OK, then you can run the cra2 model viewer like this:
./cra2 cramer228.json
[{ "class": "Room",
"name": "Cramer 230b",
"x": 20.8,
"y": 4.1,
"z": 0.5,
"w": 3.35,
"h": 3.6,
"l": 6
}]
Of course, this room is completely boring, and wrong on the walls, floor,
and ceiling, before we even start to talk about decorations.
{"class":"Door",
"x": 10.2 ,
"y": 12.3,
"z": 20.07,
"w": 1.04,
"h": 2.21,
"collide_in": 1.2,
"plane": 1,
"rooms": ["csac" ,"lab"]
}
{ "class": "Opening",
"x": 26.6,
"y": 12.3,
"z": 15.23,
"w": 2.2,
"h": 3.5,
"collide_in": 1.2,
"plane": 3,
"rooms": ["JEB228", "JEB230"]
}
{"class":"Door",
"x": 23.4 ,
"y": 12.3,
"z": 18.23,
"w": 0.8,
"texture": "mydoor.gif",
"h": 2.2,
"collide_in": 1.2,
"plane": 1,
"rooms": ["JEB222" ,"FLOOR2COR"]
}
We will work on adding doors and openings to your .json files tomorrow!
In order to collect the (x,y,z) data for some of the doors and openings
we will need to measure, and we will do that when we go out to the rooms
in order to take pictures of everything in order to make textures!
In the meantime, let's look at the other things you can put in your
.json files.
2-----3 |-----| 1-----4
{ "class": "Room",
"name": "JEB228",
"x": 26.6,
"y": 12.3,
"z": 15.23,
"w": 2.2,
"h": 3.5,
"l": 3,
"texture": "jeb230wall.gif",
"floor": { "class": "Wall",
"texture": "jeb230carpet.gif"
},
"decorations": [
{ "class": "Wall",
"texture": "whiteboard.gif",
"coords": [26.65,13.3,15.3, 26.65,14.8,15.3,
26.65,14.8,17.9, 26.65,13.3,17.9]
}
]
}
You could actually put arbitrary objects, including 3D objects, on the
decorations list; as a decoration, they would be visible but would have
no other gameplay mechanic such as interfering with the user's ability
to walk around.
For objects that the user can "feel", you put the
objects on another list: the obstacles list.
{
"comment1": "sample rooms JSON file",
"class": "Room",
"name": "SH 167",
"x": 29.2,
"y": 0,
"z": 0.2,
"w": 6,
"h": 3.05,
"l": 3.7,
"floor": {
"class": "Wall",
"texture": "floor.gif",
"coords": [29.2,0,0.2, 29.2,0,3.9, 35.2,0,3.9, 35.2,0,0.2]
},
"obstacles": [
{
"comment": "column",
"class": "Box",
"walls": [
{ "class":"Wall",
"coords": [34.3,0,0.2, 34.3,3.05,0.2, 34.3,3.05,0.6, 34.3,0,0.6] },
{ "class":"Wall",
"coords": [34.3,0,0.6, 34.0,0,0.6, 34.0,3.05,0.6, 34.3,3.05,0.6]},
{ "class":"Wall",
"coords": [34.0,0,0.6, 34.0,3.05,0.6, 34.0,3.05,0.2, 34.0,0,0.2]}
]
},
{ "comment": "window sill",
"class": "Box",
"walls": [
{ "class":"Wall",
"coords": [29.2,0,0.22, 29.2,1.0,0.22, 35.2,1.0,0.22, 35.2,0,0.22]},
{ "class":"Wall",
"coords": [29.2,1,0.22, 29.2,1.0,0.2, 35.2,1.0,0.2, 35.2,1,0.22]}
]
}
],
"decorations": [
{ "comment": "please window",
"class": "Wall",
"texture": "wall2.gif",
"coords": [29.2,1.0,0.22, 29.2,3.2,0.22, 35.2,3.2,0.22, 35.2,1.0,0.22]
},
{ "comment" : "whiteboard",
"class": "Wall",
"texture": "whiteboard.gif",
"coords": [29.3,1.0,3.7, 29.3,2.5,3.7, 29.3,2.5,0.4, 29.3,1.0,0.4]
}
]
}
In order for a 3D view to look recognizable, we need to make or find textures for the walls, floors, ceilings, and objects in our model.
A texture is a 2D image, part or all of the contents used to draw the surface of an object in a 3D scene.
For the next part, we will use a program called the GIMP. You can do some of this crudely with Windows Paint, or you can do it with Photoshop if you have that.
Step #0: if the camera shot is poor, your texture may come out better if you re-shoot it. In this case, from my poor camera, in the left shot (semi-broken regular phone camera) the plaque is readable but poor. The right shot is the re-shoot using the non-broken lower-resolution selfie camera.
|
|
Step #0.5: Download the image you want to turn into a texture ont your computer. You may well have to transfer the image from your camera, or in this case save it from the NMT CSE department website, in order to edit it. The URL for our sample image is cve.sf.net/a.jpg. Visit the link, right click the image and click "Save image as..." and save a local copy under your home directory, maybe in Downloads.
Step #1: Launch the GIMP. It takes awhile to startup. If working on your own computer, you might have to first download it from gimp.org and install it. It is installed on the NMT lab machines. After you launch the GIMP successfully, Open the Image.
Step #2: Select a bounding rectangle subset of the Image. The bounding rectangle is the smallest rectangle that contains the entire object that you want to turn into a texture. It is awesome computer science jargon to help you fit in at computer science parties.
Step #3: Crop the Image. The Image menu has a Crop to Selection command that will cut off everything not in our bounding rectangle.
After you click Crop to Selection, your cropped image looks something like this.
Step #4: Fix the perspective
To use this texture, we need to straighten it out. Go into Tools menu, pick Transform Tools submenu, and pick the Perspective tool.
Drag the yellow/orange corners of the image over to the corners of the object in the picture. You can drag all four corners, although in this case cropping got the left two corners perfect and I only had to drag the two right corners.
After clicking Transform, your image should look a lot better.
Step #5: Rescale width and height to the nearest power of two, or a power of two that is smaller.
Pick the Scale Image function from the Image menu.
Unlock the lock that forces width and height to scale proportionally.
Change width and height to powers of 2, and click Scale. For the Nartker plaque, I took a 16xx pixel height down to 1024. I could have scaled the width also to 1024, forming a square that stretched the image sideways a lot. Instead I took width down to 512, reducing stretching and shrinking the image a bit.
If the texture will usually be viewed from a distance within your 3D scene, you may want a texture MUCH smaller than the original camera image.
Step #6: Save your texture
Pick the File menu Export to... or Export As. This time I am using Export As.
Export As let's you choose a filename, including what extension and what kind of image format to use. For textures on Unicon the venerable GIF (.gif) format is the most reliable. JPEG (.jpg) or PNG (.png) might work.
The Export As for some formats will pop up another dialog and ask you what "quality" to use; this affects image file size and accuracy. The default (quality 90 in this case) is generally good enough for texture work. Higher quality might be for printing a poster-sized picture of the President or something.
Since it had to be a power of two, the finished texture image may look a bit funny in terms of its width, height and stretching. When we apply the texture in the 3D scene, the ratio of width to height will get corrected at that time.
The resulting texture image could still be enhanced further by a PhotoShop (or GIMP) expert; maybe it has red-eye or reflections to remove or other photographic enhancements needed. In our case there are a couple reflections on the black side and bottom border, but it is good enough for now.
Jeffery continues his office example with some textures, decorations and obstacles.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| not used |
Where to start with textures? The walls, floor, and ceiling. How's about I start with the floor. Resize it to power of two (in this case, by just cropping).
Stick it in the 230b Room:
[{ "class": "Room",
"name": "Cramer 230b",
"x": 20.8,
"y": 4.1,
"z": 0.5,
"w": 3.35,
"h": 3.6,
"l": 6,
"floor": "floor.gif"
}
]
Note: to switch over the default walls for all rooms, convert your wall texture
to a .GIF file and name it walltest.gif
Sticking in a decoration.
The false ceiling in Cramer 230b hangs down 30" (0.75m) and is offset 22" (0.56m) from the outside walls. Its coordinates start at
20.8,6.95,1.06and extend as a box of size 3.35-0.56, 0.75, 6-.56 we might use this texture to place it:
Put a Box into your decorations list at the correct height for your lowered/tiled ceiling.
The goals for each camper who was assigned to focus on Cramer Hall Thursday afternoon consisted of the following:
| JSON | CVE native |
|---|---|
[{ "class": "Room",
"name": "Cramer 230b",
"x": 20.8,
"y": 4.1,
"z": 0.5,
"w": 3.35,
"h": 3.6,
"l": 6,
"floor": "floor.gif"
}
]
|
Room {
name Cramer230b
x 20.8
y 4.1
z 0.5
w 3.35
h 3.6
l 6
floor floor.gif
}
|