CS Buzzcamp 2023 Cramer Model Curriculum

  1. Introduction
  2. Cramer Hall
  3. JSON
  4. A JSON 3D Model File Format
  5. Photos and Textures
  6. Collating Models
  7. Playthrough
This file is http://www.cs.nmt.edu/~jeffery/cramerhall/buzzcamp.html.

Task #1: launch Firefox

We will use Firefox in order to download some files.

1.0 Introduction

In this part of the camp we will build a 3D model that could be used as a "level" in a videogame. Our videogame level will look (I hope!) like Cramer Hall at NMT. Later you could use these ideas to build your own game levels.

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.

1.1 Cra2 Demo

This demo shows you why I/we are working on a model of Cramer Hall. Let's run a little program that you can find at http://cve.sf.net/cra2.zip, see instructions below (this file also can normally be reached from outside NMT at http://www.cs.nmt.edu/~jeffery/cramerhall/cra2.zip)

Task #2: download and extract the demo

Task #3: compile and run the demo

From this little demo program, we could:

But we will use it to see (test) bits of our "virtual Cramer Hall" as we build it, hopefully enough of Cramer Hall that a user would recognize it when they see it. So let's talk 3D models.

1.2 Models

A videogame level is a virtual model of some real or imaginary place. Now let's talk a bit more about what we are modeling: Cramer Hall.

2.0 Cramer Hall

Cramer Hall houses the computer science and engineering department, the cybersecurity center, and the office of innovation and commercialization at NMT. This all seems like a big complicated problem to me! Computer Scientists solve big complicated problems by breaking them into smaller pieces.

2.1 Zone Assignments

Here are the smaller pieces we will use for modeling Cramer Hall.

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.

Before we go walking around Cramer Hall, we need to agree on a coordinate system.

2.2 Coordinate System

We will use a standard/common coordinate system: 1.0 units = 1 meter, with an origin (0.0,0.0,0.0) in the northwest corner of Cramer Hall at ground level.


The origin of Cramer Hall's coordinate system

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

The building floor plans are mostly accurate.

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.

Room/Zone Measurement Activity

This part of the module asks students to estimate the basic location and dimensions of your zone in the Cramer Hall Model. This may require tape measures, paper and writing utensils.

Zone Report Form

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.

3.0 JSON

JSON is JavaScript Object Notation. You can learn all there is to know about JSON in about 5 minutes. JSON is written in text format.
  • There are six kinds of things that can appear in a JSON file; we care about four of them.

    3.1 Group Activity: write a JSON file

    Now, it is time to use JSON to represent parts of Cramer Hall.

    4.0 A JSON 3D Model File Format

    We will build a 3D Model as a human-readable JSON file. Its contents will capture the information that we want to depict in our video game level (in our case, Cramer Hall), including spatial location and general appearance characteristics.

    4.2 Our 3D model will have two kinds of things

    Rooms
    A Room is a 3D "box-shape" volume in space that may contain users or objects in the game
    Doors and Openings
    The holes in the wall that let you walk from one rectangular area (room) into another.

    Now it is time to dive into details of representing our 3D Models in JSON.

    4.3 Rooms

    A "Room" is a box-shaped 3D volume of space. A Room is bounded by six solid walls. Rooms are connected to one or more adjacent rooms, so people can get around. Connections between rooms are discussed in the next section. Every room has a name, a local origin (x,y,z) in the northwest corner, given in TNN coordinates, and (w,h,l) width, height, and length showing the size of the room, again given in units of 1.0 = 1 meter. Rooms can optionally include wall, floor, and ceiling texture information, along with zero or more decorations, and zero or more obstacles. Here's an example with just the minimum (no decorations or obstacles).
    { "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.

    4.4 Write a JSON File for your Room

    Cramer 230b Room Example

    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.json
    
    it dies with the message:
    valid JSON, but not a model file: cra230b.json
    
    What could possibly be wrong?

    Testing Your JSON Model

    After you write a JSON file for your room(s), and validate it as legal JSON using jsonlint.com, you can further test it in two stages.
    1. Validate it using the Unicon JSON checker, checkjson.icn. Save this to a directory/folder under your home directory, whereever you are storing your .json files
    2. Test it using the cra2 model viewer.
    Suppose you write a file named cramer228.json. To run the checkjson program you might download checkjson.icn and then say at a Terminal window:
     unicon checkjson
    
    (this compiles checkjson.icn down to an executable named checkjson) and then type
     ./checkjson cramer228.json
    
    If 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
    

    Cramer 230b Example, continued

    In the case of my cra238b.json: When I add square brackets around my json code, it will display in cra2:
    [{ "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.

    4.5 Doors and Openings

    Doors and Openings connect two adjacent Rooms together. The Rooms must be touching/overlapping on part or all of one of their sides; they must be right next to each other.
    Opening
    An opening connects two logical rooms into one larger space.
    • An opening cuts a "hole" in the walls of the rooms it connects; it is a 2D rectangle with width and height and no depth.
    • Parameters: "collide_in" sets how much distance is allowed between the avatar and the edges of the opening. "plane" tells whether the opening is on a north-south or east-west plane. plane 1 is an x-plane opening that goes east-west. plane 3 is a z-plane opening that goes north-south.
    • Mental note to Dr. J: duh, change cra2 program to accept "x" or "ew" in place of 1, and to accept "z" or "ns" in place of 3 in the "plane" parameter. Better yet: duh, change the cra2 program so that it calculates whether it is an x plane or a z plane, and get rid of the "plane" field in the .json
    Door
    A "door" is really an opening plus a 3D object that can be open or shut.
    • Doors are usually far smaller than the surrounding wall.
    • Doors can have textures, encoded with additional fields in the JSON files.
    • Double-doors can be encoded as two individual doors, or as some separate DoubleDoor class with special mechanics.
    JSON Examples:
    {"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.

    4.6 Decorations

    Every room can contain a list of 2D or 3D objects that are there just for their appearance.
    { "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.

    4.7 Obstacles

    Every room can optionally contain a list of zero or more 3D objects that force users to walk around rather than walk through them.
     {
       "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]
          }
          ]
     }
    

    Wednesday Status Report

    Today our job is to take pictures and make textures, but here's where we are at:

    5.0 Textures

    The coordinates in the JSON model would be sufficient to show a wireframe model of Cramer Hall.

    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.

    5.1 Texture Basics

    How much do you already will know about digital images?
    pixel
    A pixel (from: picture element) is one dot in a digital image
    resolution
    the number of dots in an image. frequently given as an image size, sometimes given as a ratio such as "dots per inch".

    5.2 Texture Sizes

    5.3 What to Texture (and What Not)

    For your Room, we need:

    5.4 Converting a photo into a texture

    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.

    Crop the image
    cut off around the edges, the part that is not part of your texture. GIMP has selection tools, and a Crop To Selection command.
    Stretch out your bad perspective.
    GIMP has a command that let's you straighten out crooked edges that result from taking a picture at an angle.
    Rescale it to use width/height powers of two
    Changing an image's size is easy.
    Save it; save a .gif and a .png
    GIMP expects you to "export" to save in an image format. Its normal "save" commands saves in some weird proprietary GIMP format. Most digital cameras save in JPEG (.jpg) format; you can save that but for Cramer Hall I recommend we use .gif

    5.5 Texture Activity

    In this exercise, make a usable texture of the Tom Nartker plaque from Cramer 1st floor, south hallway. Perform this process, if you have time, to all textures in your room.

    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.

    5.6 Texture Collection Activity

    This activity collects images and makes textures for our Cramer Hall Model. This will require tape measures (to figure out the coordinates for decorations), cameras, paper, writing utensils, and a computer with the GIMP installed. Finish by getting your .json and images to Dr. J by e-mail or USB jumpdrive.

    Cramer 230b Textures Example

    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.06
    
    and 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:

    6.0 Collating Models

    The models produced had to be collated together into one big model file. It was conjectured in a buzz camp planning meeting, and turned out to be true, that "this would best be performed by CJ". I tried demoing wiring rooms together and adding door/opening on the fly yesterday with a .333 batting average. The following are a couple "next steps" topics that are not part of this week's camp curriculum, but we would introduce next if we were continuing.

    6.1 Tiling textures

    Tiling is when a texture is repeated to cover a large area.

    6.2 Minimizing Polygon Counts

    Since our model is to be used in a videogame, we could discuss some of the simplifications, abstractions, and trade-offs that keep the model simple and the polygon count low, so that we can display it even on low-end computing devices.

    6.3 Collation Notes

    Additional Notes/Feedback:
    Arden 226
    Thanks for giving me about 6 good images with 3 converted to .gif format! Their widths and heights need to be powers of 2 before I can put them into the game.
    Conner 225h
    Thanks for giving me about 7 good textures and some more jpegs to work from. "no nerd stuff only banan" LOL. Breaking the fifth wall like that was the nerdiest thing in the whole camp!
    Abran 225h
    Thanks for giving me 7 jpegs, with one ceiling shot converted to .gif format. Its width and height need to be powers of 2 before I can put it into the game.
    Joey 221h
    Thanks for giving me 5 gif textures and many more JPGs!
    Marc 225h
    Thanks for giving me 3 gif's and jpg's. Their width and height need to be powers of 2 before I can put them into the game.
    Kellen
    Wow.
    Sean 217h
    Thank you for the six .gif textures and the extra improvements you made to them.
    Patty 217
    Thanks for the 7 detailed .jpg's, resized to powers of two. I kinda want .gif files, but we could probably use some of these without further conversion.
    216h
    Thanks for the great poster and display case .gif files. They need to be width and height power of two before I can put them into the game.
    Ryan 213
    Thank you for the hard work making extra textures!

    Did We Build a Virtual Cramer Hall?

    Well, it may take weeks to pull in and place all your decorations and obstacles, but ... yes! This was the first time I used JSON to model a game level and it worked.

    Is JSON better than cve native format?

    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
    }
    
    Answer is: not easier for novices. Maybe still good for data interchange with other virtual world builders. And maybe still useful for teaching JSON, which is used heavily in industry.

    Was this project overly ambitious for a Buzz Camp?

    Should it die a quiet death? You tell me.

    Did you learn anything?

    Besides JSON and the GIMP, which sounds a bit like a band name.

    7.0 Playthrough

    This part of the module will allow students to see all the models, stitched together.