SPECTRUM + 3D #1
(c)1997 Dark/X-trade and -STS-/VolgaSoft
────────────── ───────────────────────────
With this series of articles, the authors set
I have the task of showing ways to re-
implementation on the "fast" 3D graphics spec.
In principle, these articles are aimed at
a beginner coder, since a coder with
experience and probably knows all this.
Although, perhaps he can find for se-
something interesting (at least me-
re in algorithms). Our goal is not so much
give ready-made recipes and templates, how much
push the reader to further self-
meaningful study of the subject.
We haven’t explained anything particularly complicated here.
We won’t accept it, but nevertheless, we hope
We hope that your Gray Matter will not come out
from the banks before you reach
end of the text.
We'll start by solving a simple problem:
rotation of a wire object (without cutting off)
for lines that go off the screen). For per-
howl article is quite enough.
All we need is for the object to spin
wasted, is to ask it and code it,
a shadowy computer, and a quick procedure
ru lines.───────────── ────────────────────────────
The lines of code that you will see in
text, written in order to simply
explain the essence of things, and WERE NOT subjected to
without any capital optimization.
The working code can be found on the disk at
file 3DROTATE. There are 2 more files -
ALGORITMand DIVTABS, details about which
See more at the end of the article, in the section
"Algorithms". All sources are written with
using specific syntax
"STORM TURBO ASSEMBLER" (which, according to
opportunities, you can find here or
in ZX-Format #7). Something about syntax
Storm's you can also find the section
"Algorithms". The files are given in text form
where you could watch them
outside the assembler. Examples in the text, according to
possibilities are given in classical syntax
sis. To upload them to STORM you should
use the text import function
new file-BREAK+T.
───────────── ────────────────────────────
So, let's define an object. Let it be
simple pyramid.
We will describe it as a set of edges
(edge) each of which is stretched between
between two vertices (vertex). Vertices are given
in the so-called object space, i.e. from-
relative to the object's center of rotation.
The array looks something like this:
PIRAMID DW edge
vertex ;DB hp, yn, zn
DB 0,40,-20 ;base
DB 60,-20,-20 ;//
DB -60,-20,-20 ;/
DB 0,10,40 ;peak
DB #80 ;end
edge ;DB from_point_M, to_point_N
DB 0,1 ;base connection
D.B.1.2 ;//
DB 2.0 ;/
DB 0.3 ;conn. peak with base
DB 1.3 ;//
DB 2.3 ;/
DB -1 ;end
The object seems to have been set. Now let's take care of you...
numerator.
To rotate an object, it is enough to check
remove its tops. Rotation occurs
relative to zero in the same object -
nom space according to the following formulas:
Z axis work
X' =x*cos AZ + y*sin AZ
Y' =y*cos AZ - x*sin AZ
Y axis work
Z' =z*cos AY + x'*sin AY
X''=x'*cos AY - z*sin AY
X-axis workhorse
Y''=y'*cos AX + z'*sin AX
Z''=z'*cos AX - y'*sin AX
Naturally, we will calculate the data
formulas in real time and without any help
there are giant tables like A=B*SIN C,
for all possible values of B and C, so
how, naturally, this is only suitable for
intros or small demos.
First we write a procedure like:
Rotate (a,b,angle)
{
at=a*cos+b*sin
b=b*cos-а*sin
a=at
}
Let's say the input and output parameters are
it will be 8-bit:
IN :D,E=Y,X (SGN) C=ANGLE
OUT:D,E=Y,X (SGN)
;this procedure is provided simply for
illustrations.
;since 3DROTATE uses more
fast.
ROTATE LD Н,COSTB[
LD L,C
LD C,(HL)
LD A,L:SUB #40:LDL,A
LD B,(HL)
;B=sin C=cos
LD L,C:LD H,E
CALL MULS ;Н=Н*L (with signs)
LD A,H:EXA
;A'=X*COS
LD L,B:LD H,D
CALL MULS
EXA:ADD A,H:LD LX,A
;LX=X*COS+Y*SIN
LD L,C:LD H,D
CALL MULS
LD A,H:EXA
;A'=Y*COS
LD L,B:LD H,E
CALL MULS
EXA:ADD A,H:LD D,A
;D=Y*COS-X*SIN
LD E,LX
;E=X*COS+Y*SIN
RET
Let's write the final procedure:
Rot3D (x,y,z,rotX,rotY,rotZ)
{
Rotate (x,y,rotZ)
Rotate (z,x,rotY)
Rotate (y,z,rotX)
}
IN :D,E,C=Y,X,Z
OUT:D,E,C=Y,X,Z
ROT3D PUSH SUN
LD BC, (ROTZ)
;rotatable x,y at an angle rotZ
CALL ROTATE;XY
ROR VS
;replaceable t=y; y=x; x=z
LD B,D:LD D,E:LD E,C
;rotating z,x at an angle rotY
PUSH AIRCRAFT
LD BC,(ROTY)
CALL ROTATE
ROR VS
;replaceable z=y; y=z; x=t
LD C,D:LD D,E:LD E,C
;rotatable y,z by angle rotX
PUSH AIRCRAFT
LD BC, (ROTX)
CALL ROTATE
ROR VS
;replaceable t=y; Y=x; X=z; Z=t
LD A,D:LD D,E:LD E,C:LD C,A
RET
ROTX DB 0
ROTY DB 0
ROTZ DB 0
So we have a rotated vertex.
To achieve our goal it is enough
translate it into screen space
(project onto screen). Let's assume
that our Z axis is directed away from the observer
la deep into the screen.
Most commonly used projections
two:
- Parallel
The Z value is simply not taken into account.
Xr=X''+Xoffset
Yr=Y''+Yoffset
- Perspective
The formula is usually used
Xr=((X''+Xcnt)*Scale/(Z+Zcnt))+Xoffset
Yr=((Y''+Ycnt)*Scale/(Z+Zcnt))+Yoffset
! Z+Zcenter at a visible point cannot
be <=0
Scale - scaling factor.
It affects the viewing angle and is selected
to taste.
X/Yoffset - screen center (#80,#60)
X/Y/Z cnt (center) - the center of the object in 3D.
X/Yr (real) - coordinates of a point on the screen.
The resulting values of Xr and Yr are added -
into the buffer of projected vertices.
DOTS2D ds number of vertices*2
Let's use perspective projection.
The scaling factor (scale) is
is constant, so it is reasonable to eliminate
comes from multiplying by it, replacing the mind-
operation by shift or recoding according to
table. We will take the coefficient equal to
256.
All these actions (starting with rotation and
so far) are fulfilled for all vertices,
of which we have 4.
The procedure does all this:
PROJECT ;PROJECT ALL VERTEXES
LD HL,(OBJECT)
INC HL:INC HL
;HL=vertices
LD IX,DOTS2D
PROJ LD A,(HL):INC HLSR #80
;sign of the end
RET Z
LD E,A
LD D,(HL):INC HL
LD C,(HL):INC HL
PUSH HL
CALL ROT3D
LD A,CENTERZ:ADD A,C:LD L,A
LD A,CENTERY:ADD A,D:LD N,A
PUSH HL
LD A,CENTERX:ADD A,E:LD N,A
CALL FDIVB; Н.L(SGN)=Н(SGN)/L
LD A,OFFSETX:ADD A,L
;L=Н.L*256 (Н=0)
LD (IX),A:INC LX
;unsubscribed Xr
POP HL
CALL FDIVB
;Y screen coordinate goes from top to bottom
;and in bottom-up transformations
LD A,CENTERY:SUB L
;does Yr go off the screen?
;let's cut it off in advance so that later
;take care
SR #C0:JR C,$+4:LD A,#BF
LD (IX),A:INC LX
;unsubscribed Yr
POP HL
JR PROJ
The DOTS2D array must be locatedto a beautiful address (low byte=0),
There's just a little bit left - just to connect
points are lines, but this smallness is
takes up the lion's share of the time. For this for
We take each edge from the edge array (see.
above) numbers of two vertices - N1 and N2
X1=DOTS2D[N1*2]
Y1=DOTS2D[N1*2+1]
X2=DOTS2D[N2*2]
Y2=DOTS2D[N2*2+1]
and draw a line between points (x1,y1) and
(x2,y2).
There is a RENDER procedure for this.
which displays the object on the screen (pre-
highly purified). In principle, this pro-
The procedure must take care to cut off the
tions going off the screen, but we
we won't do it. Therefore, limit in advance
chili ranges of numbers, those in the buffer.
;Display an object on the screen
RENDER ;RENDER OBJECT (EDGES)
LD HL,(OBJECT)
LD E,(HL):INC HL
LD D,(HL)
;DE=ribsRENDR LD Н,DOTS2D[
LD A,(DE):INC DE
;from the top...
ADD A,A:LD L,A
;sign of the end
RET C
LD C,(HL):INC L
LD B,(HL)
;got x1,y1
LD A,(DE):INC DE
;to the top...
ADD A,A:LD L,A
PUSH DE
LD E,(HL):INC L
LD D,(HL)
;got x2,y2
CALL LINE
POP DE
JR RENDR
Drawing the line takes the lion's share
time.
In Algorithms you will find the fastest
of all currently existing
on the Spectrum implementation of the line (moreover,
with the possibility of further increase
speed).
---------------------------------------
So the main loop should beapproximately
like this:
LD HL,PIRAMID
LD (OBJECT),HL
MAIN CALL EXGVIEW;Exchange screens
CALL PROJECT;Projection
CALL RENDER ;Output to shadow
;screen
LD HL,ROTX ;Changing angles
.1 INC (HL)
INC HL
.3 DEC (HL)
INC HL
.2 INC (HL)
LD A,#7F:IN A,(#FE)
RRA:JR C,MAIN
RET
ROTX DB 0
ROTY DB 0
ROTZ DB 0
OBJECT DW 0
As you can see, it's all very simple, simpler
and it cannot be.
Actually, for objects with a large number of
quality of peaks and, especially, with complex
transformations(turns around the
arbitrary axis, scaling) very
it is profitable to build a transformation matrix,
then for all we need to do with
the top is to perform 9 multiplications and
write X and Y to the buffer... Somehow,
Perhaps we will work with matrices as well.
Looking ahead, let's say that next
This article will describe a method that
allows you to easily process volumes
projects consisting of hundreds of vertices, but for
it is not effective for such a simple object.
Share your thoughts about the article