[DirectX12学习笔记] 几何着色器

  • 注意!本文是在下几年前入门期间所写(young and naive),其中许多表述可能不正确,为防止误导,请各位读者仔细鉴别。

用几何着色器实现Billboard


几何着色器简介

几何着色器的一般形式如下

[maxvertexcount(N)]
void ShaderName (
PrimitiveType InputVertexType InputName [NumElements],
inout StreamOutputObject<OutputVertexType> OutputName)
{
   
// Geometry shader body…
}

第一排方括号内的是最大输出的顶点数量,第一个参数是顶点着色器输出,也就是几何着色器的输入,输入类型有以下五种:
在这里插入图片描述
第二个参数要用inout标注,输出的是一个StreamOutputObject,这是一个模板类,取值有以下几种
在这里插入图片描述
可以用StreamOutputObject<OutputVertexType>::Append(OutputVertexType v);方法来输出顶点,输出的一定是strip,如果希望输出list,可以用StreamOutputObject<OutputVertexType>::RestartStrip();来让strip重新开始。

Texture Array

有的时候可以吧几张图片放在同一张纹理上,形成一个纹理数组,hlsl中输入参数长这样

Texture2DArray gTreeMapArray;

当然也可以用以下方法代替:

Texture2D TexArray[4];
…
float4 PS(GeoOut pin) : SV_Target
{
   
float4 c = TexArray[pin.PrimID%4].Sample(samLinear,pin.Tex);

新的DX12支持后面这种,但是旧的版本不一定对这种方法支持的很好,所以有的时候我们需要用Texture Array来达到同样效果。

在Texture Array上采样可以通过下面这种方法

float3 uvw = float3(pin.Tex, pin.PrimID%4);
float4 diffuseAlbedo = gTreeMapArray.Sample(gsamAnisotropicWrap, uvw) * gDiffuseAlbedo;

uvw的前两维就是uv,第三维w是数组下标,从0开始。

然后primitiveID可以在几何着色器的输入种通过SV_PrimitiveID获得,如下:

[maxvertexcount(4)]
void GS(point VertexOut gin[1], 
        uint primID : SV_PrimitiveID, 
        inout TriangleStream<GeoOut> triStream)
{
   	
···
gout.PrimID = primID;
···
}

如果有几何着色器的话,primitive id只能在几何着色器的输入签名中出现,如果没有几何着色器的话,则可以在像素着色器的输入参数中获取:

float4 PS(VertexOut pin, uint primID : SV_PrimitiveID) : SV_Target
{
   
	// Pixel shader body...
}

载入Texture Array的时候,绑定srv的操作不一样,应该注意,以下会给出代码。

接下来还有几个概念可以了解一下
在这里插入图片描述
横着的是texture数组,一竖条称为一个array slice,竖着的是mipmap列,一横条称作一个mip slice,其中一张图叫做一个subresource,subresource的默认标号方法如下
在这里插入图片描述

要获取一个subresource的标号的话,可以用如下方法

inline UINT D3D12CalcSubresource( UINT MipSlice, UINTArraySlice, UINT PlaneSlice, UINT MipLevels, UINT ArraySize )
{
   
	return MipSlice + ArraySlice * MipLevels + PlaneSlice * MipLevels * ArraySize;
}

Alpha-To-Coverage

之前在blend一章也提到过这是个对叶子、头发等渲染非常有用的一个设置,首先这个问题来源于,计算msaa的时候,以4x msaa为例,着色器只会在采样中心运行一次,然后在4个小方块里检查coverage,然后把颜色取平均,但是问题来了,这个检查coverage的时候是只看多边形有没有cover这个小方块,是不考虑alpha通道的,所以这样的话效果会不好,因此,我们希望把alpha低的地方在取平均的时候加权更小,比如有一个方块虽然被多边形cover了但他的alpha只有0.5,那么颜色取平均的时候这个方块的颜色还要再乘个0.5,这样的话,出来的效果就是alpha越低的地方颜色越淡,过渡也就会均匀很多,按理说我们希望所有有透明度的地方都打开alpha-to-coverage检测,这个设置在D3D12_BLEND_DESC::AlphaToCoverageEnable = true,叶子、头发之类的都可以用这个加强效果,开销主要来源于msaa,ff的头发就是用了这种。

Tree Billboards Demo

接下来实现一个非常简单的billboard demo,即用一系列点经过几何着色器变成一个面片(两个三角面),然后在这个三角面上渲染树的图案,同时,树的y轴永远朝上,xz轴永远朝向摄像机。

整个demo基于之前的blend demo,下面只给出修改了的关键部分代码

首先创建srv的时候,树的贴图是个Texture Array,创建的时候ViewDimension是D3D12_SRV_DIMENSION_TEXTURE2DARRAY,此外还有些别的设置不同,可以注意一下。


void TreeBillboardsApp::BuildDescriptorHeaps()
{
   
	//
	// Create the SRV heap.
	//
	D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {
   };
	srvHeapDesc.NumDescriptors = 4;
	srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));

	//
	// Fill out the heap with actual descriptors.
	//
	CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());

	auto grassTex = mTextures["grassTex"]->Resource;
	auto waterTex = mTextures["waterTex"]->Resource;
	auto fenceTex = mTextures["fenceTex"]->Resource;
	auto treeArrayTex = mTextures["treeArrayTex"]->Resource;

	D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {
   };
	srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
	srvDesc.Format = grassTex->GetDesc().Format;
	srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MostDetailedMip = 0;
	srvDesc.Texture2D.MipLevels = -1;
	md3dDevice->CreateShaderResourceView(grassTex.Get
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值