好久没有更新博客了。。。 最近一直在忙一些其他的事情= =。。 DX都快忘了
今天继续更新!
上次说到简单光照,今天我们就学习一个点光源
影响点光源的因素主要有:
范围,位置,衰减
其中衰减用一个二次方程来表达
Attenuation = att0 + (att1 * d) + (att2 * d²)
att0 - 常量修饰符
由于此值未乘以任何值,因此称为“常量修改器”,这意味着此值不会随着从光源到像素的距离的变化而变化。该值用于为光源范围内的所有物体提供最小量的光。如果您要将此值设置为“1.0f”,那么光源范围内的所有内容都将具有全彩或全光。
att1 - 线性修改器
您可以看到此值乘以光源和像素之间的距离,或乘以等式中的d。这使得该值成为“线性修改器”,这意味着随着像素和光源之间的距离增加,这将逐渐减少像素获得的光量。这可能是最现实的因素。
att2 - 指数修饰符
此值乘以d的平方,使该值为“指数修饰符”。使用此值可以使非常接近光源的物体获得大量光线,但随着它们移开,它们快速接收的光线会在很短的距离内减小,然后随着距离越来越远而逐渐减小。
Point Light Equation
lightToPixelVec = light.pos - input.worldPos;
之前我们已经学了如何把世界空间中的变量发送到VS中,其实把灯光发送到PS也是一样的道理。
然后调用HLSL中的函数。然后把向量单位化
d = length(lightToPixelVec);
lightToPixelVec /= d;
计算光照强度,然后乘光照本身的颜色得到颜色。 最后除以衰减系数
howMuchLight = dot(lightToPixelVec, input.normal);
finalColor += howMuchLight * diffuse * light.diffuse;
finalColor /= light.att[0] + (light.att[1] * d) + (light.att[2] * (d*d));
The Light Structure
struct Light
{
Light()
{
ZeroMemory(this, sizeof(Light));
}
XMFLOAT3 dir;
float pad1;
///**************new**************
XMFLOAT3 pos;
float range;
XMFLOAT3 att;
float pad2;
///**************new**************
XMFLOAT4 ambient;
XMFLOAT4 diffuse;
};
描述光照
light.pos = XMFLOAT3(0.0f, 0.0f, 0.0f);
light.range = 100.0f;
light.att = XMFLOAT3(0.0f, 0.2f, 0.0f);
light.ambient = XMFLOAT4(0.3f, 0.3f, 0.3f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
Update the Lights Position
XMVECTOR lightVector = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );
lightVector = XMVector3TransformCoord(lightVector,cube1World);
light.pos.x = XMVectorGetX(lightVector);
light.pos.y = XMVectorGetY(lightVector);
light.pos.z = XMVectorGetZ(lightVector);
我们这里把光照位置设置为第一个立方体的位置
在effect file中描述我们的结构体
struct Light
{
float3 dir;
float3 pos;
float range;
float3 att;
float4 ambient;
float4 diffuse;
};
VS 和PS如下
VS_OUTPUT VS(float4 inPos : POSITION, float2 inTexCoord : TEXCOORD, float3 normal : NORMAL)
{
VS_OUTPUT output;
output.Pos = mul(inPos, WVP);
output.worldPos = mul(inPos, World);
output.normal = mul(normal, World);
output.TexCoord = inTexCoord;
return output;
}
float4 PS(VS_OUTPUT input) : SV_TARGET
{
input.normal = normalize(input.normal);
float4 diffuse = ObjTexture.Sample( ObjSamplerState, input.TexCoord );
float3 finalColor = float3(0.0f, 0.0f, 0.0f);
//Create the vector between light position and pixels position
float3 lightToPixelVec = light.pos - input.worldPos;
//Find the distance between the light pos and pixel pos
float d = length(lightToPixelVec);
//Create the ambient light
float3 finalAmbient = diffuse * light.ambient;
//If pixel is too far, return pixel color with ambient light
if( d > light.range )
return float4(finalAmbient, diffuse.a);
//Turn lightToPixelVec into a unit length vector describing
//the pixels direction from the lights position
lightToPixelVec /= d;
//Calculate how much light the pixel gets by the angle
//in which the light strikes the pixels surface
float howMuchLight = dot(lightToPixelVec, input.normal);
//If light is striking the front side of the pixel
if( howMuchLight > 0.0f )
{
//Add light to the finalColor of the pixel
finalColor += howMuchLight * diffuse * light.diffuse;
//Calculate Light's Falloff factor
finalColor /= light.att[0] + (light.att[1] * d) + (light.att[2] * (d*d));
}
//make sure the values are between 1 and 0, and add the ambient
finalColor = saturate(finalColor + finalAmbient);
//Return Final Color
return float4(finalColor, diffuse.a);
}
在PS里 我们先算了物体的自发光 物体的自发光就是他的漫反射的颜色*光照的自发光
如果不在光照范围内,直接返回这个颜色。
否则的化计算他接收的多少光照: 光照强度*物体本身的漫反射颜色*光照本身的漫反射。(这里不乘光照的自发光ambient是因为这个元素只与自身计算有关,并不对其他物体执行计算。 但是在计算finalAmbient的时候也用到了光照的ambient,我感觉有点不对。 等我仔细看一些相关的内容再来解释~)
本节内容的代码部分可以在我的github里面找到!
游戏开发路途遥远,但我相信只要坚持,总能到达彼岸!
如果我的文章对于你学习DirectX11有点帮助,欢迎评论给出建议,让我们一起学习进步!
———————— 小明 2018.12.30 11.46