BRDF y coordenadas esféricas en el trazado de rayos

9

Desarrollé un rastreador de rayos que utiliza el modelo de iluminación phong / blinn phong estándar. Ahora lo estoy modificando para admitir renderizado basado físicamente, así que estoy implementando varios modelos BRDF. En este momento estoy enfocado en el modelo Oren-Nayar y Torrance-Sparrow. Cada uno de estos se basa en coordenadas esféricas utilizadas para expresar el incidente y la dirección saliente de la luz.

Mi pregunta es: ¿de qué manera es el correcto convertir wi y wo de coordenadas cartesianas a coordenadas esféricas?

Estoy aplicando la fórmula estándar que se informa aquí https://en.wikipedia.org/wiki/Spherical_coordinate_system#Coordinate_system_conversions, pero no estoy seguro de estar haciendo lo correcto, porque mi vector no tiene cola en el origen de la sistema de coordenadas cartesianas, pero se centran en el punto de intersección del rayo con el objeto.

Aquí puedes encontrar mi implementación actual:

¿Alguien puede ayudarme a dar una explicación de la forma correcta de convertir el vector wi y wo de coordenadas cartesianas a esféricas?

ACTUALIZAR

Copio aquí la parte relevante del código:

cálculo de coordenadas esféricas

float Vector3D::sphericalTheta() const {

    float sphericalTheta = acosf(Utils::clamp(y, -1.f, 1.f));

    return sphericalTheta;
}

float Vector3D::sphericalPhi() const {

    float phi = atan2f(z, x);

    return (phi < 0.f) ? phi + 2.f * M_PI : phi;
}

Oren Nayar

OrenNayar::OrenNayar(Spectrum<constant::spectrumSamples> reflectanceSpectrum, float degree) : reflectanceSpectrum{reflectanceSpectrum} {

    float sigma = Utils::degreeToRadian(degree);
    float sigmaPowerTwo = sigma * sigma;

    A = 1.0f - (sigmaPowerTwo / 2.0f * (sigmaPowerTwo + 0.33f));
    B = 0.45f * sigmaPowerTwo / (sigmaPowerTwo + 0.09f);
};

Spectrum<constant::spectrumSamples> OrenNayar::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    float thetaI = wi.sphericalTheta();
    float phiI = wi.sphericalPhi();

    float thetaO = wo.sphericalTheta();
    float phiO = wo.sphericalPhi();

    float alpha = std::fmaxf(thetaI, thetaO);
    float beta = std::fminf(thetaI, thetaO);

    Spectrum<constant::spectrumSamples> orenNayar = reflectanceSpectrum * constant::inversePi * (A + B * std::fmaxf(0, cosf(phiI - phiO) * sinf(alpha) * tanf(beta)));

    return orenNayar;
}

Torrance-Sparrow

float TorranceSparrow::G(const Vector3D& wi, const Vector3D& wo, const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float normalDotWh = fabsf(normal.dot(wh));
    float normalDotWo = fabsf(normal.dot(wo));
    float normalDotWi = fabsf(normal.dot(wi));
    float woDotWh = fabsf(wo.dot(wh));

    float G = fminf(1.0f, std::fminf((2.0f * normalDotWh * normalDotWo)/woDotWh, (2.0f * normalDotWh * normalDotWi)/woDotWh));

    return G;
}

float TorranceSparrow::D(const Vector3D& wh, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float cosThetaH = fabsf(wh.dot(normal));

    float Dd = (exponent + 2) * constant::inverseTwoPi * powf(cosThetaH, exponent);

    return Dd;
}

Spectrum<constant::spectrumSamples> TorranceSparrow::f(const Vector3D& wi, const Vector3D& wo, const Intersection* intersection) const {

    Vector3D normal = intersection->normal;
    normal.normalize();

    float thetaI = wi.sphericalTheta();
    float thetaO = wo.sphericalTheta();

    float cosThetaO = fabsf(cosf(thetaO));
    float cosThetaI = fabsf(cosf(thetaI));

    if(cosThetaI == 0 || cosThetaO == 0) {

        return reflectanceSpectrum * 0.0f;
    }

    Vector3D wh = (wi + wo);
    wh.normalize();

    float cosThetaH = wi.dot(wh);

    float F = Fresnel::dieletricFresnel(cosThetaH, refractiveIndex);
    float g = G(wi, wo, wh, intersection);
    float d = D(wh, intersection);

    printf("f %f g %f d %f \n", F, g, d);
    printf("result %f \n", ((d * g * F) / (4.0f * cosThetaI * cosThetaO)));

    Spectrum<constant::spectrumSamples> torranceSparrow = reflectanceSpectrum * ((d * g * F) / (4.0f * cosThetaI * cosThetaO));

    return torranceSparrow;
}

ACTUALIZACIÓN 2

Después de algunas búsquedas, encontré esta implementación de Oren-Nayar BRDF .

En la implementación anterior, theta para wi y wo se obtiene simplemente haciendo arccos (wo.dotProduct (Normal)) y arccos (wi.dotProduct (Normal)). Esto me parece razonable, ya que podemos usar la normalidad del punto de intersección como la dirección cenital de nuestro sistema de coordenadas esféricas y hacer el cálculo. El cálculo de gamma = cos (phi_wi - phi_wo) hace algún tipo de proyección de wi y wo en lo que llama "espacio tangente". Suponiendo que todo sea correcto en esta implementación, ¿puedo usar las fórmulas | Ver - Normal x (View.dotProduct (Normal)) | y | Light - Normal x (Light.dotProduct (Normal)) | para obtener la coordenada phi (en lugar de usar arctan ("algo"))?

Fabrizio Duroni
fuente
Alguien me podria ayudar?
Fabrizio Duroni
¿Puedes mostrar el fragmento de código exacto, no todo el repositorio?
concept3d
Parece que esta es una de las preguntas más misteriosas sobre el trazado de rayos de todos los tiempos: D
Fabrizio Duroni
Os animo a preguntar aquí computergraphics.stackexchange.com
concept3d
Hecho en concept3d. Puede encontrarlo aquí computergraphics.stackexchange.com/questions/1799/…
Fabrizio Duroni

Respuestas:

2

En realidad, es mejor no usar coordenadas esféricas (o cualquier ángulo para el caso) para implementar BRDF, sino trabajar directamente en el sistema de coordenadas cartesianas y usar el coseno del ángulo entre vectores, que es un producto de punto simple entre vectores unitarios, como ya sabes. Esto es más robusto y eficiente.

Para Oren-Nayar, puede pensar que tiene que usar ángulos (debido al mínimo / máximo de los ángulos), pero simplemente puede implementar el BRDF directamente en el espacio cartesiano: https://fgiesen.wordpress.com/2010/10/21 / terminar-tus-derivaciones-por favor

Para los BRDF de microfaceta Torrance-Sparrow o Cook-Torrance tampoco necesita utilizar coordenadas esféricas. En estos BRDF, el ángulo se pasa a una función trigonométrica (generalmente coseno) en términos D / F / G y el denominador BRDF, por lo que puede usar identidades rectas o trigonométricas de productos de puntos sin pasar por coordenadas esféricas.

JarkkoL
fuente
1

Puede especificar un sistema de coordenadas dado el N normal y otro vector. Elegiremos wi. Por lo tanto, cualquier vector que tenga la misma dirección que wi cuando se proyecta en el plano tangente tendrá un acimut de 0

Primero, proyectamos wi en el plano tangente: (suponiendo que wi ya está normalizado)

wit = normalize(wi - N * dot(wi, N))

ahora, podemos hacer lo mismo con wo:

wot = normalize(wo - N * dot(wo, N))

Ahora, ingenio y ingenio se encuentran tanto en un plano que es ortogonal a N como tangente al punto de intersección.

Podemos calcular el ángulo entre los dos ahora:

azimuth = arcos ( dot(wit, wot) )

Que es realmente el acimut de wot con respecto al ingenio cuando se proyecta en el plano tangente.

Gato
fuente
0

Si conoce el punto de intersección y el punto de origen, ¿no sería solo una cuestión de restar uno del otro para obtener el resultado como si fuera del origen?

Si no cree en el resultado y desea llegar a ese punto, también puede obtener la transformación de rotación para ir de un punto a otro a través de una matriz LookAt y luego descomponerla para obtener el componente rotacional. También puede obtener un cuaternión si lo desea.

Los resultados son iguales. La prueba es un poco larga, pero no complicada, y se deja al lector.

Pijama Panda
fuente
Hola @Panda Pyjama, gracias por tu respuesta, pero no puedo entender tu respuesta. Intento aclarar: si tuviera el punto de intersección y el punto de vista, puedo calcular wi y wo. Entonces puedo usar la normal como la dirección de mi cenit para calcular, pero no puedo encontrar el otro eje necesario para encontrar el ángulo acimutal en un plano ortogonal al cenit. En el recorte anterior, simplemente apliqué las fórmulas de conversión para coordenadas esféricas en wi y wo dadas en el sistema de coordenadas mundial, pero no creo que esta sea la forma correcta de calcular theta y phi.
Fabrizio Duroni