QBASIC整数数学旋转和透视算法演示

QBASIC整数数学旋转和透视算法演示

参考程序

'该源码由Rich Geldreich在1992.1.2完成
'QuickBASIC4.5 3D线框动画程序.
DEFINT A-Z
TYPE LineType
    X AS INTEGER
    Y AS INTEGER
    Z AS INTEGER
    X1 AS INTEGER
    Y1 AS INTEGER
    Z1 AS INTEGER
END TYPE
DIM Points(100) AS LineType
DIM Xn(100), Yn(100), Zn(100)
DIM Xs1(100), Ys1(100), Xe1(100), Ye1(100)
DIM X(100), Y(100), Z(100), Pointers1(100), Pointers2(100), Sp(100), Zp(100)
DIM R(100), B(63), B1(63)
DIM Cosine&(360), Sine&(360)
CLS
PRINT "3-D Craft"
PRINT "By Rich 1992.1.2"
PRINT
PRINT "Keys to use: (Turn NUMLOCK on!)"
PRINT "Q...............Quits"
PRINT "Numeric keypad..Controls your position(press 5 on the keypad"
PRINT "                to completly stop yourself) "
PRINT "-...............Forward exceleration"
PRINT "+...............Backward exceleration"
PRINT "Arrow keys......Controls the rotation of the craft"
PRINT "F...............Excelerates the craft (Forward)"
PRINT "B...............Slows the craft (Backward)"
PRINT "S...............Stops the craft"
PRINT "A...............Toggles Auto Center, use this when you lose";
PRINT " the craft"
PRINT "C...............Stops the craft's rotation"
PRINT "V...............Resets the craft to starting position"
PRINT
PRINT "Wait a sec..."

'下面的for/next循环生成一个正弦和余弦表。
'每个正弦和余弦都乘以1024,并存储为长整数。
'这样做是为了我们不必使用任何缓慢的浮点。
'单CPU下一边计算一边执行影响速度。
A = 0
FOR A! = 0 TO 359 / 57.29577951# STEP 1 / 57.29577951#
    Cosine&(A) = INT(.5 + COS(A!) * 1024)
    Sine&(A) = INT(.5 + SIN(A!) * 1024): A = A + 1
NEXT
'接下来,我们读入对象中的所有行。。。
FOR A = 0 TO 44
    READ Points(A).X, Points(A).Y, Points(A).Z
    READ Points(A).X1, Points(A).Y1, Points(A).Z1
NEXT
'困难的部分来了。。。考虑这种情况:
'我们有两条相连的线路,如下所示:
'   1--------2 and 3
'            |
'            |
'            |
'            |
'            4
'其中1,2,3&4是每条线的起点和终点。
'第一条线由点12组成,第二条线由第3点和第4点组成。
'那么,你会问,怎么了?没什么,真的,但你没看到吗?
'第2点和第3点真的在采样点吗?为什么要旋转它们两次,那完全是在浪费时间?
'以下代码从行表中删除了此类情况。(很好的解释,是吗?)

NumberLines = 45
'把所有的起点和终点放在一个大数组中。。。
Np = 0
FOR A = 0 TO NumberLines - 1
    X(Np) = Points(A).X
    Y(Np) = Points(A).Y
    Z(Np) = Points(A).Z
    Np = Np + 1
    X(Np) = Points(A).X1
    Y(Np) = Points(A).Y1
    Z(Np) = Points(A).Z1
    Np = Np + 1
NEXT
'现在设置两组指针,指向由一条线组成的每一点。。。
'(换句话说,在我们刚刚构建的点阵列中,扫描每个起点和
'终点的第一次出现…)
FOR A = 0 TO NumberLines - 1
    Xs = Points(A).X
    Ys = Points(A).Y
    Zs = Points(A).Z            '获取起点的3个坐标
    FOR B = 0 TO Np - 1         '扫描点阵列
        IF X(B) = Xs AND Y(B) = Ys AND Z(B) = Zs THEN
            Pointers1(A) = B    '将指针设置为指向
            EXIT FOR            '我们刚刚发现的点
        END IF
    NEXT
    Xs = Points(A).X1           '做与我们上面做的相同的事情
    Ys = Points(A).Y1           '除了扫描终点
    Zs = Points(A).Z1           '每条线路的
    FOR B = 0 TO Np - 1
        IF X(B) = Xs AND Y(B) = Ys AND Z(B) = Zs THEN
            Pointers2(A) = B
            EXIT FOR
        END IF
    NEXT
NEXT
'好吧,差不多完成了!我们现在要做的就是建一张桌子
'这告诉我们哪些点实际上是旋转的。。。
Nr = 0
FOR A = 0 TO NumberLines - 1
    F1 = Pointers1(A)   '获取起点和终点编号
    S1 = Pointers2(A)
    IF Nr = 0 THEN      '如果Nr=0,那么'如果这是第一个点,那么它当然
                        '必须旋转
        R(Nr) = F1: Nr = Nr + 1
    ELSE
        Found = 0       '扫描以查看此点是否已存在。。。
        FOR B = 0 TO Nr - 1
            IF R(B) = F1 THEN
                Found = -1: EXIT FOR    '射击,已经到了!
            END IF
        NEXT
        IF NOT Found THEN R(Nr) = F1: Nr = Nr + 1   '指向数组中的点
                                                    '在数组中我们
    END IF                                          '找不到它。。。
        
    Found = 0   '现在寻找终点
    FOR B = 0 TO Nr - 1
        IF R(B) = S1 THEN
            Found = -1: EXIT FOR
        END IF
    NEXT
    IF NOT Found THEN R(Nr) = S1: Nr = Nr + 1
NEXT
FOR A = 0 TO 63
    B(A) = (4 * A) \ 8
    B1(A) = A - B(A)
NEXT
PRINT "Press any key to begin..."
A$ = INPUT$(1)

Deg1 = 0: Deg2 = 0: D1 = 0: D2 = 0

Spos = -200: Mypos = 0

Mx = 0: My = 0: Mz = 0: Ox = 0: Oy = 0: Oz = -260

NumberOfFrames = 0
DEF SEG = &H40
StartTime = PEEK(&H6C)

SCREEN 13
FOR A = 0 TO 63
    OUT &H3C7, A: OUT &H3C8, A: OUT &H3C9, A: OUT &H3C9, 0: OUT &H3C9, 0
NEXT

DO


    
    Deg1 = (Deg1 + D1) MOD 360
    Deg2 = (Deg2 + D2) MOD 360
    IF Deg1 < 0 THEN Deg1 = Deg1 + 360
    IF Deg2 < 0 THEN Deg2 = Deg2 + 360
   
    C1& = Cosine&(Deg1): S1& = Sine&(Deg1)
    C2& = Cosine&(Deg2): S2& = Sine&(Deg2)
    C3& = Cosine&(Deg3): S3& = Sine&(Deg3)
    'Deg3 = (Deg3 + 5) MOD 360
   
    X = Speed: Y = 0: Z = 0
 
    X1 = (X * C1&) \ 1024: Y1 = (X * S1&) \ 1024
    X2 = (X1 * C2&) \ 1024: Zn = (X1 * S2&) \ 1024
   
    Y3 = (Y1 * C3& - Zn * S3&) \ 1024
    Z3 = (Y1 * S3& + Zn * C3&) \ 1024
   
    Ox = Ox + X2: Oy = Oy + Y3: Oz = Oz + Z3
    IF Oz > 32000 THEN Oz = 32000
    IF Oz < -32000 THEN Oz = -32000
    IF Ox > 32000 THEN Ox = 32000
    IF Ox < -32000 THEN Ox = -32000
    IF Oy > 32000 THEN Oy = 32000
    IF Oy < -32000 THEN Oy = -32000
   
    
    IF AtLoc THEN
        Mx = Mx + (Ox - Mx) \ 4
        My = My + (Oy - My) \ 4
        Mz = Mz + ((Oz + 200) - Mz) \ 4
    ELSE
        '根据用户的移动量调整用户的位置。。。
        Mz = Mz + Mzm: Mx = Mx + Mxm: My = My + Mym
        IF Mz > 32000 THEN Mz = 32000
        IF Mz < -32000 THEN Mz = -32000
        IF Mx > 32000 THEN Mx = 32000
        IF Mx < -32000 THEN Mx = -32000
        IF My > 32000 THEN My = 32000
        IF My < -32000 THEN My = -32000
    END IF
   
    LOCATE 1, 1: PRINT A$
    
    MaxZ = -32768
    LowZ = 32767
    FOR A = 0 TO Nr - 1
        R = R(A)
        Xo = X(R): Yo = Y(R): Zo = Z(R)
        
        X1 = (Xo * C1& - Yo * S1&) \ 1024
        Y1 = (Xo * S1& + Yo * C1&) \ 1024
       
        X2& = (X1 * C2& - Zo * S2&) \ 1024 - Mx + Ox
        Z2 = (X1 * S2& + Zo * C2&) \ 1024
        
        Y3& = (Y1 * C3& - Z2 * S3&) \ 1024 - My + Oy
        Z4 = (Y1 * S3& + Z2 * C3&) \ 1024
        
        Z3 = Z4 - Mz + Oz
       

        Zn(R) = Z4
        IF Z4 > MaxZ THEN MaxZ = Z4
        IF Z4 < LowZ THEN LowZ = Z4
       
        'X2&,Y3&,Z3

        '如果该点离观看者太近(或落后),则
        '不要绘画它。。。
        IF (Mypos - Z3) < 15 THEN
            Xn(R) = -1000: Yn(R) = 0: Zn = 0
        ELSE
            V = (1330& * (Spos - Z3)) \ (Mypos - Z3)
            Xn(R) = 160 + X2& + (-X2& * V) \ 1330
            Yn(R) = 100 + (8 * (Y3& + (-Y3& * V) \ 1330)) \ 10
        END IF
    NEXT
       
    MaxZ = MaxZ - LowZ
   
       
    Nl = 0
    FOR A = 0 TO NumberLines - 1
        F1 = Pointers1(A): S1 = Pointers2(A)
        IF Xn(F1) <> -1000 AND Xn(S1) <> -1000 THEN
            Sp(Nl) = A
            Zp(A) = (Zn(F1) + Zn(S1)) \ 2
            Nl = Nl + 1
        END IF
    NEXT
    Nl = Nl - 1
    '根据线的Z坐标对线进行排序
    IF Nl > -1 THEN
        Mid = Nl \ 2
        DO
            FOR A = 0 TO Nl - Mid
                IF Zp(Sp(A)) > Zp(Sp(A + Mid)) THEN
                    SWAP Sp(A), Sp(A + Mid)
                    CL = A - Mid
                    CH = A
                    DO WHILE CL >= 0
                        IF Zp(Sp(CL)) > Zp(Sp(CH)) THEN
                            SWAP Sp(CL), Sp(CH)
                            CH = CL
                            CL = CL - Mid
                        ELSE
                            EXIT DO
                        END IF
                    LOOP
                END IF
            NEXT
            Mid = Mid \ 2
        LOOP WHILE Mid > 0
    END IF
    '等待垂直回扫
    WAIT &H3DA, 8
    '擦除旧点
    FOR A = Ln - 1 TO 0 STEP -1
        LINE (Xs1(A), Ys1(A))-(Xe1(A), Ye1(A)), 0
    NEXT
   
    Ln = 0
    FOR A1 = 0 TO Nl
        A = Sp(A1)
       
        Z = Zp(A)
        F1 = Pointers1(Sp(A1)): S1 = Pointers2(Sp(A1))
       
        Xn = Xn(F1): Yn = Yn(F1)
        
        IF Xn <> -1000 THEN
            X1 = Xn(S1)
            IF X1 <> -1000 THEN
                Y1 = Yn(S1)
                Z1 = (Z - Mz + Oz)
                
                IF Z1 > -1500 THEN
                    '计算颜色
                    T = 63 - ((Z1 * -63&) \ 1500)
                    C = B1(T) + (B(T) * (Z - LowZ)) \ MaxZ
                    '画线
                    LINE (X1, Y1)-(Xn, Yn), C
                    '存储以备以后使用               
                    Xs1(Ln) = X1: Ys1(Ln) = Y1
                    Xe1(Ln) = Xn: Ye1(Ln) = Yn
                    Ln = Ln + 1
                END IF
            END IF
        END IF
    NEXT
    '处理击键
    K$ = UCASE$(INKEY$)
    '处理击键(如果有)。。。
    IF K$ <> "" THEN
        SELECT CASE K$
            CASE "A"
                AtLoc = NOT AtLoc
            CASE "+"
                Mzm = Mzm + 2
            CASE "-"
                Mzm = Mzm - 2
            CASE "5"
                Mxm = 0: Mym = 0: Mzm = 0
            CASE "4"
                Mxm = Mxm - 2
            CASE "6"
                Mxm = Mxm + 2
            CASE "8"
                Mym = Mym - 2
            CASE "2"
                Mym = Mym + 2
            CASE "F"
                Speed = Speed + 5
            CASE "B"
                Speed = Speed - 5
            CASE "C"
                D1 = 0: D2 = 0
            CASE "S"
                Speed = 0
            CASE CHR$(0) + CHR$(72)
                D1 = D1 + 1
            CASE CHR$(0) + CHR$(80)
                D1 = D1 - 1
            CASE CHR$(0) + CHR$(75)
                D2 = D2 - 1
            CASE CHR$(0) + CHR$(77)
                D2 = D2 + 1
            CASE "Q", CHR$(27)
                SCREEN 0, , 0, 0: WIDTH 80
                CLS
                PRINT "END"
                END
            CASE "V"
                D1 = 0: D2 = 0: Deg1 = 0: Deg2 = 0: Speed = 0
        END SELECT
    END IF
    NumberOfFrames = NumberOfFrames + 1
    '查看是否已经通过了20帧;如果是,那么看看
    '花了多长时间。。。
    IF NumberOfFrames = 20 THEN
        TotalTime = PEEK(&H6C) - StartTime
        IF TotalTime < 0 THEN TotalTime = TotalTime + 256
        FramesPerSecX100 = 36400 \ TotalTime
        High = FramesPerSecX100 \ 100
        Low = FramesPerSecX100 - High
        'A$的字符串打印在左上角
        '屏幕的一角
        A$ = MID$(STR$(High), 2) + "."
        A$ = A$ + RIGHT$("0" + MID$(STR$(Low), 2), 2) + "  "
        NumberOfFrames = 0
        StartTime = PEEK(&H6C)
    END IF
LOOP
'以下数据是航天飞机。。。
'存储为 开始 X,Y,Z & 结束 X,Y,Z
DATA -157,22,39,-157,-18,39
DATA -157,-18,39,-127,-38,39
DATA -127,-38,39,113,-38,39
DATA 113,-38,39,193,12,39
DATA 33,42,39,33,42,-56
DATA 33,42,-56,-127,42,-56
DATA -127,42,-56,-157,22,-56
DATA -157,22,-56,-157,22,39
DATA -157,22,-56,-157,-18,-56
DATA -157,-18,-56,-157,-18,39
DATA -157,-18,-56,-127,-38,-56
DATA -127,-38,-56,-127,-38,39
DATA -127,-38,-56,113,-38,-56
DATA 113,-38,-56,113,-38,39
DATA 113,-38,-56,193,12,-56
DATA 193,12,-56,193,12,39
DATA -157,22,-56,193,12,-56
DATA 193,12,39,-157,22,39
DATA -56,-13,41,-56,-3,41
DATA -56,-3,41,-26,-3,41
DATA -26,-3,41,-26,7,41
DATA -51,7,41,-31,-13,41
DATA -11,-13,41,-11,-3,41
DATA -11,-3,41,-1,7,41
DATA 9,7,41,9,-8,41
DATA 9,-8,41,24,-8,41
DATA 34,16,41,34,-38,41
DATA 33,-39,41,33,-39,-53
DATA 33,-39,-53,33,15,-53
DATA -42,-38,19,-72,-38,19
DATA -72,-38,19,-72,-38,-41
DATA -72,-38,-41,-42,-38,-41
DATA -42,-38,-41,-42,-38,19
DATA 33,42,39,34,16,41
DATA 33,42,-56,33,15,-53
DATA -157,22,39,-127,42,39
DATA -127,42,-56,-127,42,39
DATA -127,42,39,33,42,39
DATA 159,-8,-56,159,-8,40
DATA 143,-18,-56,143,-18,39
DATA 193,12,39,193,32,30
DATA 33,42,39,193,32,30
DATA 193,32,30,193,32,-47
DATA 33,42,-56,193,32,-47
DATA 193,12,-56,193,32,-47
 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值