Picking
要点
- 将pick的射线变换到物体的局部坐标系,从而不需要将物体的所有顶点变换到世界坐标系
- 先和Bounding Box碰撞,再碰撞三角形
Cube Mapping
要点
- 语法:
- HLSL: TextureCube
- SRV: ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE
TextureCube.MostDetailedMap = 0
TextureCube.MipLevels = -1
- Sample:使用从cube的中心出发的射线与cube的交点位置的Sample
- 可以作为物体表面上对环境的反射用,直接用反射光角度来Sample即可;但是对于平面物体会露馅
- 过去经常用渲染天空盒来代替清空render target,其实 应该最后再渲染天空盒,否则:
- 深度模板缓存需要被明确的清空,才能好好利用深度优化
- 天空通常会被各种覆盖,所以渲染它是不必要的
- 使用已有场景来生成立方体贴图
- 方法1:使用6个单Texture的RT,6个DSV,6个Camera,来拍摄6次
- ViewDimension:D3D11_RTV_DIMENSION_TEXTURE2DARRAY
- ArraySize = 1
- 方法2:使用texture array size为6的RT和DSV,使用GS(参见DubeMapGS这个demo)
- D3D10_RENDER_TARGET_VIEW_DESC.Texture2DArray.ArraySize = 6
- D3D10_DEPTH_STENCIL_VIEW_DESC.Texture2DArray.ArraySize = 6
- .ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2DARRAY
- SV_RenderTargetArrayIndex: 将要渲染的某个三角形,指定渲染给该RT
- 坏处:这里GS会输出大量数据从而低效(也就3个点X6个面=18,算是大量么,没看懂);一个三角形实际上应该只会渲染到一个面上,但是这里每个都渲染了6次,因为视椎剔除没法在GS做
- 方法1:使用6个单Texture的RT,6个DSV,6个Camera,来拍摄6次
- Desc.MiscFlags: D3D11_RESOURCE_MISC_GENERATE_MIPS:有了这个Flag可以调用context->GenerageMips,然后只生成最高级的那个level的mipmap,因为低级的几个不需要
Normal Mapping
要点
- 通过Lighting来制造凹凸感
- 切线空间
- (其实之前我还想当然的以为模型的法线贴图不就是在模型坐标系下对比下高模和低模的法线的差异就可以了么!刚刚才意识到万一模型比如拉伸一下,法线不就不垂直了么【扶额。人物动作更别想了【扶额。)
- 切线空间是在单个三角形面片内的空间,y方向平面外。并不是随随便便以某两条边当xz轴,而是根据模型贴图bia上去时的uv,来决定xz——或曰T(angent)B(itangent),再加上一个N(ormal),就是TBN空间了。
- 不过事实上这个数据存在顶点。和法线一个道理,是所在面片的平均。而且B可以不存因为可以算。
Displacement Mapping
要点
- 使用高度贴图+Tessellation来制造凹凸感
- 传入shader的数据:最大和最小Tess的factor和distance。然后插值之。
- 决定细分factor虽然是在vertex里边,但是边上的factor——为了保持两个三角形面在边缘处是连续的——需要对其进行平均,使用两个顶点算出的factor的平均值即可。
- 注意在domain shader里边,普通的 Texture2D::Sample 不能用,只能用 Texture2D::SampleLevel
Terrain Rendering
要点
- 高度贴图:
- 对于8bit的高度贴图(256个值),有时候可以对它做下平滑处理
- 使用高度贴图来执行displacement mapping:能tess的最细的程度,要考虑高度贴图的分辨率
- 在VS中,通过高度图,来调整位置,从而使Tess的细分程度计算的更准确
- 在constant hull shader中,通过面或者边的中点来计算与人眼的距离,可以使用pow来插值,据说效果更好。
- 可以使用相邻像素的差值作为导数来计算法线等
- 提前计算视椎裁剪,可以提高效率。Terrain因为是axis-aligned所以特别好算AABB。
- 可以提前计算并将这个值放入Vertex的数据中,然后在 hull shader 里边测试后裁剪掉
- 多地形的情况下的贴图:
- 使用多个地形贴图,用来进行tile mapping。
- 对每一个地形贴图,增加一个alpha贴图,表示与前一融合结果的融合。这个是不tile的。恩其实是n-1个。
- (好厉害的想法啊 0 0 地形的变化时不需要高分辨率的,但是地形本身的细节是需要高分辨率的,所以用两个贴图来融合)
- 获取任意点的地形高度:三角形、线性插值。
Particle
要点
- 常用坐标:billboard
- 随机:使用随机纹理、时间种子。
- 活用Blend的叠加模式
- 可以使用Stream-out来创建销毁更新粒子,其结果重新进入管线进行渲染(不同的shader)
- 然后在渲染时将其进行扩展为billboard
Stream-out stage(SO)
要点
- (DX10新增)
- 可以把GPU的定点计算结果输出到vertex buffer中。
- 使用GS来增删顶点
步骤:
- HLSL:
- 如果想要只SO,不渲染,那么把pixel shader和depth/stencil buffer进行disable,便不会进行光栅化:
- SetPixelShader(NULL);
- SetDepthStencilState(DisableDepth, 0);
- DiableDepth{DepthEnable=FALSE; DepthWriteMask = ZERO;}
- IA:
- D3D11_BUFFER_DESC
- BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUT
前者是因为它出来之后还是要再进入下一个IA来渲染的;后者是为了能让SO写入它。 - device->CreateBuffer(&vbd, 0, &out)
初始化为空的,因为GPU稍后就会填充
- BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUT
- contex->SOSetTargets
- numbers: 数量,最大是4
- VB的列表
- VB的offset
- D3D11_BUFFER_DESC
- 输出后,要先取消绑定才能再绑定到IA进行渲染:
- context->SOSetTaragets(1, some_empty_array, &offset)
- SO出来的VB,因为其信息不需要知道,所以可以用黑科技来draw:
- context->DrawAuto(),只能用于 D3D11_BIND_STREAM_OUT
- 还是需要指定layer的
- 可以使用两个VB,不停的互换:一个被绑定,另一个自动就解除。