我正在研究DirectX11中的3D項目,並且目前正在使用帶有DirectX11書籍的Frank Luna 3D遊戲編程和現有代碼實現不同的燈光。如何在DirectX11中正確創建聚光燈?
目前,我正在開發一個聚光燈,它應該跟隨相機的位置並朝相同的方向看,但是,被點亮的位置奇怪地移動。當位置正在改變時,光的方向矢量似乎在(+ x,+ y,0)方向上跟蹤。最好用圖片解釋。
它看這裏像他們適當地被點燃,如果相機保持它在哪裏,聚光燈可以移動爲你所期望的,並且它跟蹤攝像機的方向。
在此圖像中,我搬到了相機接近箱,沿z軸,光點應該控制一下最近的盒子小,但它不是跟蹤向上。
這是聚光燈結構正在建立要傳遞到所述恆定緩衝器內的代碼,也就是所有的值在結構,除了一個浮子被用作在端部的墊:
cb.spotLight = SpotLight();
cb.spotLight.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);
cb.spotLight.specular = XMFLOAT4(0.5, 0.5, 0.5, 10.0);
cb.spotLight.diffuse = XMFLOAT4(0.5, 0.5, 0.5, 1.0);
cb.spotLight.attenuation = XMFLOAT3(1, 1, 1);
cb.spotLight.range = 15;
XMVECTOR cameraP = XMLoadFloat3(&cameraPos);
XMVECTOR s = XMVectorReplicate(cb.spotLight.range);
XMVECTOR l = XMLoadFloat3(&camera.getForwards());
XMVECTOR lookat = XMVectorMultiplyAdd(s, l, cameraP);
XMStoreFloat3(&cb.spotLight.direction, XMVector3Normalize(lookat - XMVectorSet(cameraPos.x, cameraPos.y, cameraPos.z, 1.0f)));
cb.spotLight.position = cameraPos;
cb.spotLight.spot = 96;
這裏是被用來計算着色器中的聚光燈的周圍,漫射和鏡面值功能:
void calculateSpotLight(Material mat, SpotLight light, float3 position, float3 normal, float3 toEye,
out float4 ambient, out float4 diffuse, out float4 specular)
{
ambient = float4(0, 0, 0, 0);
specular = float4(0, 0, 0, 0);
diffuse = float4(0, 0, 0, 0);
float3 lightV = light.position - position;
float distance = length(lightV);
if (distance > light.range)
{
return;
}
lightV /= distance;
ambient = mat.ambient * light.ambient;
float diffuseFact = dot(lightV, normal);
[flatten]
if (diffuseFact > 0.0f)
{
float3 vect = reflect(-lightV, normal);
float specularFact = pow(max(dot(vect, toEye), 0.0f), mat.specular.w);
diffuse = diffuseFact * mat.diffuse * light.diffuse;
specular = specularFact * mat.specular * light.specular;
}
float spot = pow(max(dot(-lightV, float3(-light.direction.x, -light.direction.y, light.direction.z)), 0.0f), light.spot);
float attenuation = spot/dot(light.attenuation, float3(1.0f, distance, distance*distance));
ambient *= spot;
diffuse *= attenuation;
specular *= attenuation;
}
而對於completenesses起見,頂點和像素着色器的相關部分。
VS_OUTPUT VS(float4 Pos : POSITION, float3 NormalL : NORMAL, float2 TexC : TEXCOORD)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul(Pos, World);
//Get normalised vector to camera position in world coordinates
output.PosW = normalize(eyePos - output.Pos.xyz);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);
//Getting normalised surface normal
float3 normalW = mul(float4(NormalL, 0.0f), World).xyz;
normalW = normalize(normalW);
output.Norm = normalW;
output.TexC = TexC;
return output;
}
float4 PS(VS_OUTPUT input) : SV_Target
{
input.Norm = normalize(input.Norm);
Material newMat;
newMat.ambient = material.ambient;
newMat.diffuse = texCol;
newMat.specular = specCol;
float4 ambient = (0.0f, 0.0f, 0.0f, 0.0f);
float4 specular = (0.0f, 0.0f, 0.0f, 0.0f);
float4 diffuse = (0.0f, 0.0f, 0.0f, 0.0f);
float4 amb, spec, diff;
calculateSpotLight(newMat, spotLight, input.PosW, input.Norm, input.PosW, amb, diff, spec);
ambient += amb;
specular += spec;
diffuse += diff;
//Other light types
float4 colour;
colour = ambient + specular + diffuse;
colour.a = material.diffuse.a;
return colour;
}
我哪裏出錯了?
@NicoSchertler哎呀,知道我忘了什麼東西(在WS,沒有投影空間input.Pos)。在'float4 colour'被設置之前,就在該部分的底部。 – Yann
您的變量命名似乎存在差異。 'output.PosW'看起來像一個位置,但它是相機的方向。你將'calculateSpotlight()'作爲'position'參數傳遞給它,它被用作位置。這兩個部分之一必須改變。此外,當你計算'spot'時,你在'light.direction.z'之前缺少減號。無論如何,在那裏似乎有太多的缺點('reflect(-lightV,normal)','dot(-lightV,...','-light.direction') –
你可能想看看[ FixedFuncEMUFX11](https://github.com/walbourn/directx-sdk-samples)示例,該示例具有實現所有標準「固定功能」渲染(包括投射燈)的HLSLshaders。 –