📄 3d 映射原理 .txt
字号:
mov eax,Move1X
mov ebx,Move1Y
sub eax,MoveX
sub ebx,MoveY
mov ls,eax
mov ls1,ebx
finit
;------------------
;屏幕x轴参考向量改变角度等于lsrad
;rad是改变快慢的系数
fild ls
fld rad
fdiv
;------------------
fsincos
fld dword ptr VectorU
fld dword ptr VectorU+4
fld dword ptr VectorU+8
fmul st(0),st(3)
fstp dword ptr VectorA+8
fmul st(0),st(2)
fstp dword ptr VectorA+4
fmul
fstp dword ptr VectorA
fld dword ptr VectorR
fld dword ptr VectorR+4
fld dword ptr VectorR+8
fmul st(0),st(3)
fstp dword ptr VectorB+8
fmul st(0),st(2)
fstp dword ptr VectorB+4
fmul
fstp dword ptr VectorB
movaps XMM0,VectorA
addps XMM0,VectorB
movaps VectorU,XMM0
;屏幕x轴改变方向
invoke VecMul,addr VectorU,addr VectorV,addr VectorR
;屏幕x轴改变方向后要立即重新计算屏幕法向量
finit
fild ls1
fld rad
fdiv
fsincos
fld dword ptr VectorV
fld dword ptr VectorV+4
fld dword ptr VectorV+8
fmul st(0),st(3)
fstp dword ptr VectorA+8
fmul st(0),st(2)
fstp dword ptr VectorA+4
fmul
fstp dword ptr VectorA
fld dword ptr VectorR
fld dword ptr VectorR+4
fld dword ptr VectorR+8
fmul st(0),st(3)
fstp dword ptr VectorB+8
fmul st(0),st(2)
fstp dword ptr VectorB+4
fmul
fstp dword ptr VectorB
movaps XMM0,VectorA
addps XMM0,VectorB
movaps VectorV,XMM0
;屏幕y轴改变方向
invoke VecMul,addr VectorU,addr VectorV,addr VectorR
;屏幕y轴改变方向后要立即重新计算屏幕法向量
ret
rad dd 100.0
Circumgyrate endp
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
local ls
local ls1
local ls2
mov eax,uMsg
.if eax == WM_TIMER
push y
mov ebx,100
lp
push ebx
push x
mov ecx,100
@@
push ecx
;===================================================================
;核心代码段,原理在上面的理论分析中已经讲了
invoke Function,addr x;计算函数的z轴坐标
invoke VecMul,addr x,addr VectorR,addr VectorL
;计算原点到函数点所够成的向量与屏幕法向量的法向量
invoke VecMul,addr VectorL,addr VectorR,addr VectorT
;计算上面得出向量与屏幕法向量的法向量
;此向量落在屏幕上,与屏幕法向量,原点到函数点所够成
;向量是共面的
invoke Projection,addr x,addr VectorT,addr VectorT
;求原点到函数点所够成向量在屏幕上的投影向量,
;此向量是三维向量,不是我们要的二维向量。
invoke VectorAbs,addr VectorT
;计算投影向量的模长
mov ls,eax
invoke IntstAngle,addr VectorT,addr VectorU
;计算投影向量与屏幕x轴参考向量的夹角余弦值
mov ls1,eax
invoke IntstAngle,addr VectorT,addr VectorV
;计算投影向量与屏幕y轴参考向量的夹角余弦值
mov ls2,eax
finit
fld ls
fld ls1
fld ls
fld ls2
fmul
fistp ls2
fmul
fistp ls1
add ls2,300;加上y轴偏移值,因为屏幕是不显示负坐标的
add ls1,300;加上x轴偏移值
;此时ls1是屏幕x轴坐标,ls2是屏幕y轴坐标
invoke SetBmpPixel,lpBmp,ls1,ls2
;把计算好的象素坐标设置到32bit位图中
;===================================================================
finit
fld x
fadd add2
fst x
pop ecx
dec ecx
jnz @b
pop x
finit
fld y
fadd add2
fst y
pop ebx
dec ebx
jnz lp
pop y
;----------------------------------
mov edi,lpBmp
mov ecx,lpBmp
mov edx,lpBmp
add ecx,40
invoke SetDIBitsToDevice,hdc,0,0,dword ptr[edi+4],
dword ptr[edi+8],0,0,0, dword ptr[edi+8],
ecx,edx,DIB_RGB_COLORS;绘制处理好的图象
mov edi,lpBmp
mov ecx,600600
mov eax,-1
add edi,40
rep stosd;把位图涂成白色
.elseif eax == WM_MOUSEMOVE
cmp DownJh,0;当鼠标左键按下时允许变换图象
jz @f
mov eax,lParam
mov edx,lParam
and eax,0ffffh
shr edx,16
mov MoveX,eax
mov MoveY,edx
push eax
push edx
invoke Circumgyrate
;变换屏幕所在平面的坐标从而使图象变换
pop Move1Y
pop Move1X
@@
.elseif eax == WM_LBUTTONDOWN
invoke SetTimer,hWnd,1,1,0;设置最快的速度刷新屏幕图象
mov DownJh,1;当鼠标左键按下时设置允许变换图象标记
mov eax,lParam
mov edx,lParam
and eax,0ffffh
shr edx,16
mov Move1X,eax
mov Move1Y,edx
.elseif eax == WM_LBUTTONUP
invoke KillTimer,hWnd,1;停止刷新屏幕图象
mov DownJh,0;当鼠标左键弹起时设置不允许变换图象标记
.elseif eax == WM_NCMOUSEMOVE
invoke KillTimer,hWnd,1;停止刷新屏幕图象
mov DownJh,0;当鼠标指针移到边框时设置不允许变换图象标记
.elseif eax == WM_CREATE
invoke VecMul,addr VectorU,addr VectorV,addr VectorR
;计算屏幕法向量
;在映射时这个向量非常重要
invoke SetTimer,hWnd,1,1,0
invoke GetDC,hWnd
mov hdc,eax
.elseif eax == WM_CLOSE
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
_ProcWinMain endp
_WinMain proc
local @stWndClassWNDCLASSEX
local @stMsgMSG
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
invoke RegisterClassEx,addr @stWndClass
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,
WS_SYSMENU,
0,0,625,650,
NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
.break .if eax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endw
ret
_WinMain endp
start
invoke GlobalAlloc,0,4600600+40;为600600分辨率的32bit位图分配内存空间
;一般情况下存储的是24bit位图,所谓的32bit位图只有低24bit是有用的,
;用32bit是为了与内存4BYTE对齐,加快处理速度。
mov lpBmp,eax
mov edi,eax
mov dword ptr[edi],40;头文件大小
mov dword ptr[edi+4],600;水平分辨率
mov dword ptr[edi+8],600;垂直分辨率
mov dword ptr[edi+12],200001h;设置平面数为1,20h(32)bit的位图
mov ecx,600600
mov eax,-1;白色
add edi,40
rep stosd;把位图涂成白色
call _WinMain
invoke GlobalFree,lpBmp;释放位图空间
invoke ExitProcess,NULL
end start
看到这里,你一定迫不及待想要看到结果了吧~ 使用MasmPlus 可以很容易帮助你编译。不过需要做一点点修改:
在MASMPLUS的安装目录下找到 IDE.INI ,在段[ASM]中修改下面的语句:
#Compiler=ml.exe $(CParam) Fo$(FileName).obj $(FileDir)$(FileName).$(FileExt)
修改为
#Compiler=ml615.exe $(CParam) Fo$(FileName).obj $(FileDir)$(FileName).$(FileExt)
当然还要在MASMPlusBin 中放一个 ml615.exe
之后使用 新建 Win32 EXE 模板,新建一个EXE工程,用上面的代码取代模板中的就可以了。
另外,还可以尝试编写自己的函数,比如下面的函数
Function proc lpVector
; _______
;f(x,y)=(√x^2+y^2)20
mov edi,lpVector
finit
fld _10
fld dword ptr[edi+4]
fld dword ptr[edi]
fmul st,st
fxch
fmul st,st
fadd
fdiv DWORD PTR [_10]
fst dword ptr[edi+8]
ret
_10 dd 20.0
Function endp
--------------------------------------------------------------------------------
上一篇 欢迎访问AoGo汇编小站httpwww.aogosoft.com 下一篇
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -