Computer Graphics Workshop '96 Problem Set 3
The first step is to write the function compute-point-on-torus. The arguments to this function are:
This function should return a Scheme vector of the x, y, and z coordinates. To make this vector, use the vector function:
> (define x 2) > (define y 3) > (define z 4) > (vector x y z) #(2 3 4)You may want to include the following definition in your program:
(define M_PI 3.14159265358979323846)
You will probably want to add more nodes to the above scene graph (such as an SoMaterial node) to be able to change more parameters of the torus (like its color).
We want the torus to be an "object" that we can interact with in the same way we interact with Open Inventor objects from within Scheme. You should use this wrapper for the "->" function to allow Scheme and C++ objects to share the same syntax, in a similar fashion to the object system used in the adventure game in 6.001.
;;; SICP-ish simple object system for dealing similarly ;;; with Scheme and C++ objects using "send" (define (send object message . args) (if (C++-object? object) (eval `(-> ,object ',message ,@args)) (let ((method (get-method object message))) (if (not (no-method? method)) (apply method (cons object args)) (error "No method named" message))))) (define (get-method object message) (object message)) (define (no-method method) 'no-method) (define (no-method? method) (eq? method 'no-method))Using this wrapper, and the structure for your Scheme objects described below, you can now use this "send" function to send messages to native Inventor objects and objects you have written in Scheme in the same way. For example:
> (define root (new-SoSeparator)) > (send root 'ref) > (define torus (new-Torus 10 3 20 10)) ;; new-Torus ;; defined below > (send root 'addChild (send torus 'getGeometry))Now define the "new-Torus" function, which is the constructor for a new Torus object:
(define (new-Torus major-radius minor-radius x-res y-res) (define root (new-SoSeparator)) (send root 'ref) ;;; ... Insert code here to build scene graph ... (lambda (message) ;;; Method to return pointer to root of scene graph (cond ((eq? message 'getGeometry) (lambda (self) root)) ((eq? message 'generate) (lambda (self) (let* ((points (compute-torus-polygons major-radius minor-radius x-res y-res 0 0)) (num-points (length points))) (set-mfield-values! (send coords 'point) 0 points) (send (send coords 'point) 'setNum num-points) ;; update the values in the face set: ;; (num-points / 4) polygons of four vertices. (let loop ((i 0)) (send (send face-set 'numVertices) 'set1Value i 4) (if (< i (/ num-points 4)) (loop (1+ i)))) (send (send face-set 'numVertices) 'setNum (/ num-points 4))))) ;;; Insert code here for other methods which include ;;; setColor, setMajorRadius, setMinorRadius, ;;; setHorizResolution, and setVertResolution. ;;; After all other methods' definitions, ;;; if we haven't been able to find this method, ;;; signal an error (else (no-method message)))))Each method takes the current object as its first argument (i.e. (lambda (self arg1 arg2 ...))). All of the "set" methods end with a call to
(send self 'generate)This allows the torus object to be operated upon in a similar fashion to other Inventor objects; when a "field" in the torus is changed (i.e. the major radius) the scene graph is automatically redrawn to reflect that change.
Look at the man page for SoShapeHints. It has three fields: vertexOrdering, shapeType, faceType, and creaseAngle. The creaseAngle field specifies (in radians) the maximum angle between adjacent polygons before they stop being smoothly shaded together. In Inventor 2.1 the default crease angle is 0; in previous releases it was 0.5. If your torus is not smoothly shaded, add a shape hints node to your scene graph and increase its crease angle to 0.6 or 0.7.
To make the torus render faster, you can enable backface culling; this prevents polygons not facing the camera from rendering. It is only appropriate to enable this feature for solid shapes; but since normally you can not see the "inside" of the torus, we can use it here.
Add a shape hints node to your graph and set the shapeType field to be SOLID:
(-> (-> shape-hints 'shapeType) 'setValue SoShapeHints::SOLID)Now, depending on whether you ordered the vertices in your polygons clockwise or counterclockwise with respect to the outside of the torus, set the vertexOrdering field to CLOCKWISE or COUNTERCLOCKWISE:
(-> (-> shape-hints 'vertexOrdering) 'setValue SoShapeHints::CLOCKWISE) ;; or: (-> (-> shape-hints 'vertexOrdering) 'setValue SoShapeHints::COUNTERCLOCKWISE)(If you have the wrong ordering, you will know: the inside of the torus will be visible on the screen, and will not look like a physically realizable object.) Switch back and forth between the SOLID and UNKNOWN_SHAPE_TYPE shape types. Note the difference in rendering speed.
$Id: index.html,v 1.9 1996/01/17 22:39:40 kbrussel Exp $