On this page:

10 3D Universe

 (require pict3d/universe) package: pict3d

This module provides functionality for creating interactive, graphical programs in the style of 2htdp/universe; i.e. by defining plain mathematical functions. The biggest difference is that scenes are in THE THIRD DIMENSION!

Another difference is that big-bang3d, the analogue of big-bang in 2htdp/universe, is a plain Racket function with keyword arguments.

Besides minor stylistic differences, there are some significant interface differences. Callback functions receive not only the current state, but a frame count and an inexact number of milliseconds since the big bang. There is no separate pad handler, no separate draw handler for the initial and final states, and no separate frame limit. On the whole, the interface is both a little more streamlined and a little more complicated.

What did you expect? You’re doing 3D. You’re playing with the big kids now.

One of the simplest pict3d/universe programs is
#lang racket
(require pict3d
(big-bang3d 0)

This opens a 512x512 window named World3D that renders empty-pict3d at 30 frames per second, which responds to no events except those that close the window. When the window closes, big-bang3d returns 0, which was given as the initial state.

A slightly more complicated program does the ol’ spinning cube animation:
#lang racket
(require pict3d
(current-material (material #:ambient 0.01
                            #:diffuse 0.39
                            #:specular 0.6
                            #:roughness 0.2))
(define lights+camera
  (combine (light (pos 0 1 2) (emitted "Thistle"))
           (light (pos 0 -1 -2) (emitted "PowderBlue"))
           (basis 'camera (point-at (pos 1 1 0) origin))))
(define (on-draw s n t)
  (combine (rotate-z (rotate-y (rotate-x (cube origin 1/2)
                                         (/ t 11))
                               (/ t 13))
                     (/ t 17))
(big-bang3d 0 #:on-draw on-draw)

Press F12 at any time to dump the most amazing “screenshots” ever taken—the current Pict3Ds—into DrRacket’s REPL.

There is currently no support for networked games.


(big-bang3d init-state    
  [#:valid-state? valid-state?    
  #:pause-state? pause-state?    
  #:stop-state? stop-state?    
  #:name name    
  #:width width    
  #:height height    
  #:x x    
  #:y y    
  #:display-mode display-mode    
  #:gl-config gl-config    
  #:cursor cursor    
  #:frame-delay frame-delay    
  #:on-frame on-frame    
  #:on-key on-key    
  #:on-release on-release    
  #:on-mouse on-mouse    
  #:on-draw on-draw])  S
  init-state : S
  valid-state? : (-> S Natural Flonum Boolean) = (λ (s n t) #t)
  pause-state? : (-> S Natural Flonum Boolean) = (λ (s n t) #f)
  stop-state? : (-> S Natural Flonum Boolean) = (λ (s n t) #f)
  name : String = "World3D"
  width : Positive-Integer = 512
  height : Positive-Integer = 512
  x : (U Integer False) = #f
  y : (U Integer False) = #f
  display-mode : (U 'normal 'fullscreen 'hide-menu-bar)
   = 'normal
  gl-config : (Instance GL-Config%) = (pict3d-default-gl-config)
  cursor : (U (Instance Cursor%) False) = #f
  frame-delay : Positive-Real = (/ 1000 30)
  on-frame : (-> S Natural Flonum S) = (λ (s n t) s)
  on-key : (-> S Natural Flonum String S) = (λ (s n t k) s)
  on-release : (-> S Natural Flonum String S) = (λ (s n t k) s)
  on-mouse : (-> S Natural Flonum Integer Integer String S)
   = (λ (s n t x y e) s)
  on-draw : (-> S Natural Flonum Pict3D)
   = (λ (s n t) empty-pict3d)
Runs a “3D world” program.

On startup, big-bang3d begins to keep track of
  • The current state s : S, initially set to init-state.

  • The frame number n : Natural, initially set to 0.

  • The time t : Flonum, in milliseconds, initially set to 0.0.

All callback functions—valid-state?, pause-state?, stop-state?, on-frame, on-key, on-release, on-mouse and on-drawreceive the current values of s, n and t.

There are two phases in running a 3D world program: initialization and frame loop. In the initialization phase, big-bang3d does the following once.
  1. Computes (valid-state? s n t); if #f, raises an error.

  2. Computes (pause-state? s n t).

  3. Computes (stop-state? s n t).

  4. Creates a window with title name and a width-by-height client area. The window contains only a pict3d-canvas% with (on-draw s n t) as its initial Pict3D. The window is positioned at x and y on the screen (where #f values use auto-placement). The display-mode determines the window’s style, either as a normal window, a fullscreen window, or a fullscreen-like window that hides the window’s title and menu bar (but is not “fullscreen” from the platform’s perspective). The canvas is configured with gl-config, and cursor is installed as the canvas’s cursor.

  5. Waits one second for the GUI machinery to start up.

  6. Synchronizes on a signal that the window has painted itself for the first time.

If (stop-state? s n t) returned #f, big-bang3d enters the frame loop phase. In the frame loop phase, big-bang3d repeats the following.
  1. Updates n to (+ n 1).

  2. Updates t to the numer of milliseconds since big-bang3d was called minus the number of milliseconds spent in paused states.

  3. Computes (on-frame s n t) to yield a new state s.

  4. Handles all accumulated keyboard and mouse events, which also update sand waits until a new keyboard or mouse event if the most recent s is a pause state.

  5. Computes (on-draw s n t) to yield a new Pict3D, which it sets in the canvas.

  6. Computes the number of milliseconds ms until frame-delay milliseconds will have passed since the start of the frame, and sleeps for (max 1.0 ms) milliseconds.

Sleeping for at least one millisecond gives the canvas time to receive GUI events when a frame loop iteration takes longer than frame-delay milliseconds.

Key presses are handled by computing (on-key s n t k) to yield a new state s. Key releases are handled by computing (on-release s n t k) to yield a new state s. In both cases, the key event code k is the value returned by get-key-code or get-key-release-code, converted to a string.

Mouse events are handled by computing (on-mouse s n t x y e) to yield a new state s. The values x and y are the mouse cursor’s event position, and e is a string that indicates what kind of event occurred. Values for e are the symbols returned by the method get-event-type of mouse-event%, converted to strings, unless the symbol is 'motion. In that case, e is "drag" if a mouse button is pressed; otherwise "move".

After every state update, the frame loop
  1. Checks (valid-state? s n t); if #f, raises an error.

  2. Checks (pause-state? s n t) to determine whether to pause the frame.

  3. Checks (stop-state? s n t); if #t, flags the frame loop as being on its last iteration.

If stop-state? ever returns #t or the window is closed, the frame loop exits after completing its current iteration, and big-bang3d returns s.

The callbacks valid-state?, stop-state? and on-draw can determine whether they’re being used during the initialization phase by checking (zero? n).

Changed in version 1.2 of package pict3d: Added #:pause-state?.