HLSL效果框架-多光源效果

原文:HLSL效果框架-多光源效果


昨日不可追,?今日尤可为.勤奋,炽诚,不忘初心

手机淘宝二维码?扫描??????

或者打开连接:程序设计开发?,掌声鼓励,欢迎光临.


?

?

高级着色器语言(HLSL)难就难在它是运行在GPU,CPU上的,编写和调试都很麻烦.

用效果框架简化了很多操作,先列出着色器的代码,重点部分都用中文注释了

着色器语言文件为:,代码为:

//着色器处理未知数量光源数目 未知光源种类 的 混合效果
//HLSL里一共支持256个float4,一个int最后也转成float4,float4x3和float3x3占内存一样,最终都变成float4
//因为HLSL的限制条件非常零散也非常多,所以,用起来还是很吃力的,在不懂的情况下,
//最终指令不能超过500多条貌似,运行在显卡中程序,所以能省则省,能精简则精简!!!

//
//结构体 注意:为了优化结构,把一些相关参数整合到了一起
//
struct PointLight	//点光源 结构
{
	float4 Diffuse;		//漫反射的颜色r,g,b,a
	float4 Specular;	//镜面高光的颜色r,g,b,a
	float4 Position;	//光源位置x,y,z,w没用到
	float4 RangeAttenuation;//范围,恒定衰减,光强,二次衰减
};

struct DirectLight	//方向光 结构
{
	float4 Diffuse;		//漫反射的颜色r,g,b,a
	float4 Specular;	//镜面高光的颜色r,g,b,a
	float4 Direction;	//方向x,y,z,高光
};

struct SpotLight	//聚光灯 结构
{
	float4 Diffuse;		//漫反射的颜色r,g,b,a
	float4 Specular;	//镜面高光的颜色r,g,b,a
	float4 Position;	//光源位置x,y,z,w没用到
	float4 Direction;	//方向x,y,z,w没用到
	float4 RangeAttenuation;//范围,恒定衰减,光强,二次衰减
	float4 FalloffThetaPhi;	//从内锥到外锥之间的强度衰减,y没用到,内锥的弧度,外锥的弧度
};

//接收光源的数量
int g_NumPLs;	//程序里定义了几个点光源?
int g_NumDLs;	//程序里定义了几个方向光源?
int g_NumSLs;	//程序里定义了几个方向光源?

PointLight		g_PLs[10];	//定义最多支持10个点光源
DirectLight		g_DLs[10];	//定义最多支持10个方向光源
SpotLight		g_SLs[10];	//定义最多支持10个聚光灯光源

//环境光(对于多灯光的场合,对每一个灯光循环进行这些运算(环境光除外))
//最后加上环境光(假设只有一个环境光)

matrix g_WorldMatrix;//世界矩阵
float4 g_ViewPos;//观察点(相机)
matrix WVPMatrix;	//世界-观察-投影矩阵

float AmbAmount;	//环境光的强弱程度,介于0-1之间
float4 AmbCol = { 1.0f, 1.0f, 1.0f, 1.0f };//环境光的颜色,默认白色

//--------------------------------------------------------------------------
//				顶点着色器(注意看下面,我把顶点着色器的输出顶点位置和法线,当作像素着色器的输入了!!!
//							TEXCOORD这类寄存器也没啥用,用来保存顶点和法线数据最合适不过了,最多好像是15个)
//--------------------------------------------------------------------------
struct VS_INPUT		//输入结构
{
	float4 position : POSITION;//输入:坐标
	float3 normal : NORMAL;	//输入:法线
};
struct VS_OUTPUT	//输出结构
{
	float4 position : POSITION;
	float4 vtpos : TEXCOORD0;//传入像素着色器用,TEXCOORD表示寄存器名字,(实际上保存的数据当像素着色器的输入坐标用,用TEXCOORD,一方面是多,二方面没啥用)
	float3 normal : TEXCOORD1;
};

VS_OUTPUT VS_Main(VS_INPUT input)
{
	VS_OUTPUT output = (VS_OUTPUT)0;
	output.vtpos = input.position;//模型本地空间坐标
	output.position = mul(input.position, WVPMatrix);//输出:世界-观察-投影变幻后的坐标
	output.normal = input.normal;
	return output;
}

//--------------------------------------------------------------------------
//				像素着色器(COLOR0是必须输出的,其他的可作任何用途)
//--------------------------------------------------------------------------
struct PS_INPUT		//输入
{
	float4 vtpos : TEXCOORD0;//顶点位置(接受顶点着色器的输出,要对应)
	float3 normal : TEXCOORD1;
};
struct PS_OUTPUT	//输出像素颜色
{
	float4 Color : COLOR0;	//像素着色器最终输出计算好的颜色
};
PS_OUTPUT PS_Main(PS_INPUT input)
{
	PS_OUTPUT output = (PS_OUTPUT)0;

	float4 worldpos = mul(input.vtpos, g_WorldMatrix);//顶点在世界空间中的坐标,即乘以世界矩阵
	float4 colRes;//用于保存最终的颜色 = E环境光+自身光+E(点光+方向光+聚光); 其中点,方向,聚光 又包含漫反射,镜面反射
	float4 ambient = { 0.0f, 0.0f, 0.0f, 1.0f };//总环境光
	float4 self = { 0.0f, 0.0f, 0.0f, 1.0f };//自发光
	float4 diffuse = { 0.0f, 0.0f, 0.0f, 1.0f };//总漫反射光
	float4 specular = { 0.0f, 0.0f, 0.0f, 1.0f };//总镜面反射

	ambient = AmbCol * AmbAmount;//求出环境光

	for (int i = 0; i < g_NumPLs; i++)//点光源
	{
		float3 dirSize = input.vtpos.xyz - g_PLs[i].Position.xyz;//光源到顶点的方向和大小.光源→顶点pos
		float distance = length(dirSize);//距离
		float3 dir = normalize(dirSize);//单位化方向
		if (distance < g_PLs[i].RangeAttenuation.x)//顶点在灯光范围内
		{
			//求出漫反射
			float difusefactor = dot(dir.xyz, input.normal.xyz);
			if (difusefactor < 0)
			{
				difusefactor = 0;
			}
			float distanceDec = 1.0f - 1.0f / g_PLs[i].RangeAttenuation.x * distance;
			//漫反射 = diffuse*漫反射因子*距离衰减
			diffuse.xyz += g_PLs[i].Diffuse.xyz * difusefactor * distanceDec;//最后要乘以材质的吸收系数(这里没乘)

			//下面求镜面反射(镜面反射的算法自己去百度找吧...)
			float3 DirectionToView = normalize(worldpos.xyz - g_ViewPos.xyz);  //(同在世界空间中!)
			float3 VectorToLight = normalize(input.vtpos.xyz - g_PLs[i].Position.xyz);
				//计算反射光
			float3 reflectanceRay = 2 * dot(input.normal.xyz, VectorToLight.xyz)*input.normal.xyz - VectorToLight.xyz;
			float specfactor = pow(abs(dot(reflectanceRay, DirectionToView)), g_PLs[i].RangeAttenuation.z);
				//镜面光累加
			specular.xyz += g_PLs[i].Specular.xyz * specfactor;//最后要乘以材质的吸收系数(这里没乘)
		}
		//else在光线外,无此光照影响
	}
	for (int j = 0; j < g_NumDLs; j++)//方向光源
	{
		//漫反射
		float3 dir = normalize(g_DLs[j].Direction.xyz);//单位化方向(光的方向)
		float difusefactor = dot(dir.xyz, input.normal.xyz);
		if (difusefactor < 0)
		{
			difusefactor = 0;
		}
		diffuse.xyz += g_DLs[j].Diffuse.xyz * difusefactor;//最后要乘以材质的吸收系数(这里没乘)

		//镜面反射
		float3 DirectionToView = normalize(worldpos.xyz - g_ViewPos.xyz);//观察点→顶点  (同在世界空间中!)
		//dir 已有
			//计算反射光
		float3 reflectanceRay = 2 * dot(input.normal.xyz, dir.xyz)*input.normal.xyz - dir.xyz;
		float specfactor = pow(abs(dot(reflectanceRay, DirectionToView)), g_DLs[j].Direction.w);
			//镜面光累加
		specular.xyz += g_DLs[j].Specular.xyz * specfactor;//最后要乘以材质的吸收系数(这里没乘)
	}

	for (int k = 0; k < g_NumSLs; k++)//聚光灯
	{
		float disdec = 0.0f;//距离衰减
		float raddec = 0.0f;//角度衰减

		float distance = length(g_SLs[k].Position.xyz - worldpos.xyz);//光源到顶点的距离
		float3 xconeDirection = normalize(g_SLs[k].Direction.xyz);//聚光灯方向
		float3 ltvdir = normalize(g_SLs[k].Position.xyz - worldpos.xyz);//光到顶点的方向
		float cosx = abs(dot(xconeDirection, ltvdir));//夹角的余弦值

		float cosPhi = cos(g_SLs[k].FalloffThetaPhi.w / 2.0f);
		float cosTheta = cos(g_SLs[k].FalloffThetaPhi.z / 2.0f);

		//距离衰减因子
		float sss = 1.0f / g_SLs[k].RangeAttenuation.x;

		if (cosx>cosTheta)//本影(角度衰减: 不衰减)
		{
			raddec = 1.0f;

			if (distance*cosx <g_SLs[k].RangeAttenuation.x)//在射程范围内
			{
				disdec = 1.0f - 1.0f / g_SLs[k].RangeAttenuation.x*distance*cosx;//距离衰减(线性衰减)
			}
		}

		if (cosx < cosTheta)//本影外(角度衰减: 急剧衰减 )
		{
			float v1 = cosx - cosPhi;
			float v2 = cosTheta - cosPhi;
			float v3 = v1 / v2;
			raddec = pow(abs(v3), g_SLs[k].FalloffThetaPhi.x);

			if (distance*cosx <g_SLs[k].RangeAttenuation.x)//在射程范围内(无光)
			{
				disdec = 1.0f - 1.0f / g_SLs[k].RangeAttenuation.x*distance*cosx; //距离衰减(线性衰减)
			}
		}

		if (cosx<cosPhi)//光锥外
		{
			raddec = 0.0f;
		}

		//计算漫反射
		float difusefactor = dot(ltvdir.xyz, input.normal.xyz);
		if (difusefactor < 0.0f)
		{
			difusefactor = 0.0f;
		}
		diffuse.xyz += g_SLs[k].Diffuse.xyz * raddec * disdec * difusefactor;//最后要乘以材质的吸收系数(这里没乘)

		//计算镜面反射
		float3 DirectionToView = normalize(worldpos.xyz - g_ViewPos.xyz);//观察点→顶点  (同在世界空间中!)
		float3 VectorToLight = normalize(input.vtpos.xyz - g_SLs[k].Position.xyz);
			//计算反射光
		float3 reflectanceRay = 2 * dot(input.normal.xyz, VectorToLight.xyz)*input.normal.xyz - VectorToLight.xyz;
		float specfactor = pow(abs(dot(reflectanceRay, DirectionToView)), g_SLs[k].RangeAttenuation.z);
			//镜面光累加
		specular.xyz += g_SLs[k].Specular.xyz * raddec * disdec * specfactor;//最后要乘以材质的吸收系数(这里没乘)
	}

	output.Color.w = 1.0f;//因为output被初始化为(PS_OUTPUT)0,w也初始化为0了.
	output.Color.xyz = ambient.xyz + self.xyz + diffuse.xyz + specular.xyz;//把所有种类的光都累加起来
	return output;
}

//--------------------------------------------------------------------------
//				框架效果
//--------------------------------------------------------------------------
technique MulLights
{
	pass P0
	{
		vertexShader = compile vs_3_0 VS_Main();//顶点着色器
		pixelshader = compile ps_3_0 PS_Main();//像素着色器
	}
}

值得注意的是,环境光也可以有好几个(这里假设只有一个),另外,光照的最终叠加效果公式为:

最终光照颜色 =?所有的环境光 *?材质吸收指数?+?自发光 + (点光源 +?方向光源+聚光灯) * (漫反射 +?镜面反射) *材质吸收指数????????

(自己推算的公式,可能有误,欢迎批评指出)

?

然后是应用程序中的代码:

变量定义:

D3DXMATRIX m_ProjMatrix;?//投影矩阵

?D3DXMATRIX m_ViewMatrix;?//观察矩阵

?//四个模型

?ID3DXMesh*????m_Meshes[4];

?D3DXMATRIX????m_WorldMatrices[4];

?D3DXVECTOR4????m_MeshColors[4];

?D3DMATERIAL9???m_Material;

?//点光源

?PointLight????m_PointLight[10];

?DirectLight???m_DirectLight[10];

?SpotLight????m_SpotLight[10];

?//-----------顶点着色器相关------------------

?D3DXHANDLE???m_WVPMatrixHandle;//世界-观察-投影矩阵句柄

?//-----------效果框架-----------------

?ID3DXEffect*???m_NLightEffect = 0;

?//-----------------句柄------------------------

?D3DXHANDLE????m_TecniMulLightsHandle = 0;?//技术句柄

?D3DXHANDLE????m_AmbAmountHandle = 0;??//环境光系数句柄

??//各种光源句柄

?D3DXHANDLE????m_PointLHandle = 0;???//点光源句柄

?D3DXHANDLE????m_DirectLightHandle = 0;?//方向光句柄

?D3DXHANDLE????m_SpotLightHandle = 0;??//聚光灯句柄

??//各种光源数量句柄

?D3DXHANDLE????m_NumPointLightHandle = 0;?//点光源个数句柄

?D3DXHANDLE????m_NumDirectLightHandle = 0;?//方向光个数句柄

?D3DXHANDLE????m_NumSpotLightHandle = 0;?//聚光灯个数句柄

?D3DXHANDLE????m_ViewPosHandle = 0;??//观察点句柄

?D3DXHANDLE????m_WorldMatrixHandle = 0;?//世界矩阵句柄

?

#define MESH_TEAPOT		0
#define MESH_SPHERE		1
#define MESH_TORUS		2
#define MESH_CYLINDER	3

typedef D3DXVECTOR4 float4;	//这里typedef成float4,就能与着色器里面一致,不需要改代码了!

struct PointLight
{
	float4 Diffuse;		//漫反射的颜色
	float4 Specular;	//镜面高光的颜色
	float4 Position;	//光源位置
	float4 RangeAttenuation;//范围,恒定衰减,镜面光强弱,二次衰减
};

struct DirectLight
{
	float4 Diffuse;		//漫反射的颜色
	float4 Specular;	//镜面高光的颜色
	float4 DirectionPow;	//方向x,y,z,高光
};

struct SpotLight
{
	float4 Diffuse;		//漫反射的颜色
	float4 Specular;	//镜面高光的颜色
	float4 Position;	//光源位置
	float4 Direction;	//方向
	float4 RangeAttenuation;//范围,恒定衰减,镜面光强弱,二次衰减
	float4 FalloffThetaPhi;	//从内锥到外锥之间的强度衰减,NULL,内锥的弧度,外锥的弧度
};

?

//setup: main函数中调用一次
	void Setup()
	{
		HRESULT hr = 0;

		//创建模型们: 茶壶 圆球 圆环 圆桶
		D3DXCreateTeapot(m_d3dDevice->GetD3DDevice(), &m_Meshes[MESH_TEAPOT], NULL);
		D3DXCreateSphere(m_d3dDevice->GetD3DDevice(), 1.0f, 20, 20, &m_Meshes[MESH_SPHERE], NULL);
		D3DXCreateTorus(m_d3dDevice->GetD3DDevice(), 0.5f, 1.0f, 20, 20, &m_Meshes[MESH_TORUS], NULL);
		D3DXCreateCylinder(m_d3dDevice->GetD3DDevice(), 0.5f, 0.5f, 2.0f, 20, 20, &m_Meshes[MESH_CYLINDER], NULL);
		//模型们的在世界中的矩阵:
		D3DXMatrixTranslation(&m_WorldMatrices[MESH_TEAPOT], 0.0f, 2.0f, 0.0f);
		D3DXMatrixTranslation(&m_WorldMatrices[MESH_SPHERE], 0.0f, -2.0f, 0.0f);
		D3DXMatrixTranslation(&m_WorldMatrices[MESH_TORUS], -3.0f, 0.0f, 0.0f);
		D3DXMatrixTranslation(&m_WorldMatrices[MESH_CYLINDER], 3.0f, 0.0f, 0.0f);
		//模型们的颜色:
		m_MeshColors[MESH_TEAPOT] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
		m_MeshColors[MESH_SPHERE] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
		m_MeshColors[MESH_TORUS] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
		m_MeshColors[MESH_CYLINDER] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);

		//
		//创建两个点光源
			//m_PointLight[0]
		m_PointLight[0].Diffuse = { 1.0f, 0.0f, 0.0f, 1.0f };//Diffuse
		m_PointLight[0].Specular = { 1.0f, 1.0f, 1.0f, 1.0f };//Specular
		m_PointLight[0].Position = { -6.0f, 2.0f, 2.0f, 0.0f };//Position
		m_PointLight[0].RangeAttenuation = { 15.0f, 1.0f, 50.0f, 0.0f };//Range,Attenuation0,镜面光强弱,Attenuation2
			//m_PointLight[1]
		m_PointLight[1].Diffuse = { 0.0f, 1.0f, 0.0f, 1.0f };
		m_PointLight[1].Specular = { 1.0f, 1.0f, 1.0f, 1.0f };
		m_PointLight[1].Position = { 6.0f, 2.0f, 3.0f, 0.0f };
		m_PointLight[1].RangeAttenuation = { 15.0f, 0.8f, 50.0f, 0.0f };
		//创建一个方向光
			//m_DirectLight[0]
		m_DirectLight[0].Diffuse = { 0.5f, 0.5f, 0.5f, 1.0f };
		m_DirectLight[0].Specular = { 0.5f, 0.5f, 0.5f, 1.0f };
		m_DirectLight[0].DirectionPow = { 0.0f, 0.0f, -1.0f, 10.0f };//(z轴正方向)
		//创建一个聚光灯
			//m_SpotLight[0]
		m_SpotLight[0].Diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
		m_SpotLight[0].Specular = { 1.0f, 1.0f, 1.0f, 1.0f };
		m_SpotLight[0].Position = { 0.0f, 1.8f, -5.0f, 0.0f };
		m_SpotLight[0].Direction = { 0.0f, 0.0f, 1.0f, 0.0f };
		m_SpotLight[0].FalloffThetaPhi = { 3.5f, 0.0f, 0.04f, 0.18f };//衰减,-,内角(弧度半角),外角(弧度半角)
		m_SpotLight[0].RangeAttenuation = { 10.0f, 0.0f, 20.0f, 0.0f };//范围,衰减1,高光,衰减2

		ID3DXBuffer* errorBuffer = 0;
		hr = D3DXCreateEffectFromFile(m_d3dDevice->GetD3DDevice(),
			L"D:\\nlight.fx",
			0,
			0,
			D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
			0,
			&m_NLightEffect,
			&errorBuffer);
		// 输出错误信息:
		if (errorBuffer)
		{
			string str = (char*)errorBuffer->GetBufferPointer();
			MessageBox(NULL, Common::StringToWString(str).c_str(), L"ERROR", MB_OK);
			//safe_release<ID3DXBuffer*>(error_buffer);
		}
		if (FAILED(hr))
		{
			MessageBox(NULL, L"D3DXCreateEffectFromFile() - FAILED", L"ERROR", MB_OK);
		} 

		//获取hlsl中常量句柄
			//得到技术technique MulLights的句柄
		m_TecniMulLightsHandle = m_NLightEffect->GetTechniqueByName("MulLights");
			//各种光源的个数
		m_NumPointLightHandle = m_NLightEffect->GetParameterByName(NULL, "g_NumPLs");
		m_NumDirectLightHandle = m_NLightEffect->GetParameterByName(NULL, "g_NumDLs");
		m_NumSpotLightHandle = m_NLightEffect->GetParameterByName(NULL, "g_NumSLs");
			//获取光源种类的句柄
		m_AmbAmountHandle = m_NLightEffect->GetParameterByName(NULL, "AmbAmount");//环境光因子句柄
		m_PointLHandle = m_NLightEffect->GetParameterByName(NULL, "g_PLs");//点光源句柄
		m_DirectLightHandle = m_NLightEffect->GetParameterByName(NULL, "g_DLs");//方向光句柄
		m_SpotLightHandle = m_NLightEffect->GetParameterByName(NULL, "g_SLs");//聚光灯句柄
			//获取观察点,矩阵句柄
		m_ViewPosHandle = m_NLightEffect->GetParameterByName(NULL, "g_ViewPos");
		m_WorldMatrixHandle = m_NLightEffect->GetParameterByName(NULL, "g_WorldMatrix");
		m_WVPMatrixHandle = m_NLightEffect->GetParameterByName(NULL, "WVPMatrix");//世界观察投影矩阵

		//设置常量句柄
			//传光源数据进去
		m_NLightEffect->SetRawValue(m_PointLHandle, m_PointLight, 0,sizeof(PointLight)*2);//传点光源
		m_NLightEffect->SetRawValue(m_DirectLightHandle, m_DirectLight, 0, sizeof(DirectLight)* 1);//传方向光
		m_NLightEffect->SetRawValue(m_SpotLightHandle, m_SpotLight, 0, sizeof(SpotLight)* 1);//传聚光灯

		m_NLightEffect->SetFloat(m_AmbAmountHandle, 0.0f);
		m_NLightEffect->SetInt(m_NumPointLightHandle, 2);//点光源数量:2 (调节个数可方便调试)
		m_NLightEffect->SetInt(m_NumDirectLightHandle, 1);//方向光数量:1
		m_NLightEffect->SetInt(m_NumSpotLightHandle, 1);//聚光灯数量:1

		//设置投影矩阵
		RECT rt;
		GetClientRect(Application::GetInstance()->GetWnd(), &rt);
		D3DXMatrixPerspectiveFovLH(&m_ProjMatrix, D3DX_PI / 4.0f, (float)rt.right / rt.bottom, 1.0f, 1000.0f);

		//暂时未设置纹理
		m_d3dDevice->GetD3DDevice()->SetRenderState(D3DRS_LIGHTING, false);//关闭灯光,即不用固定管线
	}

?

	//display: 在消息循环中调用,时时更新
	void Display(float timeDelta)
	{
		static float angle = (3.0f * D3DX_PI) / 2.0f;
		static float height = 0.0f;

		if (GetAsyncKeyState(VK_LEFT) & 0x8000f)
			angle -= 0.5f * timeDelta;

		if (GetAsyncKeyState(VK_RIGHT) & 0x8000f)
			angle += 0.5f * timeDelta;

		if (GetAsyncKeyState(VK_UP) & 0x8000f)
			height += 5.0f * timeDelta;

		if (GetAsyncKeyState(VK_DOWN) & 0x8000f)
			height -= 5.0f * timeDelta;

		//求出观察矩阵
		D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f);
		D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
		D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
		D3DXMatrixLookAtLH(&m_ViewMatrix, &position, &target, &up);
		D3DXVECTOR4 vps = { cosf(angle) * 7.0f, height, sinf(angle) * 7.0f, 0.0f };
		m_NLightEffect->SetVector(m_ViewPosHandle, &vps);

		// render now
		m_d3dDevice->GetD3DDevice()->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x99999999, 1.0f, 0);
		m_d3dDevice->GetD3DDevice()->BeginScene();

		//设置技术
		m_NLightEffect->SetTechnique(m_TecniMulLightsHandle);

		D3DXMATRIX WVPMatrix;

		for (int i = 0; i < 4; i++)
		{
			WVPMatrix = m_WorldMatrices[i] * m_ViewMatrix * m_ProjMatrix;

			m_NLightEffect->SetMatrix(m_WorldMatrixHandle, &m_WorldMatrices[i]);
			m_NLightEffect->SetMatrix(m_WVPMatrixHandle, &WVPMatrix);
			UINT numPass = 0;
			m_NLightEffect->Begin(&numPass, 0);
			for (UINT j = 0; j < numPass; ++j)
			{
				//开始过程
				m_NLightEffect->BeginPass(j);	//在begin和end中间不建议设置着色器变量
				m_Meshes[i]->DrawSubset(0);
				//结束过程
				m_NLightEffect->EndPass();
			}
			//结束使用技术
			m_NLightEffect->End();
		}
		m_d3dDevice->GetD3DDevice()->EndScene();
		m_d3dDevice->GetD3DDevice()->Present(NULL, NULL, NULL, NULL);
	}

测试一: 1个点光源:

发现了一个错误!!!:黑色的地方没有光照,居然也有镜面反射了,oh,shit,网上的算法也不严谨嘛...

解决方法:稍微一思考,有光的地方才有镜面反射对吧?怎么样才有光? 就是光线方向和面法线的夹角要大于0,

即difusefactor = dot(光线,面法线)>0.0f; 即difusefactor>0.0f,所以,HLSL里在计算镜面光的时候多加一个

判断:

//镜面反射算法

???if (difusefactor>0.0f)?//只有有光照到的地方才有镜面反射!!!

???{

????float3 DirectionToView = normalize(worldpos.xyz - g_ViewPos.xyz);? //(同在世界空间中!)

?????float3 VectorToLight = normalize(input.vtpos.xyz - g_PLs[i].Position.xyz);

?????//计算反射光

?????float3 reflectanceRay = 2 * dot(input.normal.xyz, VectorToLight.xyz)*input.normal.xyz - VectorToLight.xyz;

?????float specfactor = pow(abs(dot(reflectanceRay, DirectionToView)), g_PLs[i].RangeAttenuation.z);

????//镜面光累加

????specular.xyz += g_PLs[i].Specular.xyz * specfactor;//最后要乘以材质的吸收系数(这里没乘)

???}??

(下面的效果图都没有修改这一个错误,自行修改)

测试二:?两个点光源:

测试三:?方向光:

测试四:聚光灯:

测试五:火力全开:

(亮瞎眼了~...)

??

??

原文地址:https://www.cnblogs.com/lonelyxmas/p/10807300.html

时间: 2024-08-03 16:21:44

HLSL效果框架-多光源效果的相关文章

HLSL效果框架

原文:HLSL效果框架 HLSL效果框架能简化许多操作.这里先不写具体的效果框架的程序,在处理多光源光照的时候再整理. 下一章:效果框架-多种光源的多光源?叠加效果 这儿先列出效果框架的一个注意点: 在begin和end中间不建议设置着色器变量,虽然用CommitChanges()可强制传入显卡,但是太浪费性能, 调用默认的begin和end总是最好的.所以渲染框架如下: for (int i = 0; i < 4; i++)//四个模型 ???{ ????WVPMatrix = m_World

提示框第三方库之MBProgressHUD iOS toast效果 动态提示框效果

提示框第三方库之MBProgressHUD iOS toast效果 动态提示框效果 2014-08-11 17:39 11614人阅读 评论(0) 收藏 举报  分类: iOS相关(20)  文章来自:http://blog.csdn.net/ryantang03/article/details/7877120 MBProgressHUD是一个开源项目,实现了很多种样式的提示框,使用上简单.方便,并且可以对显示的内容进行自定义,功能很强大,很多项目中都有使用到.到GitHub上可以下载到项目源码

为什么DW的可视化下看到的效果与浏览器的效果有所区别?

可视区不是调用外面浏览器,Dreamweav 可视化区是为用户编辑而设计. 支持最基本的 HTML 与 CSS ,对 CSS 而言,我写入样式时如果你使用最基本的样式时它显示与你浏览器中看的效果相差不大, 如果你使用一些 HACK 技术(因为 HACK 单独对不同浏览而用)加上 DW 自身对样式的错误理解,看到可视化区就会变得面目全非! 如果你很依赖可视化的话,最好少用一些 HACK 技术,因为 HACK 技术是没有方法情况下为了各浏览器正常显示加的代码, 但这不是为了展示技术而做的一项工作.写

多种效果进度指示层效果iOS源码项目

该源码是一个多种效果进度指示层效果源码案例,源码KVNProgress,KVNProgress提供多种效果的进度指示层,有半透明效果,也支持全屏显示.指示层还高度支持自定义,可以按自己的需求定制.效果图: <ignore_js_op> 使用方法: 支持CocoaPods pod 'KVNProgress' 导入头文件: #import "KVNProgress.h" 展现: -[KVNProgress showWithParameters:@{KVNProgressView

6 cocos2dx粒子效果,类图关系,系统原生粒子和自己定义粒子效果,粒子编译器软件,爆炸粒子效果,烟花效果,火焰效果,流星效果,漩涡粒子效果,雪花效果,烟雾效果,太阳效果,下雨效果

?? 1 粒子 演示样例 2 类图关系 3 系统原生粒子 CCParticleSystem 全部粒子系统的父类 CCParticleSystemPoint. CCParticleSystemQuad 点粒子和方形粒子系统,都继承了CCParticleSystem的全部属性 CCParticleExplosion 爆炸粒子效果 CCParticleFireworks 烟花粒子效果 CCParticleFire 火焰粒子效果 CCParticleMetepr 流行粒子效果 CCParticleSpi

jQuery开发之超链接提示效果和图片提示效果

1,超链接提示效果 超链接自带的有提示效果的,这里就把自己定义的提示效果放在一起可以进行一下比较.示例代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type"

6 cocos2dx粒子效果,类图关系,系统原生粒子和自定义粒子效果,粒子编译器软件,爆炸粒子效果,烟花效果,火焰效果,流星效果,漩涡粒子效果,雪花效果,烟雾效果,太阳效果,下雨效果

 1 粒子 示例 2 类图关系 3 系统原生粒子 CCParticleSystem 所有粒子系统的父类 CCParticleSystemPoint. CCParticleSystemQuad 点粒子和方形粒子系统,都继承了CCParticleSystem的所有属性 CCParticleExplosion 爆炸粒子效果 CCParticleFireworks 烟花粒子效果 CCParticleFire 火焰粒子效果 CCParticleMetepr 流行粒子效果 CCParticleSpira

一款简洁而强大的前端框架JQUery—动画效果及剪刀石头布小游戏

jQuery是什么? jQuery是一个快速.简洁的JavaScript框架,它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作.事件处理.动画设计和Ajax交互.它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作.事件处理.动画设计和Ajax交互. JQuery效果-隐藏和显示 .show()让隐藏的元素显示.效果为:同时修改元素的高度.宽度.opacity属性 .hide()让显示

iOS火焰动画效果、图文混排框架、StackView效果、偏好设置、底部手势等源码

iOS精选源码 高性能图文混排框架,构架顺滑的iOS应用. 使用OpenGLE覆盖阿尔法通道视频动画播放器视图. 可选最大日期截至当日日期的日期轮选器ChooseDatePicker 简单轻量的图片浏览器YCPhotoBrower 使用偏好设置.属性列表.归档解档保存数据.恢复数据 页面底部手势交互滚动UITableView 使用CoreAnimation来模拟iOS中的StackView. 盒子可以更具长宽高变化的动画 iOS优质博客 iOS导航栏使用总结 目录:一.设置导航栏样式二.自定义导