存档

‘Tips & Tricks’ 分类的存档

Macbook Air外接显示器开启ClearType

2010年12月21日 Huang Donghai 没有评论

发现Macbook Air外接显示器的时候,默认是没有开启ClearType的,字体发虚的很厉害。

解决方法是在终端底下输入:

defaults -currentHost write -globalDomain AppleFontSmoothing -int 2

就是强行把抗锯齿打开。

分类: Tips & Tricks 标签: ,

iPhone/iPod有时不能显示歌词的解决方法

2010年11月14日 Huang Donghai 没有评论

有时候明明mp3里嵌入了歌词的tag,但是iPhone/iPod里还是不能显示。经试验,发现是V2.4的ID3 Tag偶尔会有这种Bug。在iTunes里,选择相应的mp3文件,右键点击,选择Convert ID3 Tags,转成V2.3版的ID3 Tag,问题解决。

分类: Tips & Tricks 标签: ,

Ubuntu 9.10下Firefox字体发虚的问题

2010年4月27日 Huang Donghai 1 条评论

Ubuntu 9.10 下如果你出现了 Firefox 字体始终发虚(启动了ClearType),并且在“外观”里修改而 Firefox 始终发虚(其他程序正常),如这个案例:

    Ubuntu中文论坛 • 查看主题 – ubuntu 9.10下firefox 3.5 的字体平滑方式如何解决?

那么你可以这样做:

sudo rm /etc/fonts/conf.d/10*
sudo dpkg-reconfigure fontconfig

重启 Firefox 就好了。

分类: Tips & Tricks 标签: , ,

由 Z buffer 得到 View Space Z

2010年4月23日 Huang Donghai 没有评论

现在几乎没有不用某种程度的延迟模式渲染,我们经常需要在 GBuffer 里保存 Z 信息,然后可以反算出视点坐标系或者世界坐标系的坐标。如果你直接保存 ViewSpace 的 Z,那没有这篇所说的问题。但是保存 ViewSpace Z,需要 DepthBuffer 之外的地方来保存。有的引擎直接用 Hardware ZBuffer,OpenGL 上这个并不难实现,D3D 上需要些 Tricks,要用 vendor 提供的特殊的 FOURCC 格式,比如 nVidia 的 RAWZ、INTZ,ATi 的 DF16、DF24,好像最新的 ATi 显卡也支持 INTZ 了。

由 ZBuffer Z 得到 ViewSpace Z 是件很简单的事情,我们先看 Direct3D 和 OpenGL 上的变换矩阵:

OpenGL:

\mathrm{P}_{OpenGL}=\left(\begin{array}{cccc} {\displaystyle \frac{2n}{r-l}} & 0 & {\displaystyle \frac{r+l}{r-l}} & 0\\ 0 & {\displaystyle \frac{2n}{t-b}} & {\displaystyle \frac{t+b}{t-b}} & 0\\ 0 & 0 & {\displaystyle -\frac{f+n}{f-n}} & {\displaystyle -\frac{2fn}{f-n}}\\ 0 & 0 & -1 & 0\end{array}\right)

z\in\left[-1,1\right]

D3D:

\mathrm{P}_{D3D}=\left(\begin{array}{cccc} {\displaystyle \frac{2n}{r-l}} & 0 & {\displaystyle \frac{r+l}{r-l}} & 0\\ 0 & {\displaystyle \frac{2n}{t-b}} & {\displaystyle \frac{t+b}{t-b}} & 0\\ 0 & 0 & {\displaystyle \frac{f}{f-n}} & {\displaystyle -\frac{fn}{f-n}}\\ 0 & 0 & 1 & 0\end{array}\right)

z\in\left[0,1\right]

OpenGL 的投影变换矩阵变换后,z 的值在 [-1, 1] 范围,而 D3D 的值在 [0, 1] 范围。新手混淆不清的是,OpenGL 的 z 实际上是在 [1, -1],因为他的右手坐标系,z 是指向你的眼睛的,所以,远的地方 z 值反而较小,以至于为负。

但是当你写到硬件 ZBuffer 以后,读出来的时候,无论是 OpenGL 还是 D3D,无论是那个格式(RAWZ, INTZ, DF16, DF24, GL_DEPTH_COMPONENTxx),都是 [0, 1] 范围,0 是最近点,既是 near plane 的 z,1 是最远点,far plane 的 z。这也是经常让人混淆的东西。因为这个原因,我们可以值用 D3D 的公式来算。

有了这些信息,我们不难推导出求 ViewSpace Z 的公式。

因为:

\left(\begin{array}{cccc} {\displaystyle \frac{2n}{r-l}} & 0 & {\displaystyle \frac{r+l}{r-l}} & 0\\ 0 & {\displaystyle \frac{2n}{t-b}} & {\displaystyle \frac{t+b}{t-b}} & 0\\ 0 & 0 & {\displaystyle \frac{f}{f-n}} & {\displaystyle -\frac{fn}{f-n}}\\ 0 & 0 & 1 & 0\end{array}\right)\left(\begin{array}{c} x_{v}\\ y_{v}\\ z_{v}\\ w_{v}\end{array}\right)=\left(\begin{array}{c} x_{c}\\ y_{c}\\ z_{c}\\ w_{c}\end{array}\right)

我们只关心 Z 的值:

\begin{cases} \begin{array}{l} {\displaystyle \frac{f}{f-n}}z_{v}-{\displaystyle \frac{fn}{f-n}=z_{c}}\\ \\w_{c}=z_{v}\end{array}\end{cases}

根据上两式我们得到:

\begin{array}{rcl} z_{buf} & = & {\displaystyle \frac{z_{c}}{z_{v}}}\\ & = & \frac{{\displaystyle \frac{f}{f-n}}z_{v}-{\displaystyle \frac{fn}{f-n}}}{{\displaystyle z_{v}}}\\ & = & {\displaystyle \frac{f}{f-n}}-{\displaystyle \frac{fn}{z_{v}\left(f-n\right)}}\end{array}

移动一下位置:

{\displaystyle \frac{fn}{z_{v}\left(f-n\right)}}={\displaystyle \frac{f}{f-n}}-z_{buf}

两边乘以\left(f-n\right)

{\displaystyle \frac{fn}{z_{v}}}=f-z_{buf}\left(f-n\right)

最终得到:

\mathrm{z}_{view}=\frac{fn}{f-\mathrm{z}_{buf}(f-n)}

神奇的是,这个公式反而不分 OpenGL 和 D3D 了。这是因为,虽然 OpenGL 和 D3D 的透视变换矩阵虽然不同,定义的 clip space 的 z 也不同,但是,实际上写入物理 zbuf 的值,却是完全一样的,所以一个公式可以搞定。

具体实现上,可以传入 f*n, f, f-n 三个值,以减少 shader 的计算,如果这样的话,HLSL 代码大概是这样的:

// zparam, for recover view space z, Zview = 2*f*n/((f+n)-Zbuf(f-n)), where Zbuf is [-1,1]
// if Zbuf is [0,1], acultly we use, the equation should be
//
//              f * n
// Zview = -------------------
//           f - Zbuf(f-n)
// faster than use matrix multiply, but only for perspective projection
 
struct ZrecoverParam {
    float near, far, farXnear, farSUBnear;
};
 
const ZrecoverParam g_zrecoverParam;
 
// return n~f
float ZR_getViewSpace(float zbuf) {
    return g_zrecoverParam.farXnear / (g_zrecoverParam.far - zbuf * g_zrecoverParam.farXnear);
}
// return 0~1 view space
float ZR_getViewSpaceNormalized(float zbuf) {
    return 1.0 / (zbuf * g_zrecoverParam.far + g_zrecoverParam.farXnear);
}

nullptr

2010年4月22日 Huang Donghai 没有评论

nullptr 将会是 C++1X 标准支持的功能之一(VC2008 有实现这个)。目前 C++ 里 NULL 直接宏定义为 0,这个很不对,首先 0 是个整数字面量,没有指针的含义,另外用宏也对命名空间造成污染,并且会让人造成误解,以为跟 C 语言一样,NULL 是个指针,结果传入模板时推导就会错误,所以有的开发人员和小组直接用 0(比如 Qt),而不用 NULL。

nullptr 可以解决这个问题,可惜的是 C++1X 遥遥无期。幸运的是,我们可以在 C++98 上近乎完美的模拟出这个功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const class nullptr_t  // const 对象...
{
public:
	template<class T>
	operator T*() const // 转换成任何非成员指针...
	{ return 0; }
 
	template<class C, class T>
	operator T C::*() const   // 或者任何成员指针...
	{ return 0; }
 
private:
	void operator&() const;  // 禁止拿地址
} nullptr = {};
分类: Tips & Tricks 标签:

Switch to our mobile site