2015-11-16 6 views
1

Я работаю над 3D-проектом в DirectX11, и в настоящее время я использую различные огни, используя Программу 3D-игры Фрэнка Луны с помощью книги DirectX11 с моим существующим кодом.Как правильно создать прожектор в DirectX11?

В настоящее время я разрабатываю прожектор, который должен следовать за положением камеры и смотреть в том же направлении, однако положение, которое горит, странно перемещается. Когда положение изменяется, вектор направления света, по-видимому, отслеживается в направлении (+ x, + y, 0). Лучше всего объясняется картиной.

Boxes lit "properly"

Он послушай, как они освещены должным образом, и если камера остается на месте, в центре внимания можно перемещать, как и следовало ожидать, и он отслеживает направление камеры.

Boxes misbehaving

На этом изображении, я переместил камеру ближе к ящикам, вдоль оси, и световое пятно нужно просто получить меньше на ближайшем поле, но он вместо того, чтобы отслеживать вверх.

Это код, где в центре внимания структура создается до быть передан в постоянном буфере, то есть все значения в структуры, в сторону от поплавка используется в качестве прокладки в конце:

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; 
} 

Где я ошибся?

+0

@NicoSchertler К сожалению, знал, что я что-то забуду. Это прямо в нижней части раздела, как раз перед установкой 'float4 colour'. – Yann

+0

Кажется, что существует несоответствие с вашим именем переменной. 'output.PosW' выглядит как позиция, но это направление к камере. Вы передаете это значение 'calculateSpotlight()' как параметр 'position', где он используется как позиция. Одна из двух частей должна быть изменена. Кроме того, когда вы вычисляете 'spot', вам не хватает минуса перед' light.direction.z'. Во всяком случае, там слишком много минусов ('reflect (-lightV, normal)', 'dot (-lightV, ...', '-light.direction'). –

+0

Возможно, вы захотите взглянуть на [ FixedfuncEMUFX11] (https://github.com/walbourn/directx-sdk-samples), который имеет HLSLshaders, которые реализуют всю стандартную рендеринг с фиксированной функцией, включая точечные источники. –

ответ

2

Здесь приведен неверный аргумент input.PosW. Вы должны использовать позицию в мировом пространстве. input.PosWнормализованный вектор. Не имеет смысла вычитать нормализованный вектор из положения света.

Вы

calculateSpotLight(newMat, spotLight, input.PosW, input.Norm, input.PosW, amb, diff, spec); 

Вам нужно (input.Pos в WS, а не проекция пространства)

calculateSpotLight(newMat, spotLight, input.Pos, input.Norm, input.PosW, amb, diff, spec); 
+0

Это не совсем правильный ответ, но это набрал меня на правильном пути. Мне нужен вход. До того, как он был помещен в координаты проекции мировоззрения. – Yann

+0

Это может быть любое ортогональное пространство, но такое же пространство, как 'light.pos'.Например, они могут быть местом для камеры. –

+0

Да, это должно, но input.Pos помещается в пространство проецирования до конца вершинного шейдера, поэтому я просто добавил еще одну переменную на вывод вершинного шейдера, который дает положение в мировом пространстве. – Yann