Earlier, we used convenience function of skandha to make a sphere. Let's have a look how things can be made from scratch. We are going to make a square -- a very simple thing specified with four points which can be organized into just one facet. We will also paste texture to the facet. First, we create an appropriate data structure -- a thing of rectangles:
(setq my-square (XG.3D-MAKE-THING-OF-RECTANGLES :WANT-POINT-NORMALS t :WANT-POINT-COLORS t :WANT-FACET-NORMALS t :WANT-FACET-COLORS t :WANT-FACET-TEXTURES t ))
The thing my-square is currently empty, and should be filled with data. Let's make a list to hold the 3D coordinates of the four points of the square:
(setq square-points '( (-1 -1 0) ; point 0 ( 1 -1 0) ; point 1 ( 1 1 0) ; point 2 (-1 1 0) ; point 3 ))
A model of a 3D object should contain a number of points, for which we need to know the x-, y- and z- coordinates. In skandha, these are stored in a graphic relation (an instance of the class GRAPHIC-RELATION). Points in space are represented by a relation containing three FLOAT arrays named conventionally :POINT-X, :POINT-Y and :POINT-Z. Let's create such arrays as follows:
(defvar point-count 4)
(setq my-Xs (send class-float-array :new point-count)) (setq my-Ys (send class-float-array :new point-count)) (setq my-Zs (send class-float-array :new point-count))
make a graphic relation to hold four points:
(setq my-point-grl (:new class-graphic-relation point-count))
add the point arrays to the graphic relation:
(send my-point-grl :set-array :point-x my-Xs) (send my-point-grl :set-array :point-y my-Ys) (send my-point-grl :set-array :point-z my-Zs)
fill the arrays with data from the list square-points (using function dataelem, which helps us address the elements of the list as if it was a two dimensional array):
(defun dataelem (data row col) (nth col (nth row data)))
(dotimes (i point-count) (send my-point-grl :setf (list :point-x (dataelem square-points i 0) :point-y (dataelem square-points i 1) :point-z (dataelem square-points i 2) ) i ) )
and set the point relation of my-square to my-point-grl relation:
(xg.3d-set my-square :point-relation my-point-grl)
We can now look at the thing, but at this we will only see four pixels
on the screen corresponding four points:
Facets Facet graphic relation is used to organize points into facets, and may also be used to carry other information about facets (e.g. color). In case of rectangular facets, FACET-RELATION should contain four 32 bit integer arrays named FACET-0, FACET-1, FACET-2 and FACET-3 corresponding to four points in space that define facets. An element of the array is an index that we use to look up the 3D coordinates of the corresponding point in the arrays POINT-X, -Y and -Z of the the POINT-RELATION:
As seen in the figure, the same point can be used to define more than one facet. Different elements of arrays of the FACET-RELATION can and often do refer to the same entry in the PIONT-RELATION.
To create one facet for the square, we first create the appropriate data structure:
(setq my-facet-grl (xg.3d-make-grl-of-rectangles))
make it point to the four points of my-point-grl:
(:vector-push-extend my-facet-grl (list :facet-0 0 :facet-1 1 :facet-2 2 :facet-3 3 ))
and add the facet relation to my-square thing
(xg.3d-set my-square :facet-relation my-facet-grl)
You may have noticed that the arrays of both POINT- and FACET-RELATIONs
should be of the same length. In general, all arrays within a graphics
relation must be of the same shape -- they must have the same number of
dimensions and be the same size in each dimension.
To work with texture, let's first load an image. In skandha4, PIXEL-RELATION -- a different type of graphic relation -- is used to for this type of graphic data. It contains three class-8-bit-float-array instances named :PIXEL-RED, :PIXEL-GREEN and :PIXEL-BLUE. We can create a PIXEL-RELATION by loading an image file:
(setq my-image (XTIF-LOAD-TIFF-FILE "my-texture.tif"))
A 2D coordinate system (u, v) is imposed upon the image so that (0, 0) corresponds to the lower left corner of the image, and (1, 1) corresponds to the upper right corner. To paste an image (or its fragment) onto a polygon, we specify appropriate texture coordinates at each point of the polygon. Texture coordinates may be specified in either the facet or the point relation. To provide texture coordinates via the point relation, we include arrays named :POINT-TEXTURE-U and :POINT-TEXTURE-V. This would be the appropriate way to map an image coherently onto a tiled sheet of polygons. Since this is a simplified example, we map the image onto just one facet.
First, we create the arrays:
(setq my-Us (send class-float-array :new point-count)) (setq my-Vs (send class-float-array :new point-count))
provide the (u,v) coordinates for each point of the facet:
(setq square-point-textures '( (0 0) ; point 0 (1 0) ; point 1 (1 1) ; point 2 (0 1) ; point 3 ))
(dotimes (i point-count) (:setf my-Us (dataelem square-point-textures i 0) i) (:setf my-Vs (dataelem square-point-textures i 1) i) )
and add arrays to the point-relation created earlier:
(send point-grl :set-array :point-texture-u my-Us) (send point-grl :set-array :point-texture-v my-Vs)
create the texture (object of CLASS-TEXTURE) and add it to my-square:
(setq my-texture (:new CLASS-TEXTURE :TEXTURE-IS :BY-FACET :GRAPHIC-RELATION my-image ) )
(xg.3d-set my-square :texture my-texture)
We can
now draw the scene and see the result of pasting the texture to the facet.
For comparison, the original pixel relation is also added to the thing-list.
Pixel relation will be drawn pixel by pixel in the bottom left corner of
the image.
(setq thing-list (list :LIGHTS (list light) my-square (list :pixel-relation my-image-grl)))
(send camera :set :things thing-list) ;; This tells the camera what to draw
(XG.3D-FRAME-LOOP :FULL-WINDOW-CAMERA camera :CAMERA-LIST (list camera))