着色器语言文件为:,代码为:算法
//着色器处理未知数量光源数目 未知光源种类 的 混合效果 //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();//像素着色器 } }
#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); }
//镜面反射算法
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;//最后要乘以材质的吸取系数(这里没乘)
} 框架
函数
测试