Em um dos slides do PowerPoint "Renderização do DirectX 11 no Battlefield 3", observei o código a seguir:
struct Light {
float3 pos; float sqrRadius;
float3 color; float invSqrRadius;
}
Não entendo por que eles armazenariam o raio ao quadrado e até o inverso ao quadrado (que acredito ser apenas um raio ao quadrado) em vez de simplesmente armazenar o raio? Como eles estão usando esses dados em seus cálculos? Além disso, e as luzes de cone e linha? Essa estrutura deve ser apenas para as luzes de ponto, não consigo vê-la funcionando para outros tipos - não há dados suficientes. Ainda assim, eu gostaria de saber como eles usam esse quadrado e o invSquare.
ATUALIZAÇÃO: Ok, finalmente entendi.
Aqui está a equação clássica de atenuação da luz, facilmente encontrada na rede:
float3 lightVector = lightPosition - surfacePosition;
float attenuation = saturate(1 - length(lightVector)/lightRadius);
É relativamente caro, pois length(lightVector)
está realmente fazendo isso:
length(lightVector) = sqrt(dot(lightVector, lightVector);
além disso, a operação de divisão (/lightRadius)
também é bastante cara.
Em vez de calcular a atenuação da luz dessa maneira, você pode calculá-la da seguinte maneira, o que seria muito mais rápido:
attenuation = saturate(1 - dot(lightVector, lightVector)*invRadiusSqr);
onde invRadiusSqr pode ser pré-calculado no nível da CPU e passado como uma constante de sombreador.
Além disso, você obtém uma atenuação quadrática da luz como resultado (em vez de linear no primeiro caso), o que é ainda melhor, pois a luz IRL demonstrou ter queda quadrática.
Obrigado a todos por sua ajuda!
Respostas:
Isso é simplesmente um tipo de otimização
invSqrRadius = 1/SqrRadius
, pois, em vez de calcular o raio inverso ao quadrado de cada luz toda vez que eles simplesmente armazenam em cache, a razão é que a divisão é geralmente uma operação "lenta" pelo menos quando comparada à multiplicação.Essa otimização é relevante principalmente:
Em relação à forma como é usado, não tenho certeza sobre sua implementação específica, mas em relação a
1/sqrRadius
isso é simplesmente usado para atenuação leve, queda e seleção. Também é relevante para direcionais e holofotes, a única diferença no caso de holofotes é que você precisa calcular o fator holofotes após aplicar a atenuação . Em relação às luzes direcionais, como o sol, ele geralmente não possui atenuação ou queda, por isso acho que será ignorado.[EDIT] Só para elaborar mais, é não dados irrelevantes. A irradiância da luz pode ser calculada usando a seguinte equação:
Esta equação explica por que a quantidade de energia recebida diminui com a distância ao quadrado.
Outro ponto é que você precisa calcular a distância entre o vértice e a luz para calcular a contribuição da luz em um vértice específico (é improvável que esse valor seja armazenado em cache), o vértice pode estar dentro ou fora da faixa de luz que nos leva ao próximo ponto onde
Radius Square
é útil para abate.Se você deseja um exemplo prático para calcular a queda de luz e o descarte, isso é especialmente útil em renderizadores diferidos com base em bloco, aqui está um exemplo .
fonte
invSqrRadius não é 1 - sqrRadius; é 1 / sqrRadius.
Isso significa que você pode multiplicar por invSqrRadius, em vez de dividir por sqrRadius (como a divisão geralmente é muito mais cara que a multiplicação)
fonte
As outras respostas aqui tratam do raio quadrado inverso, mas, em vez disso, vou olhar para o raio quadrado (conceito que tocamos, mas acredito que merece uma discussão mais aprofundada).
Para que os quadrados são úteis são comparações de distância. Sabemos que calcular a distância entre dois pontos envolve uma raiz quadrada, e as raízes quadradas são caras de calcular, mas se tudo o que queremos fazer é comparar distâncias (para descobrir qual é menor ou maior e fazer algo interessante com base no resultado) podemos jogar fora a raiz quadrada.
Se sqrt (x)> sqrt (y), também é o caso de x> y.
Para uma luz, o raio ao quadrado é o mesmo que a distância entre o centro da luz e sua extensão máxima - ao quadrado, é claro.
Para cálculos de iluminação, isso pode ser usado para um caso de saída antecipada. Se a distância entre o ponto que você está iluminando e o centro da luz (quadrado) for maior que o raio quadrado, o ponto não receberá luz e você não precisará executar o resto dos seus cálculos. Portanto, isso é apenas uma otimização (bastante comum) - podemos usar o raio quadrado para fazer a comparação da distância sem raízes quadradas caras, e a um custo de apenas um produto de subtração e ponto.
É claro que não sei se é exatamente para isso que o BF3 está usando, mas espero que não esteja muito longe da realidade.
fonte