Cramer Model Curriculum
This is the initial, MST teacher edition of the Cramer Model BuzzCamp module
discussed during the June 2023 MST Buzzcamp.
For the subsequent, simplified version of this delivered to students, go to
http://www.cs.nmt.edu/~jeffery/cramerhall/buzzcamp.html
- Introduction
- Cramer Hall
- JSON
- A JSON 3D Model File Format
- Textures
- Measurement and Texture Collection
- Collating Models
- Playthrough
In this camp module we will build a playable videogame level by brute force.
Our videogame level will consist of a virtual 3D model of Cramer Hall at NMT
that we can walk through. A similar activity could be performed for a
selected building at most any institution such as a K-12 school, or junior
or technical college. For each item, we will ask
- How much teaching is needed for students to get this? and
- How can we best teach this topic? -- appropriate to your grade level
This is not a programming activity, it is a digital data activity. The
data we produce can be used from programs written in any language. But,
people are always going on about how important it is to integrate research
into our teaching, so yeah, we are going to visit my research.
The programs that will use our model in are written in the Unicon programming
language, from unicon.org.
- Unicon is an open source programming language halfway between
Python and Java.
- Unicon's built-in 3D graphics were developed here in New Mexico,
starting with the work of an undergraduate student named Naomi Martinez.
- The first person to use Naomi's 3D graphics to write an interactive 3D
first-person (videogame-like) demo was an undergraduate student named
Korrey Jacobs.
- You (and your students) do not need to learn Unicon to learn this
module's concepts.
Now, let's see whether the demo will work for us.
1.1 Cra1 Demo
This demo shows you why I/we are working on a model of Cramer Hall
by running a little Unicon program that you can find at
http://www.cs.nmt.edu/~jeffery/cramerhall/cra1.zip.
You might have it in a subdirectory named cra1 under your home directory,
or you might download it and unzip it into such a directory.
- Do you know what a .zip file is? Do your students?
Should we talk about compressed archive files?
Do you know how to uncompress a .zip file?
- Do you know about interpreters and compilers? Python is commonly
used via an interpreter. Java is usually compiled. So is Unicon.
- The Unicon compiler is invoked for this example on a couple of
Unicon source files with extension .icn: cra1.icn and model.icn
unicon cra1 model
cra1.icn is a ~500 line Unicon program.
model.icn is a ~1500 line library module that provides code for
virtual spaces comprised of virtual 3D objects.
- The actual data that determines what space you experience is given
in a model file -- a data file containing a 3D model. That is what we
are studying.
-
The program cra1 is invoked with a model file as its command line argument.
cra1 csac.json
I think csac.json is one of three samples included in the cra1.zip file.
You can also try jeb.json and sh167.json. Our goal is to add a 4th: cramer.json
From this little demo program, we could make a maze game, a puzzle/adventure
game, a first-person shooter, or a networked multi-user roleplaying game.
But our mission in this module is not to go do that, our mission is to
represent Cramer Hall well enough that a user would recognize
it when they see it in-game, and vice-versa. So let's talk 3D models.
1.2 Models
A videogame level is a virtual model of some real or imaginary place.
Do we all know what a model is?
- A model is a representation of something else that lets us
study or understand it.
- Models are abstractions that simplify or ignore some parts
of a thing in order to focus or emphasize other aspects.
- A physical model can be built from toothpicks or Legos or
almost any other building material.
- A virtual model is a digital representation of something
that can be manipulated on a computer to let us study it
- Like all computer data, a virtual model can be raw binary (1 and 0) for
efficient computer processing or text (alphanumeric letters encoded as
groups of 1 and 0) for the sake of human readability
There are a zillion different types of digital models
used on computers. This is not vocational technical school. We are not
teaching you a commercial modeling tool this week (sorry). We are trying
to teach concepts by creating our own 3D model from scratch. But before
that, let's talk a bit more about what we are modeling: Cramer Hall.
Cramer Hall was built around 1970. As of 2023 it houses the computer science
and engineering department, the cybersecurity center, and the office of
innovation and commercialization at NMT.
- Cramer Hall consists of two traversable aboveground stories;
the basement is an apparently inaccessible mystery.
- What existing models of Cramer Hall are there?
- Textual models. You could literally just describe Cramer Hall, or
you could write a
text adventure
containing a description of each room/area of Cramer Hall.
- Floor Plans. A traditional floor plan might be the bases for a 2D
arcade-style model of the space. Alternatively, you could model each
of Cramer Hall's floors as ASCII art,
or develop an interactive roguelike 2D model.
- Architectural Blueprints. The 2D models used during construction do
not accurately reflect the current Cramer Hall, but in most respects they
will be correct about most things, and can help us coordinate and check our
work. The "real" Cramer blueprints below show a room numbering that
is substantially different from the actual room numbering. Also: up is
West; you may be used to reading maps with up being North.
- What are the requirements of the new model we want to build?
- Open to all. A lot of 3D model formats are proprietary secrets.
- Human-readable. I want to be able to understand/maintain the data.
- Machine-readable. The program must be able to parse the data, too.
- Enough expressive power to enable our model to recognizably resemble
the real thing.
- What our model doesn't have to do.
- It doesn't have to look indistinguishable from real life.
- It doesn't have to feel/behave exactly like real life.
- We don't have to model temperature, lighting, electronics, etc.
So, how do we represent complex structured data on a computer?
My first bruce force way of doing this was to just make it up as
I went along. Later, I learned a standard data format that would
do the job and make it easier for others to understand and use my data.
That format is called JSON.
We will use the JavaScript Object Notation (JSON) to build our model. You
can learn all there is to know about JSON in about 5 minutes; no wonder
it is so popular. JSON is described at
json.org which uses
railroad diagrams and a simple grammar to give a precise definition.
- JSON is written in an ASCII text format
- Can we write ASCII text files on these computers?
- Should we use a word processor, or a text editor?
- Do you know the difference between word processors and text editors?
- Should we try
this web-based text editor? Or the "vi" editor that comes with
Linux? Or Notepad, on Windows?
- Should we teach ASCII
- How to write a JSON file
- There are six kinds of things that can appear in a JSON file
- Four kinds of simple ("atomic") values: string, number, boolean, or null
- Examples:
"hello", 3.14, true, null
- Two kinds of collections that can contain multiple values:
arrays and objects
- An array is an ordered sequence; elements identified by index (position #).
- An object is an unordered collection; access elements by string key
- Square brackets for arrays, curly brackets for objects.
- Examples:
["hello", 3.14, true, null] vs.
{"hello": 3.14, "true": null}
- JSON syntax for these things is from JavaScript, but it is similar
in other popular languages like Pyhton.
3.1 Self-test (or maybe groups of two) activity
- Write a JSON file that represents for
each of us, what city we live in. (First, we will have to ask
how we want to identify "each of us" and find out what city we
live in).
- Check your JSON code to see if it has errors...with
jsonlint.com
3.2 Python Cross-Check
(Extra for experts; save this for later)
This week you will learn some Python, if you don't already know some.
JSON is easy to use from Python and might be useful to you in future.
If you store your answer to 3.1 in a file named ourcities.json,
you can read it from Python like this:
import json
with open("ourcities.json", "r") as read_file:
data = json.load(read_file)
and then use data in your program to access what you stored
in your JSON file. See if you can write Python code to print out what was
in your JSON file by walking through variable named data.
At this point you might want to ask yourself:
- Am I teaching simple 3D Modeling in JSON just so students get
to learn JSON? or:
- Am I teaching JSON just so we
have an extra human-friendly format in which to create 3D Models?
Unlike proprietary 3D Model formats that only
do polygons and pixel colors, we can put anything we want in
our JSON models...we could put text adventure descriptions in
if we wanted.
Now, it is time to practice JSON by using it to represent data about
Cramer Hall.
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.
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. The entire
building (except anything below ground level as viewed from the northwest
corner) will have fairly small positive real numbers in the model. This
coordinate system is referred to as TNN world coordinates (TNN=Tom Nartker
Normal).
- Tom Nartker was the founder of the NMT CS Department, and a friend
of mine.
- You can read about him on a plaque on the 1st floor of Cramer Hall. That plaque should definitely be in our Cramer Hall videogame level.
- There is also a tree dedicated to him outside our south entrance.
It would be interesting to extend our model outside far enough to include
the tree. I think that is a bridge too far for this week.
For each (x,y,z) or (l,w,h) that we need in our model, we have to figure
out their value in meters using the TNN coordinates. Our options are to
either
- physically measure everything with tape measures, or
- calculate our coordinates from existing scale-accurate models.
If the building floor plan or the blueprints include a legend with the scale
used, all your (x,y) and/or (l,w) measures can be gleaned from them. Two of
your dimensions are obtained cheap/easy that way. For the (y) or (height),
you will need to measure, but probably for an entire floor of a building
the ceiling height will be the same, except maybe for a special case or two.
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 blueprints or
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. How might we
double check this number? I estimated 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.
A graph is possibly the most fundamental building block of mathematics for
computer science. Every computer scientist learns about graphs.
- Can we teach 7th graders about graphs?
- How much will we need to say about graphs in this 3D Model lesson?
It turns out: graphs are easy and fun. For many years, New Mexico was
home to one of the most prominent mathematician/computer scientists in the
world, Frank Harary. He was
quite a comedian. But here is a short definition of graphs.
- graph
- a graph is a set of nodes and a set of edges
- node
- a node, or vertex, is a place or a state of being. Nodes can have
names or numbers to identify them. There can be different kinds of
nodes. They can have any information
(what I would call a "data payload") that you may want to use
in conjunction with that place or state of being.
- edge
- an edge is a connection or function that allows movement or
expresses relationship between two nodes. They also can have
names or labels, different kinds, and any data payload you want.
Computer Scientists usually draw graphs that look something like this.
Some graphs have edges that go both directions, other graphs' edges
will only go in one way.
If you wanted to draw your own graphs you could:
- write by hand on paper, or
- try a web software tool such as zoomcharts or
- download a local installable free drawing tool such as Dia, or something similar.
What does all this have to do with our 3D Model?
- Our nodes are called Rooms.
Each Room is a 3D volume in space that may contain
users or objects in the game
- Our edges are those holes in the wall that let you walk
from one rectangular area (room) into another. You traverse
an edge to get to the connecting room. There are two kinds of edges,
called openings and doors.
Now it is time to dive into details of representing our 3D Models in JSON.
The fundamental unit in our model is a box-shaped 3D volume of space, called
a "Room". By default, a Room will have no connections to other rooms, and
will be bounded by six solid walls. In practice, almost all Rooms are
connected to one or more adjacent rooms, so that people can get around.
Connections between rooms are discussed in the next section.
- A Room in a model is generally a space that a user can walk around in.
- It might be an actual rectangular room.
- It might be a part of a larger, more complex shaped room.
- It might be a corridor
- Simple rectangular volumes keep various arithmetic tasks simple.
- To make irregular shapes, you can either
- subdivide into smaller
rectangle shapes and connect them via openings, or
- you can allocate one big space and place various big
obstacles within a room to change its navigable shape.
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": "corridor 230",
"x": 28.8,
"y": 12.3,
"z": 15.23,
"w": 1.8,
"h": 3.5,
"l": 3
}
Most rooms have more data than just a boring stretch of corridor that uses
default textures to draw its walls, floor, and ceiling. By the way, this
example is not the corridor outside my office in Cramer Hall, it is
from in the Janssen Engineering Building at the University of Idaho. We have
to measure new corridor coordinates for Cramer Hall.
There are two ways to connect two adjacent Rooms together in our model:
Doors and Openings. Both of these require that the Rooms are touching
along part or all of one of their sides: the coordinates have to place
them right next to each other.
- Opening
- An opening connects two logical rooms into one larger space.
- An opening is a "hole" in the walls of a room.
- The hole can be the entire area by which two rooms adjoin,
or some fraction of it
- I notice my examples include a "height" field instead of an "h".
I should probably modify the code to be consistent. This assumes
that a door always starts at the bottom of a wall within a room;
if we were modeling a submarine we'd need a field for how high up
the bottom of the door starts.
- An opening is almost a 2D object with width and height and not
much 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
- Door
- A door is an opening with an attached object that can prevent movement.
- Most doors occupy a small fraction of wall that adjoins two rooms,
sized for the individuals that walk through the door.
- A door can be open, closed and/or locked. These properties can change
over time. A lot of doors in cramer are locked from only one side, i.e.
door is still openable from the inside when locked. Such a locked door
is sort of a one-way door. In graph terms, the edge is directed.
- The data payload we encode about our objects
in our .json file is static (non-changing), also called constant,
while the question of whether a door is open, or locked or not, might be
dynamic (changing) if the game has a mechanism by which the
property ever changes.
- It would be fair game (I guess) if we encoded initial values
in our JSON for whether a door is open or not, or locked or not.
But I'd kind of like to not mix our static model with our dynamic model.
- Some doors have custom texture images, 3D handles, etc. These properties
might be encoded with additional fields in our JSON.
- Some doors are double-doors. Those might 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,
"height": 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",
"height": "3.5",
"collide_in": "1.2",
"plane": "3",
"rooms": ["JEB228", "JEB230"],
}
Every room can optionally contain a list of zero or more 2D or 3D objects
that are there just for their appearance. The most basic decoration is a
2D (rectangle) object. The class "Wall" is actually just a 2D object that
has four corner (x,y,z) vertices and an associated texture image. The fact
that Rooms' walls happen to be solid is enforced by the Room class, not
the Wall class. While the vast majority of decorations are simple rectangle
(Wall class) objects, there are some classes for things like Windowblinds
that might involve many repetitions of a texture instead of a simple picture
of some window blinds.
{ "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]
},
{"class": "Windowblinds",
"coords": [29.4, 1.5, 29.1],
"angle": 90,
"crod": "blue",
"cblinds": "very dark purplish brown",
"height": 3.05,
"width": 4.7
}
]
}
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. One of the
For objects that the user can "feel", you put the
objects on another list: the obstacles list.
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]
}
]
}
4.7 Tools
A third category of thing besides obstacles and decorations that can be placed
in a room are called tools. This category is for things that are not quite
obstacles or decorations, but more like interactive objects that a user might
manipulate by clicking on them, or pick up in order to use later. For example,
the model might have virtual whiteboards, and whiteboard markers to draw on
them with. I guess
maybe we will skip tools in our model. We might change our mind later.
{"class" : "Pen",
"Id" : 1,
"coords": [60.5, 0.95, 20.55],
"color" : "blue",
"Angle" : 0
}
4.8 Furnishings
Although you can make almost anything by a suitable arrangement of Box
objects, common types of furniture will have game mechanics. They
go in the obstacles list. Classes "Chair" and "Table" support at
least two chair
types "office" and "lab"; maybe there is a third for "classroom".
Field "position" gives the direction the chair is facing, in degrees;
maybe 0 is due east, I forget.
It is an interesting question whether such objects should be modeled
as a logical entity like this, or simply as a collection of triangles
or something like that. A logical entity such as a "Chair" class tells
the application what game mechanics it should support, whereas just
describing a chair's appearance as a set of triangles would not.
{
"class": "Chair",
"coords": [31.2,0,1.4],
"position": 0,
"color": "red",
"type": "office":
"movable": "true"
},
{
"class": "Table",
"coords": [31.4,0,2.4],
"position": 180,
"color": "very dark brown",
"type": "office"
},
{"class": "Computer",
"coords_mntr": [58.85, 1.02, 20.4],
"coords_cpu": [59.2, 0.2, 20.25],
"coords_kb": [58.85, 0.96, 20.05],
"color": "very light gray",
"angle": 180
},
{"class": "Printer",
"coords" [42.25, 13, 27.4],
"angle": 0,
"color": white
}
4.8 Specialty Objects
Ramps, and Stairs are examples of objects that can be placed in a room
that interact with game mechanics in a fundamental way. Instead of
preventing movement, the user's y value is calculated from the base of
the room, plus some amount depending on their position on the ramp or
stairs.
In class Ramp, there is a "type" field.
- Type 1 gradually goes upwards from north to south or vice versa;
- Type 2 goes from east to west.
- Type 3 is a flat platform.
- Type 4 is a staircase rising from east to west;
- Type 5 is a staircase from north to south.
The number of steps (numsteps) field is used only for types 4-5.
{
"class": "Ramp",
"coords": [70.76, 0, 32.5],
"color": "pink",
"texture": "dat/nmsu/texsmall/blue_tile.gif",
"type": 3,
"width": 3.1,
"height": 1,
"length": 13.2,
"numsteps": 5
}
While we are talking about stairs, it might be worth discussing elevators.
I've implemented elevators before by sleight of hand, providing two or more
elevator rooms at different "y" elevations, and implementing a mechanic for
changing the user's "y" value to the selected floor, perhaps via a button
press. It would be possible to have a single elevator room object
move from one floor to another when the door is closed, but might be harder
to code...and the user might not see any difference.
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 obtain textures for the walls, floors, ceilings, and
objects in our model.
In this context, a texture is a 2D image, part or all of the
contents used to draw the surface of an object in a 3D scene. (Aside:
for what it's worth, textures a.k.a. "fill patterns" can also be used in
2D graphics).
- Texture Basics
- Texture Sizes
- width and height must be powers of two
- Converting a photo into a texture
5.1 Texture Basics
How much do your students already will know about digital images?
- pixel
- A pixel (from: picture element) is one dot in a digital image
- RGB
- The color of a pixel is typically given in (red,green,blue) values.
(0,0,0) is black. white is often (255,255,255) or (1.0,1.0,1.0).
Other colors are obtained by mixing R, G and B in different ratios.
- 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
- Modern cameras often take pictures with ~20M pixels.
- A modern 4K 2D display shows ~8M pixels, so 20M is overkill unless
you are printing in high resolution and/or blowing up to wall- or poster-sized
(often projection) of the image.
- A texture in a 3D scene is usually drawn on a small fraction of the
screen. 1%? 10%?
- Depending on the size of your object in the model, you would seldom
need more than 1024x1024 even though your camera can shoot much finer pictures.
- A lot of your textures can be 512x512, or 128x128, or...
- A 3D scene may have dozens (hundreds?) of textures that
all have to fit in your graphics card at the same time.
- It might be possible to run out of graphics card memory by using
too many textures that are too large...but this is difficult
if you have a modern graphics card.
- Computers without 3D graphics cards need smaller textures.
5.3 Converting a photo into a texture
For this part, we should learn a little bit of a program called the
GIMP.
You can do some of this crudely with Windows Paint, or you can do it with
Photoshop if you know that tool.
- 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, probably as .jpg or .png
- GIMP expects you to "export" to save in an image format. Its normal
"save" commands saves in some weird proprietary GIMP format.
5.4 Texture Activity
In this exercise, let's practice making a usable texture of the Tom Nartker
plaque from Cramer 1st floor, south hallway. You should apply this process,
if you have time, to other textures that you encode 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.
(In subsequent instructions where I show the filename nartkerplaque.jpg, you
probably want to pick nartkerplaque2.jpg, since that is the better image
on the right.)
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
http://www.cs.nmt.edu/~jeffery/cramerhall/nartkerplaque2.jpg. So,
visit link and right click the image and click "Save image as..." and
save a local copy under your home directory.
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. I believe 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 JPEG (.jpg) or PNG (.png) or maybe
even the venerable GIF (.gif) might be good.
The Export As for the JPEG format, and some others, will ask you what
"quality" to use; this affects image file size and accuracy. The default
(quality 90 in this case) is generally good.
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 some
professional PhotoShip (or GIMP) nerd; 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 I am going
to call it good for now.
This part of the module asks students to each build a part of the
Cramer Hall Model. This will require tape measures, cameras, paper and
writing utensils. Turn in your .json and images on Canvas.
- Each student will be assigned one section of the model, probably one
room. We can't do rooms that are locked! But Dr. J has the Master Key.
- Models are encoded in the TNN coordinate system that we use in
common. Students should make sure their boundary coordinates match with
the others' sections that connect with their own.
- The results of the activity will be encoded in JSON format.
Zones for instructor week are shown here:
Cramer 230b 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 Tuesday 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
}
OK, so that's a "D" grade. Now to bump that grade up by adding
textures, decorations and obstacles. Except woops, when I try to run
./cra1 cra230b.json
it dies with the message:
valid JSON, but not a model file: cra230b.json
What could possibly be wrong?
6.2 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.
- 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
- Test it using the cra1 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 cra1 model viewer will surely
not be able to load and view it.
If checkjson is OK, then you can run the cra1 model viewer like this:
./cra1 cramer228.json
Cramer 230b Example, continued
In the case of my cra238b.json:
- jsonlint says it is legal JSON.
- checkjson says it is legal JSON.
- it was not a legal model file because...
a model file is an array of JSON objects, not a single JSON object.
- The output of checkjson should say it is a "list"... of stuff rather than
a "table"... of stuff.
- In Python and Unicon an "array" is called a list
- In Python a JSON object is called a "dictionary",
while in Unicon it is called a "table"
When I add square brackets around my json code, it will display in cra1:
[{ "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.
- Cramer 230b raw photo images .zip,
from which to make textures (23 images)
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.jpg"
}
]
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:
The models produced in the preceding activity will need to be collated
together into one big model file. It was previously conjectured in a MST
camp planning meeting, and
possibly true, that "this would best be performed by CJ".
- Students
turn(ed) in whatever is/was put together by Thursday evening.
- This creates a bottleneck if the whole project depends on one
person (Jeffery) doing a lot of work overnight Thursday for a
Friday demo. Anticipated and certainly true in practice.
- Bottleneck would be lessened if students do some of the
doors/openings. Everyone should try to add at least one door or opening
connecting to one other person.
What follows this are various fancy next steps that are not part of this week's
camp curriculum, but we would introduce next if we were continuing.
7.1 Tiling textures
Tiling is when a texture is repeated to cover a large area.
- Avoids "stretching" a texture when applying it to more area than it
was originally shot for.
- Yields a higher effective resolution from smaller/fewer textures
- Things like ceiling tiles are hard to capture with a single image,
easier to capture a single tile and repeat it.
- Removing the "seams" is important, especially in carpet, wall, grass etc.
Could have a whole GIMP session on this topic.
7.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.
- How many polygons is the minimum, and how many polygons is the sweet spot
- Choice between representing something physically vs. depicting it in an image
This part of the module will allow students to run the CVE collaborative
virtual environment on lab computers, and see all the models, stitched
together.
- "Fun" end of week activity
- See and compare each others' work, give constructive peer feedback
- Download http://www.cs.nmt.edu/~jeffery/cramerhall/cramer2.zip, unzip it, maybe have
to type "unicon cra1 model" to build cra1 executable, then run
"./cra1 230.json" and see where you can get.
8.1 What Dr. J Learned from teaching Cramer Module at MST Camp
Don't repeat these in your reflections, unless you have something
more and different to say!
- Students were Good Sports about testing research software!
- By last night, students turned in 8 .json files, 19 image files.
- Need to add instruction on how to get pictures from cameras into PC's,
particularly into our Linux lab PC's! Some folks did it with no
instruction!
- Not many pictures turned in yet. Turn in your pictures.
- "How to edit text files" was a problem, should have focused
on Linux GUI text editor on Lab machines. Maybe would benefit
from a text editor with a JSON-mode syntax coloring etc.
- Campers could not modify cra1 demo files due to ownership "root".
Fix, or start class by
copying into a new directory where students can work
- Campers picked up a lot of Linux terminal commands during the week!
- json file syntax learned by all, but it is nitpicky and harder than
it should be. Matching brackets properly, commas, etc.
- Some students found it easy to follow examples, others not so much.
- Students maybe are not used to nesting things inside other things.
- Decorations have to go Inside the Room object that they decorate
- cra1 demo's new JSON support was fragile/buggy
- spurious "legal JSON not a model file" messages
- The JSON filename mattered, could not start with number
- Creating textures with the GIMP was challenging;
some students used the GIMP and produced good cropped
power-of-two textures
- Adding textures to the 3D Model JSON files was too fragile. Images
did not show, even when campers did everything Right.
- Sticking in trivial decorations like a whiteboard or a sign is more
work than it should be. Should be a way to just stick something on a
wall somewhere.
- Doors and openings needed
more or better explanation, or more time and coordination, to put
more doors/openings and connect everyone up.
- One student put together two rooms with an opening Thursday.
- Corridors have a minimum width in order to be passable! Had to
widen some as-measured corridors a little bit.
8.2 What teachers Learned from Cramer Module at MST Camp
- a thing called JSON
- save your files as .json
- Python has its rules, JSON has its rules...
- showing different things you can do in computers, it is not all coding
or playing games
- really hard starting from zero, Cramer meant switching between languages,
which was bad.
- computers are frustrating
- pre-print the floor plan maps, make xyz calculations as easy as possible