在Render Monkey中使用CubeMap让我困扰了很长时间,请原谅我没有在DirectX的程序中学习好这个而直接跳到了这里。
这里我想说几个我当时使用CubeMap时几个疑问。我觉得用Q&A的方式来写比较好,就不用罗列不必要的东西了。
Q1:单位球不是半径为1吗?为什么茶壶半径差不多单位也为1,却始终显示在单位球体以内呢???
A1:这个是绘制单位球中关闭Z-buffer及禁止写入Z-buffer的功劳,我们把球心设置在了相机位置,这样不管我们怎样前后左右移动,球体始终是不变的,因为它随着相机的变动而变动。如果我们旋转的话,球体也会跟着旋转。关闭Z-buffer及禁止写入Z-buffer,我们绘制茶壶时,茶壶始终是绘制在单位球上的,这样就给我们一个错觉,单位球是无限远的,而茶壶的远近是可以移动的(非常聪明的一个方法)。
Q2:如果我们把绘制单位球Pass中的Render State中的D3DZB_ENABLE及D3DZB_WRITEENABLE分别设置为D3DZB_TRUE和TRUE会怎么样???
A2:如果我们把绘制单位球Pass中的Render State中的D3DZB_ENABLE及D3DZB_WRITEENABLE分别设置为D3DZB_TRUE和TRUE,就会出现我们以往碰见的现象了,如球体挡住茶壶,或者茶壶跑到球体后边去了,当然,这不是我们想要的,我们要的就是错觉!!(以下图是我们在渲染状态D3DZB_ENABLE及D3DZB_WRITEENABLE分别设置为D3DZB_TRUE和TRUE下的渲染结果)
注意这里的遮挡是非常严重的,因为茶壶跟单位球体的尺寸是差不多的,茶壶如果想要遮挡球体,必然遮住了屏幕的一大部分。
如果你的茶壶只有很小一部分被球体遮挡了,那个不是被单位球遮挡了,是被视棱锥裁剪了。如下图,请注意,这两种情况是不同的。
Q3:代码问题?
1 VS_OUTPUT vs_main( VS_INPUT Input ) 2 { 3 VS_OUTPUT Output; 4 5 Output.Position = mul( float4(Input.Position.xyz + vViewPosition.xyz,1.0f), matViewProjection ); 6 Output.Tex = Input.Position.xyz; 7 return( Output ); 8 }
A3:关键之处在于
Output.Position = mul( float4(Input.Position.xyz + vViewPosition.xyz,1.0f), matViewProjection );
加上vViewPosition的目的是把球体移动到视点位置,其实就是一个球体世界坐标变换。
Output.Tex = Input.Position.xyz;
就是把球体上每一个点的视点向量计算出来,视点位置为vViewPosition,经过变换后的球体上的点的坐标为Input.Position.xyz + vViewPosition.xyz,要计算视点为起点,重点在球体点的向量,直接用Input.Position.xyz + vViewPosition.xyz - vViewPosition = Input.Position.xyz,这就直接解释了第二行代码。
Q4:添加RenderTarget时,注意RenderTarget属性的设置,第一个球体Pass中必须要清理颜色和深度,第二个绘制茶壶的Pass中则不需要清除颜色及深度。好好理一下这是为什么??
A4:其实跟在back buffer绘制是一个道理,只不过back buffer的颜色及深度清除使系统自己做的,而RenderTarget的颜色及深度清除要我们在第一个Pass中设置。
//end