Directx11教程二十四之Billboarding(广告板)

这节教程的结构如下:



一,什么是广告板(Billboarding)?

首先在介绍 广告板(Billboarding)前说一下这种情况,假设在一个3D游戏中有一大片森林,每个树都是一个3D模型,一棵树的面数也许不大,但是你想想一座森林有几千甚至几万棵树,加起来的面数如此之多以至于能让你的显卡爆炸。这时候,广告板的技术诞生了,我们可以将做出一张四方形的纹理贴图,上面有一颗树,假设那张树的纹理贴图离相机比较远,在游戏中远远的看去,你无法分辨到底那棵树到底是3D模型还是一张树纹理,但是你一走近的话,也许会暴露这个缺点,这时假设树或者树纹理贴图与Y轴平行,树纹理贴图的中心点跟相机在XZ平面垂直,可以大大降低被玩家发现是假3D的几率


如图:



如图,假设树的纹理贴图的中心点在XZ面的投影为 (Xc,0,Zc),    相机的位置在XZ面的投影点为 (Xe,0,Ze),

那么向量W=(Xc-Xe,Zc-Ze)垂直于向量u(向量u为四方形的树的纹理图在XZ面投影的线段)

下面上我画的图:

刚开始时位置是这样的:






后面相机向X轴正方向平移是这样的:


Θ=arctan(AE/AC);


bool GraphicsClass::Render()
{
	//三个变换矩阵
	XMMATRIX WorldMatrix, ViewMatrix, ProjMatrix;
	XMFLOAT3 CameraPostion, BillBoardModelPostion;
	double angle; //广告板旋转角度(围绕Y轴)
	float rotation; //旋转量


	bool result;

	//第一,清除缓存开始绘制场景
	mD3D->BeginScene(0.3f, 0.4f, 0.0f, 1.0f);

    //第二,生成ViewMatrix(根据CameraClass的mPostion和mRotation来生成的)
	mCamera->Render();

	//第三,获取三个变换矩阵(WorldMatrix和ProjMatrix来自mD3D类,ViewMatrix来自CameraClass)

	WorldMatrix = mD3D->GetWorldMatrix();

	ProjMatrix = mD3D->GetProjMatrix();

	ViewMatrix = mCamera->GetViewMatrix();


	//第四,把地面的顶点数据和索引数据放入3D渲染流水线
	mFloorModel->Render(mD3D->GetDeviceContext());

	//第五,用ColorShader对底面进绘制
	result = mColorShader->Render(mD3D->GetDeviceContext(),mFloorModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix,mFloorModel->GetTexture(),mLight->GetDiffuseColor(),mLight->GetLightDirection());
	if (!result)
	{
		MessageBox(NULL, L"mFloorModel Render failure", NULL, MB_OK);
		return false;
	}

	//第六,获取相机的位置
	XMStoreFloat3(&CameraPostion, mCamera->GetPostion());

	//第七,设置广告板的位置
	BillBoardModelPostion = XMFLOAT3(0.0f, 1.5f, 0.0f);

	//第八,计算广告板旋转角度,由于广告板围绕Y轴旋转,则广告板旋转时其上面的顶点Y坐标不变,X和Z坐标改变 用ant2计算
	angle = atan2(BillBoardModelPostion.x - CameraPostion.x, BillBoardModelPostion.z - CameraPostion.z);

	 //将角度转换为弧度,乘以2*PI/360 XMMatrixRotationY的参数为角度而不是弧度
	//rotation = (float)(angle* 0.0174532925f);

	//第九,求出旋转矩阵和移动矩阵,并求出最终的世界矩阵,负角度代表逆时针旋转,正角度代表顺时针旋转
	WorldMatrix = WorldMatrix*XMMatrixRotationY(angle)*XMMatrixTranslation(BillBoardModelPostion.x, BillBoardModelPostion.y, BillBoardModelPostion.z);

	//第十,把广告板模型的顶点数据和索引数据放入3D渲染流水线
	mBillBoardingModel->Render(mD3D->GetDeviceContext());

	//第十一,用ColorShader进行渲染
	result = mColorShader->Render(mD3D->GetDeviceContext(), mBillBoardingModel->GetIndexCount(), WorldMatrix, ViewMatrix, ProjMatrix, mBillBoardingModel->GetTexture(), mLight->GetDiffuseColor(), mLight->GetLightDirection());
	if (!result)
	{
		MessageBox(NULL, L"mBillBoardingModel Render failure", NULL, MB_OK);
		return false;
	}

	//把渲染的场景呈献给屏幕
	mD3D->EndScene();
	return true;
}



还有一点注意的是XNAMATH库的XMMatrixRotationY的参数是弧度。
D3DXMATRIXRotationY的参数也为弧度


程序运行图

(1)当相机在X轴中间位置时





(2)当相机往X轴负方向运动时,





(3)当相机往X轴右边运动时





这里我在PixelShader里用 clip 函数剔除了树纹理中黑色的像素

Shader代码:

Texture2D ShaderTexture:register(t0);  //纹理资源
SamplerState SampleType:register(s0);   //采样方式

//VertexShader
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
	matrix WorldInvTranspose;
};

cbuffer CBLight:register(b1)
{
	float4 DiffuseColor;
	float3 LightDirection;
	float pad;
}

struct VertexIn
{
	float3 Pos:POSITION;
	float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
	float3 Normal:NORMAL;
};


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float2 Tex:TEXCOORD0;
	float3 W_Normal:NORMAL;  //世界空间的法线

};


VertexOut VS(VertexIn ina)
{
	VertexOut outa;
	outa.Pos = mul(float4(ina.Pos,1.0f), World);
	outa.Pos = mul(outa.Pos, View);
	outa.Pos = mul(outa.Pos, Proj);
	outa.W_Normal = mul(ina.Normal, (float3x3)WorldInvTranspose);  //此事世界逆转置矩阵的第四行本来就没啥用
	outa.W_Normal = normalize(outa.W_Normal);
	outa.Tex= ina.Tex;
	return outa;
}


float4 PS(VertexOut outa) : SV_Target
{
	float4 TexColor; //采集的纹理颜色
    float LightFactor; //灯光因子
	float4 color = {0.0f,0.0f,0.0f,0.0f}; //最终输出的颜色


	//第一,获取采样颜色
    TexColor = ShaderTexture.Sample(SampleType, outa.Tex);
	color = TexColor;
	clip(color.a - 0.1);  //剔除接近于黑色的像素

	//第二,求出灯光因子
	float3 InvLightDir = -LightDirection;
	 LightFactor = saturate(dot(InvLightDir,outa.W_Normal));
	 
	//第三,求出灯光照射颜色
	 if (LightFactor>0)
	 {
		 color += LightFactor*DiffuseColor;  //saturate(float1*float4)
	 }
	 
	 color = saturate(color);
		
	//第四,用灯光颜色调节纹理颜色
	color = color*TexColor;

	return color;
}





这里明显看到随着观察角度不同,树始终面向我们的视角,树的纹理图就像真的3D树模型一样欺骗了我们的眼镜,当然在游戏中一片森林还是提倡几十棵3D模型棵树和几千棵假树一起配合效果会更好。


下面我的源代码链接如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值