Archive

Archive for August, 2016

Vim 异步运行 Shell 指令的插件 – AsyncRun

August 24th, 2016 No comments

自制另一个新的 Vim 8.0 专用异步插件:asyncrun.vim,它可以让你在 Vim 里面异步运行各种 Shell 指令并且把结果实时输出到 Quickfix,需要 Vim 7.4.1829 以上版本。

安装方法

到插件首页 https://github.com/skywind3000/asyncrun.vim 下载项目,并拷贝 asyncrun.vim 到你的 ~/.vim/plugin。或者使用 Vundle 指向 skywind3000/asyncrun.vim 来自动更新。

基本教程

使用 gcc 异步编译当前文件:

:AsyncRun gcc % -o %<
:AsyncRun g++ -O3 % -o %< -lpthread 

该命令会在后台运行 gcc 并且把输出实时显示在 Quickfix 窗口,宏 % 代表当前文件名,%< 代表没有扩展名的文件名。

异步运行 make:

:AsyncRun make
:AsyncRun make -f makefile

异步调用 grep:

:AsyncRun! grep -R word . 
:AsyncRun! grep -R <cword> .

默认 :AsyncRun 运行命令后,输出添加到 Quickfix时 Quickfix 会自动滚动到最下面那一行,使用感叹号修饰符以后,可以避免 Quickfix 自动滚动。同时 <cword> 代表当前光标下面的单词。

编译 go项目:

:AsyncRun go build %:p:h

%:p:h 代表当前文件的目录

查询 man page,异步 git push ,以及把设置 F7异步编译当前文件:

:AsyncRun! man -S 3:2:1 <cword> 
:AsyncRun git push origin master
:noremap <F7> :AsyncRun gcc % -o %< <cr> 

使用手册

AsyncRun – Run shell command:

:AsyncRun{!} [cmd] ...

后台运行命令并且实时输出到 quickfix 窗口,如果有感叹号修饰符,quickfix 窗口的自动滚动将会禁止。

命令参数以空格分割,接受下面这些以 ‘%‘, ‘#‘ or ‘<‘ 开头的替换宏:

%:p     - File name of current buffer with full path
%:t     - File name of current buffer without path
%:p:h   - File path of current buffer without file name
%:e     - File extension of current buffer
%:t:r   - File name of current buffer without path and extension
%       - File name relativize to current directory
%:h:.   - File path relativize to current directory
<cwd>   - Current working directory
<cword> - Current word under cursor
<cfile> - Current file name under cursor

运行一个命令前,环境变量也会做如下设置:

$VIM_FILEPATH  - File name of current buffer with full path
$VIM_FILENAME  - File name of current buffer without path
$VIM_FILEDIR   - Full path of current buffer without the file name
$VIM_FILEEXT   - File extension of current buffer
$VIM_FILENOEXT - File name of current buffer without path and extension
$VIM_CWD       - Current directory
$VIM_RELDIR    - File path relativize to current directory
$VIM_RELNAME   - File name relativize to current directory 
$VIM_CWORD     - Current word under cursor
$VIM_CFILE     - Current filename under cursor
$VIM_GUI       - Is running under gui ?
$VIM_VERSION   - Value of v:version
$VIM_MODE      - Execute via 0:!, 1:makeprg, 2:system()
$VIM_COLUMNS   - How many columns in vim's screen
$VIM_LINES     - How many lines in vim's screen

AsyncStop – Stop the running job:

:AsyncStop{!}

停止后台任务(使用 TERM信号),如果有感叹号修饰,则使用 KILL 信号结束

基本设置:

g:asyncrun_exit - 字符串,如果不为空那么任务结束时会被执行(VimScript)
g:asyncrun_bell - 如果非零的话,任务结束后会响铃(终端输出控制符 \a)
g:asyncrun_mode - 0:异步(需要 vim 7.4.1829) 1:同步 2:直接运行

全局变量:

g:asyncrun_code   - 退出码
g:asyncrun_status - 状态 'running', 'success' or 'failure'

如果你喜欢的话请为我投一票:
http://www.vim.org/scripts/script.php?script_id=5431

Categories: 随笔 Tags:

3D 图形光栅化的透视校正问题

August 18th, 2016 No comments

写了文章《如何写一个软件渲染器》以后,不少网友希望进一步解释背后的数学公式,询问以及自己加一个 phong 光照该如何加,本文将对透视纹理映射的插值原理做一个简单的解释,希望能帮助到大家:

透视纹理绘制发生在最后阶段,坐标已经完成projection,剔除,裁剪了,然后顶点/w,开始批量绘制扫描线之前,这时候开始计算纹理的位置。

使用w还是用z,关系不大,早年的3d引擎,直接/z的,只是后面标准化了以后,发现w更好用,可以同时表示透视投影和正交投影。同时顶点经过标准的mvp矩阵运算后,w和z是承线性关系的,方便对z/w做 [0,1] 的cvv裁剪。你可以理解成w就是另外一个z。以前屏幕坐标:

x' = x / z * d + A
y' = y / z * d + A

现在是

x' = x / w * d + A
y' = y / w * d + A

然后绘制纹理前,你需要先证明屏幕上两个点之间,1/w 承线性关系,即屏幕上两个点X1′, X2’之间任意取一点X3’,他们的(1/w)值的变化比例相同,即在 t 取任意值有:

x3' = x1' + (x2' - x1') * t
(1 / w3) = (1 / w1) + ((1 / w2)  - (1 / w1)) * t

再根据他们在同一个平面上,证明屏幕上两个点之间,u/w, v/w 承线性关系,即 t 取任意值有:

x3' = x1' + (x2' - x1') * t
(u3 / w3) = (u1 / w1) + ((u2 / w2) - (u1 / w1)) * t
(v3 / w3) = (v1 / w1) + ((v2 / w2) - (v1 / w1)) * t

具体到代码里面的做法就是三角形的三个顶点/w以后,u和v也同时/w,然后把w换成自己的倒数:w = 1 / w,及把顶点数据:

(x, y, z, w) + (u, v)

变换成:

(x / w, y / w, z / w, 1 / w) + (u / w, v / w)

然后用 1/w, u/w, v/w进行屏幕空间插值,具体绘制某个点的时候,先从1/w求倒得到w,然后乘以 u/w, v/w得到 u, v,就可以了。

更进一步,可以证明,所有在三维空间里同x,y,z成线性关系的变量,不管是纹理坐标,顶点色或者法向还是其他,他们在屏幕空间里的插值规则都可以通过:插值前先/w,插值后要用时再 * w得到具体值,然后我们把这类三维空间里同x,y,z成线性关系的变量统进行统一的批量处理,和OpenGL的 attribute,varying处理方法相同。

相关阅读:
如何写一个软件渲染器
还原被摄像机透视的纹理

Categories: 图形编程 Tags: