For an Operating System / Window Manager Engineer, focus usually means the application in the foreground. The application with focus is receiving keyboard and mouse events. On some systems, only the application with focus can make sounds. Furthermore, the applications without focus may be running at a lower priority, thus receiving less compute time.
Modal / Full Screen UI
In the mobile space, this question of focus is rather straight forward. Displays are so small, that the window manager will display the application with focus on the entire screen. Although I think it's a bit of a misnomer, more and more people are refer to such as scheme as a modal UI. These modal, or full-screen, UIs have been getting a lot of news lately. Steve Jobs announced that full-screen apps are going to play a more serious role in Mac OS X Lion.
I was a little apprehensive with fear that he was going to dumb down my Mac desktop user experience. I gained more confidence in the idea when I thought about all of the [semi]-pro apps that I use on my Mac that already had full screen modes. I always figured that those apps were full screen to give creative professionals the maximum amount of real estate. Now, I actually think it has more to do with minimizing distraction and allowing for better mental focus.
Full Screen Equals Full Mental Focus
This point hit me late last night. I bought an iPad yesterday. I bought it primarily for leisure computing. I found that my MacBook Pro was constantly in the middle of 2-3 school/geek projects. I tend to just leave things open when I'm in the middle of them. I feel it encourages me to pick back up more easily. What it actually does is stress me out and distract me. I couldn't even enjoy a cup of coffee and read RSS feeds without wanting to touch up some OpenCL. My idea for the iPad was to get away from a desk and relax a little. I could ignore all of those open projects and relax for a few minutes.
That lasted about an hour last night before I found myself downloading class notes and sitting at the kitchen table with a beer for some late night studying. It was really effective too. When you're working in a modal UI, all you can do is what's in focus. And if you turn off status updates, you won't even be bothered by incoming emails, tweets, calendar notifications, etc. I was easily able to stay on task, only briefly popping over to another browser window to look things up.
Apple Might Be On To Something
I'm definitely going to dwell on this some more and make some personal observations about my usage, but I think Steve might be on to something. We've long known that multi-tasking hits a point of diminishing returns after two or three tasks. I personally struggle with the constant context switching. Having a modal UI might help me focus on the task at hand, whether it's studying, coding, or relaxing.
BTW, Google Reader Play is an absolute joy on the iPad. Too bad it doesn't use my feeds.
Download Project Source/Scenes/Mac-Binaries: Program3.tar.gz
For the first part of the Ray Tracing project, I added a quite a few extra features. One of those extra features was the recursive calculations of Specular Reflection, Dielectric Reflection, and Dielectric Transmission. I considered myself pretty lucky, considering that this feature is one of the two features that we were required to add for this second part. However, I wasn't quite in the clear. Lets just say that I had a looser understanding of ray tracing than I thought.
Many of the features of my Ray Tracer were implemented in the first part. That list can be seen on that project post. The following are new features:
- Mid-Axis Partitioning
- SAH Partitioning
- Cost-Based Termination of leaf nodes for both
- Recursive KD Tree Traversal
- KD Tree Printing in Debug Builds
- Fixed Ray Tracing bugs
- Dramatically Improved Ray Tracing Performance
- Interactive Ray Shooting in Debug Builds
When you launch my Ray Tracer, the following are the defaults that are used unless you specify otherwise.
- Dimensions: 500x500
- Sampling: 4 x 4 Adaptive Jittered Supersampling
- Ray Casting: Blinn-Phong Lighting with an Ambient Factor
- Ray Tracing: Specular Reflections, Dielectric Reflections, and Dielectric Transmission supported through recursion terminated based on a contribution threshold
- Multi-Processing: Uses multiple CPU cores through OpenMP
- KD Tree: Built using SAH cost analysis to determine best split and when to terminate branches
The optics involved with refraction are not very intuitive to me. Initially, I thought that an image seen through a glass sphere would be reduced, but instead it's actually magnified. I had a rather serious bug when calculating refraction. I was refracting my rays with a dot product of the ray and surface normal with the wrong sign. Correcting that made a tremendous difference.
Once I started rendering the scene with 16 spheres, I started to realize that I had some serious additive errors on calculations of the transmissive component. There were two reasons for this. Firstly, I was calculating the reflective and transmissive components inside of the loop that calculated the phong shading for each light source. Fixing this corrected several of the bright spots, and it led to a signficant speed improvement.
Secondly, I was calculating the phong shading and reflective components for for illumination points inside of a sphere. This scenario arose whenever I was calculating the color for a refracted ray transmitted through a sphere. The refracted ray would intersect the other side of the sphere on the inside, and at that point I should have only been calculating the transmissive component. Making this change also led to a dramatic speedup.
My KD Tree was actually a deceleration structure for much of the project. I had several issues when creating the tree, as well as the traversal. I started by creating a KD Tree that simply divided the space at the midpoint of the split axis.
The first issue that I had, was that I was creating a new bounding box around the primitives in each of the newly split subspaces. This is very problematic, because it created overlapping spaces whenever I had the occurrence of a single primitive shared between both spaces. Once drew a clear delineation between space partitioning and bounding volume hierarchies, I was able to clean up my KD Tree and I saw fewer artifacts.
My next hurdle was understanding how to traverse the tree correctly and to fix the remaining artifacts. Initially, while I was trying to learn how KD Trees work, I was only considering an algorithm where the ray always intersected the outermost bounding box. This was fundamentally flawed for several reasons. First off, the ground sphere made the bounding box really large, but it didn't create to many artifacts for me. The second major instance of rays originating inside of the outermost bounding box where theway used when calculating shadows, reflections, and transmissions. Through some digging, I found a very helpful post that illustrated the different cases that have to be handled when traversing a KD Tree.
His diagrams were very helpful. They were so implanted in my brain that I ended up adopting his algorithm completely from the code that he posted. He still missed two cases, that I initially had some trouble finding. I ended up implementing a special, interactive debug feature that would allow me to use the mouse to point at a pixel in the viewing window and result in the rendering of that single view ray. I would use it by rendering the entire scene, setting a breakpoint, then clicking on the pixel that I needed to test. This was invaluable in finding the remaining artifacts as well as some ray tracing issues.
At this point, my KD Tree still proved to be more of a deceleration structure. I fired up a profiler, and found a number of slowdowns related to mallocs when operating on C++ vectors. I reduced my use of vectors and passed them by reference throughout the KD Tree traversal. This brought significant gains, but my KD Tree was still slower.
The next step was to implement a smarter space partitioning scheme based on comparing the Surface Area Heuristic of each new subspace. This cost calculation was also critical to determining when to make a leaf node. I had a few bugs that led to excessive node duplication. Once I sorted those out, I finally got the gains I was hoping for. My resulting tree for the more complicated scene was 11 nodes deep, and contained several empty leaf nodes.
16 Sphere Scene Without a KD Tree
Size: 500x500 Total Primitive Intersection Checks: 223084940 Total Node Traversals: 0 Total Render: 29.763917 seconds
16 Sphere Scene With KD Tree
Size: 500x500 Build KD Tree: 0.000580 seconds Total Primitive Intersection Checks: 55731412 Total Node Traversals: 161224507 Total Render: 24.878577 seconds
I reduced the number of sphere intersections from 225m to 161m while only adding 55m node traversals. The time savings wasn't as dramatic as I had hoped, likely because my algorithm still used functional recursion instead of maintaining a smaller stack inside of a loop. For my final project, I'm likely going to go stackless altogether since I'll be using the GPU too.
However, I really started to notice gains when I upped the complexity of the scene. I created a model of 140 reflective spheres arranged into a tightly-packed pyramid.
140 Sphere Scene Without KD Tree
Size: 500x500 Total Primitive Intersection Checks: 1016735174 Total Node Traversals: 0 Total Render: 103.413575 seconds
140 Sphere Scene With KD Tree
Size: 500x500 Build KD Tree: 0.091852 seconds Total Primitive Intersection Checks: 230486448 Total Node Traversals: 161218665 Total Render: 38.800175 seconds
I haven't posted about my Enertia for a while. At first, I feared that the novelty had worn off. I really haven't been riding it much...until this last weekend. And with that fresh seat time, my enthusiasm for the Enertia picked right back up where it left off. Coincidently, I passed the 2500 mile mark too.
Extra Leg on the Commute
A few changes in my circumstances have led to my lessened use of the Enertia. Firstly, I'm commuting from the office to school two days a week. Parking on campus is a nightmare. You basically have to park in a commuter lot and hop a bus in.
However...when I ride a motorcycle in, I can park right next to my building. This is exactly the time savings I was looking for to reduce my time away from the office, so I've been happily riding a motorcycle on those days. Unfortunately I haven't found a place to charge the Enertia on campus. Furthermore, in the spirit of saving time, I take the interstate. All of this means that I ride my V-Strom gasser instead of the Enertia.
I've reduced my Enertia riding on the weekend too, which is a shame, because the Enertia is perfect for running errands around home. I've got a roommate now, and we do a lot of things together. Unfortunately there's no room on the Enertia for a passenger.
My changed circumstances have highlighted the Enertia's range and capacity issues and affected the utility of the Enertia somewhat. At the same time though, riding my bulky, stinky, and loud V-Strom have made me appreciate the Enertia even more. It's a bit of a conundrum.
Enter the Empulse. This bike
could will directly solve two of my three problems. I should easily be able to commute on this, even on days when I'm on campus too. Even though I can't easily charge on campus, the extended range will mean that I likely won't need to. Furthermore the liquid cooled motor means that I'll be able to sustain highway speeds on the Interstate and avoid taking a circuitous route at lower speeds. This will prove to be a huge time saver.
Unfortunately, there still isn't room for a passenger. But riding two-up is for old folks anyway...except for the time I took too laps at Jennings GP with Jason Pridmore. We definitely didn't lap like old folks. Although I nearly lost control of my bowels like a grandpa.