En una de las diapositivas de PowerPoint "Representación de DirectX 11 en Battlefield 3", noté el siguiente código:
struct Light {
float3 pos; float sqrRadius;
float3 color; float invSqrRadius;
}
No entiendo por qué almacenarían el radio cuadrado e incluso el cuadrado inverso (que creo que es simplemente un radio de 1 cuadrado) en lugar de simplemente almacenar el radio. ¿Cómo están utilizando estos datos en sus cálculos? Además, ¿qué pasa con las luces de cono y línea? Esta estructura debe ser solo para las luces de punto, no puedo ver que funcione para otros tipos, no hay suficientes datos. Aún así, me encantaría saber cómo usan ese cuadrado e invSquare.
ACTUALIZACIÓN: Ok, finalmente lo entendí.
Aquí está la ecuación clásica de atenuación de luz, que se encuentra fácilmente en la red:
float3 lightVector = lightPosition - surfacePosition;
float attenuation = saturate(1 - length(lightVector)/lightRadius);
Es relativamente costoso ya length(lightVector)
que en realidad está haciendo esto:
length(lightVector) = sqrt(dot(lightVector, lightVector);
Además, la operación de división (/lightRadius)
también es bastante costosa.
En lugar de calcular la atenuación de la luz de esta manera, puede calcularla de la siguiente manera, lo que sería mucho más rápido:
attenuation = saturate(1 - dot(lightVector, lightVector)*invRadiusSqr);
donde invRadiusSqr se puede calcular previamente a nivel de CPU y pasar como una constante de sombreador.
Además, obtienes una atenuación de luz cuadrática como resultado (en lugar de lineal en el primer caso), lo que es aún mejor, ya que la luz IRL ha demostrado tener una caída cuadrática.
¡Gracias a todos por su ayuda!
Respuestas:
Esto es simplemente un tipo de optimización dado que
invSqrRadius = 1/SqrRadius
, en lugar de calcular el radio cuadrado inverso para cada luz cada vez que simplemente lo almacenan en caché, la razón es que la división suele ser una operación "lenta" al menos en comparación con la multiplicación.Esta optimización es relevante especialmente:
Con respecto a cómo se usa, no estoy seguro acerca de su implementación específica, pero con respecto a
1/sqrRadius
esto, esto simplemente se usa para atenuación de luz, caída y sacrificio. También es relevante para direccional y foco, la única diferencia en caso de foco es que necesita calcular el factor de foco después de aplicar la atenuación . Con respecto a las luces direccionales como el sol, generalmente no tiene atenuación ni caída, por lo que supongo que se ignorará.[EDIT] Sólo para elaborar más, es que no los datos irrelevantes. La irradiancia de la luz se puede calcular utilizando la siguiente ecuación:
Esta ecuación explica por qué la cantidad de energía recibida disminuye con la distancia al cuadrado.
Otro punto es que necesita calcular la distancia entre el vértice y la luz para calcular la contribución de la luz en un vértice específico (es poco probable que este valor se almacene en caché), el vértice puede estar dentro o fuera del rango de luz, lo que nos lleva al siguiente punto donde
Radius Square
es útil para sacrificar.Si desea un ejemplo práctico para calcular la caída de luz y el sacrificio, esto es especialmente útil en renderizadores diferidos basados en mosaicos, aquí hay un ejemplo .
fuente
invSqrRadius no es 1 - sqrRadius; es 1 / sqrRadius.
Significa que puede multiplicar por invSqrRadius, en lugar de dividir por sqrRadius (ya que la división suele ser mucho más costosa que la multiplicación)
fuente
Las otras respuestas aquí trataron con el radio cuadrado inverso, pero voy a ver el radio cuadrado en su lugar (que concept3d mencionó, pero creo que merece más discusión).
Para qué son útiles los cuadrados son las comparaciones de distancia. Sabemos que calcular la distancia entre dos puntos implica una raíz cuadrada, y las raíces cuadradas son caras de calcular, pero si todo lo que queremos hacer es comparar distancias (para encontrar cuál es menor o mayor, y hacer algo interesante basado en el resultado) podemos tirar la raíz cuadrada.
Si sqrt (x)> sqrt (y), entonces también es el caso de que x> y.
Para una luz, el radio al cuadrado es el mismo que la distancia entre el centro de la luz y su extensión máxima, al cuadrado, por supuesto.
Para los cálculos de iluminación, esto se puede usar para un caso de salida anticipada. Si la distancia entre el punto que está iluminando y el centro de la luz (al cuadrado) es mayor que el radio al cuadrado, el punto no recibe luz y no necesita ejecutar el resto de sus cálculos. Por lo tanto, esto es solo una optimización (bastante común): podemos usar el radio cuadrado para hacer la comparación de distancia sin costosas raíces cuadradas, y a un costo de solo una resta y un producto de puntos.
Yo, por supuesto, no sé si esto es exactamente para lo que BF3 lo está usando, pero esperaría que no esté demasiado lejos de la marca.
fuente