Ecuación de Phong + 1

Diciembre 8, 2008

Hola

Después de una semana un poco movida sin haber podido postear por falta de tiempo, hoy vengo para explicar la evolución de la ecuación de Phong en nuestros engines.

La ecuación de Phong es muy simple, básicamente es una suma de tres componentes:

Resultado = Ambiente + Diffusa + Specular

¿Dónde está el problema? El problema reside en que esa es la forma más simple de calcular la iluminación en un píxel, y a medida que vamos añadiendo ‘capacidades’ a la ecuación, esta va evolucionando para dar como resultado algo nada intuitivo.

Actualmente me encuentro haciendo la ecuación de la nueva versión del engine y os puedo comentar varias cosas:

- En esta ecuación no se representa en ningún momento alguna componente de auto iluminación, por lo tanto, ya tenemos una componente que en esa ecuación no está reflejada.
- En la ecuación de iluminación del Half-Life 2, la Ambiente y la Diffusa no se suman, sino que se operan entre sí para formar una componente Diffusa nueva a la cual se le sumara la componente Specular.
- La ecuación de Phong con una sola luz nos proporciona oscuridad casi absoluta en esas caras o píxeles que no estén mirando a la luz, cargándose por completo la sensación de iluminación global de la escena. Por lo tanto a veces se opta por poner un 30% de Ambiente y un 70% de Diffusa para que los píxeles no tiendan a negro absoluto.
- En ningún momento hemos hablado de la componente de lightmap, por lo tanto ya tenemos otra componente oculta y que deberemos tratar para obtener buenos resultados.
- Etc.

Como podéis observar, la ecuación de Phong está bien para empezar, pero poco a poco vamos añadiendo mas información necesaria y nos da como resultado una ecuación que distaba mucho de la teoría.

Este podría ser un ejemplo:

Resultado = ((Ambiente <-> Diffusa) * LightMap) + Specular + Self-Ilumination

Un saludo


Render HDR y niebla

Noviembre 27, 2008

Hola

Hoy aunque breve, me gustaría hablar sobre una idea que me ha sobresaltado mientras pensaba en esto del HDR. Y aparte voy a probar de paso esto del particionado de la noticia.

Leer el resto de esta entrada »


Otra manera de hacer HDR (2)

Noviembre 26, 2008

Hola

Continuando con los experimentos de HDR, os quería mostrar lo que hablaba el otro día sobre esos ‘dos rangos’ en los que se dividía la luz.

hdr

Bien, en la imagen, podéis ver píxeles con color en el rango LDR [0.0f – 1.0f] y pixeles HDR que son de color rojo (son así porque he puesto un if en le shader para distinguirlos). La manera de interpretar esta imagen es la siguiente:

- Todos los píxeles que no son rojos, son píxeles que tienen rango LDR pero no tienen nada de HDR.
- Todos los píxeles ROJOS son píxeles que aparte de tener LDR tienen HDR.

Por lo tanto, solo el rango HDR será el que pasara a los filtros de glow y demás. Todos los otros píxeles se quedaran igual.

También comente de que si hacíamos dos salidas de píxeles, una en un render target, y otra en otro render target, es posible que perdiésemos el Anti Aliasing por hardware, y así es como es, lo perdemos, pero que no cunda el pánico, pues existen unos filtros de detección de bordes que nos permitirán aplicar un blur sobre esos píxeles y hacer nosotros mismos el Anti Aliasing.

Un saludo


Otra manera de hacer HDR

Noviembre 24, 2008

Hola

Hoy os quería mostrar otra manera de hacer los cálculos de un render HDR un poco diferentes a los que se utilizan en otras aplicaciones como juegos de ordenador.

Debo comentar que no voy a explicar el proceso completo, porque el proceso completo incluye cálculos de tonemapping y blur que ahora no tocaremos.

Concretamente lo que vamos a explicar es como hacer los cálculos de la luz para que no se vean restringidos a un rango de [0.0f – 1.0f].

Bien, la iluminación con HDR según podemos encontrar en tutoriales por internet (como por ejemplo AQUÍ) parte de la base de que todos los cálculos se deben realizar sin ningún tipo de limitador de rangos, es decir, el color no tiene porque ir de 0.0f a 1.0f sino que puede ir de 0.0f a 1000.0f o más.

El caso es que las texturas también tendrían que estar en ese formato, pero como una textura en HDR ocupa una barbaridad, utilizaremos las de toda la vida.

Normalmente en el cálculo de HDR se calculan las ecuaciones sin ningún tipo de limitación entre los parámetros de la luz, por lo tanto acabamos obteniendo valores de color que sobrepasan los rangos de color que un monitor puede ofrecer.

Es aquí donde entra el ser humano y hace una división en los rangos, es decir, el programador coge el valor resultante de ese cálculo sin limitación y especifica 2 campos. El color que va desde [0.0f – 1.0f] y el color que va desde [1.0f-n].

Esta ‘división’ en mi caso es un tanto diferente a como se realiza en otras aplicaciones. Es decir, en otras aplicaciones renderizan en HDR y los resultados los compactan en un float para que no se pierdan los valores exactos y sin limitar de la propia ecuación. Este float es guardado en un Render Target con formato de floats (32R) para su posterior uso.

Lo que yo hago es hacer el cálculo sin limitaciones aparentes (a excepción de los pixeles de las texturas) y al final del pixel shader divido los rangos en LDR y HDR. Recordemos que LDR = [0.0f – 1.0f] y HDR [1.0f – n].

Una vez hecha esta división de rangos, saco en un render target el LDR y en otro el HDR, así el HDR está listo para poder ser objetivo de diferentes post-procesos como blur y demás.

hdr_ldr

A la izquierda rango LDR, a la derecha rango HDR.

Lo que me queda por descubrir es si una de las salidas de los multi render targets puede ser el Back Buffer. De no ser así tendríamos un problema porque nos quedamos sin Anti Aliasing por hardware.

Un saludo


Generador de funciones simples

Noviembre 20, 2008

Hola

Hace ya tiempo que quería implementar una especie de generador de funciones simples para controlar animaciones periódicas de algunos parámetros de las luces al igual como de los materiales.

Concretamente me he implementado una clase que dependiendo del tipo de onda especificado, amplitud y periodicidad, es capaz de devolver en tiempo real los valores de la función deseada.

func

A continuación tenéis el código de las funciones que tengo implementadas:

//---------------------------------------------------------------------------------
// USE: Updatea
//	IN: float - Valor de entrada
// OUT:	Void
//---------------------------------------------------------------------------------
void CWaveGenerator::UpdateNone(float inTime)
{
	m_fValue = 0.0f;
}

//---------------------------------------------------------------------------------
// USE: Updatea
//	IN: float - Valor de entrada
// OUT:	Void
//---------------------------------------------------------------------------------
void CWaveGenerator::UpdateOne(float inTime)
{
	m_fValue = 1.0f;
}

//---------------------------------------------------------------------------------
// USE: Updatea
//	IN: float - Valor de entrada
// OUT:	Void
//---------------------------------------------------------------------------------
void CWaveGenerator::UpdateHalfSawTooth(float inTime)
{
	m_fTime += inTime;
	m_fTime = fmodf(m_fTime,m_fPeriodic);
	m_fValue = m_fTime / m_fPeriodic;
	m_fValue *= m_fAmplitude;
}

//---------------------------------------------------------------------------------
// USE: Updatea
//	IN: float - Valor de entrada
// OUT:	Void
//---------------------------------------------------------------------------------
void CWaveGenerator::UpdateSawTooth(float inTime)
{
	m_fTime += inTime;
	m_fTime = fmodf(m_fTime,m_fPeriodic);
	if(m_fTime > (m_fPeriodic / 2.0f) )
	{
		m_fValue = 1.0f - (m_fTime / m_fPeriodic);
	}
	else
	{
		m_fValue = m_fTime / m_fPeriodic;
	}
	m_fValue *= m_fAmplitude;
}

//---------------------------------------------------------------------------------
// USE: Updatea
//	IN: float - Valor de entrada
// OUT:	Void
//---------------------------------------------------------------------------------
void CWaveGenerator::UpdateSquare(float inTime)
{
	m_fTime += inTime;
	m_fTime = fmodf(m_fTime,m_fPeriodic);
	if(m_fTime > (m_fPeriodic / 2.0f) )
	{
		m_fValue = 1.0f;
	}
	else
	{
		m_fValue = 0.0f;
	}
	m_fValue *= m_fAmplitude;
}

Esta clase está destinada a proporcionar los valores de parámetros como la intensidad de la luz o la intensidad de la componente Self-Ilumination de los materiales.

Un saludo


Componente especular y fresnel

Noviembre 19, 2008

Holas

Hoy os traigo algo interesante con relación a la componente especular.

Normalmente nosotros definimos la cantidad de especular que va a tener un material y nos quedamos tan anchos. Pero las cosas en la vida real son un poco diferentes, y aquí os traigo una idea que estoy desarrollando partiendo de lo que en su día hicieron los chicos de Valve con su ecuación grafica.

El caso es que una superficie con mucha especular (muy brillante), es brillante cuando en casi cualquier ángulo que formemos entre nosotros y la luz. El problema radica en las superficies que NO son brillantes, concretamente las mates, que si las miramos de frente son mates, PERO si estas superficies se ponen en paralelo a nuestro vector de visión y formando ángulo para el brillo con la luz, entonces se vuelven brillantes.

Esto es lo que comentan en la wiki de Valve software, yo concretamente antes de implementarlo lo he probado con una superficie mate y sí que es verdad.

alyx_phong_closeup

Para ello, nos ayudamos de un parámetro que se llama fresnel. El fresnel es simplemente un producto escalar entre nuestro vector de visión y la normal del píxel. Este valor de fresnel multiplicado por la componente especular nos proporciona “aproximadamente” ese efecto que comentábamos antes.

defaultfresnelterms

Yo lo he implementado recientemente en los materiales y la verdad es que cumple su cometido casi a la perfección, aunque el algoritmo no sea idéntico al que utilizan en Valve software.

alyxfresnel

Un saludo a todos.

P.D: Las imágenes son de la wiki de Valve, las he puesto porque ayuda a entender el concepto que explico.


Codigo fuente del proyecto iL-engine

Noviembre 18, 2008

Holas

Hoy no he podido actualizar debido a que he estado presentando por la mañana el proyecto iL-engine en la universidad, concluyendo así más de un año de desarrollo y cerrando el círculo que me acredita como ingeniero superior, como curiosidad, el proyecto tiene una nota de Matricula de Honor.

Como el proyecto ya esta entregado, hago público el código entero del proyecto como ya comente hace tiempo, aunque también me gustaría comentar ciertas cosas del código a modo de precaución:

- Se tiene que ir con mucho cuidado a la hora de compilar el código debido a que las librerías DXUT pueden dar problemas. Yo concretamente he intentado portar el código de un PC a otro PC y me han dado problemas de compilación. Según parece, el motivo es que hay posibles diferencias entre el SDK de un PC a otro. Por lo tanto os recomiendo que si no os compila de esta manera. Substituyáis las librerías DXUT por las de vuestro SDK.

- Recuerdo a todo el mundo de que este engine NO está diseñado para ser portable o para ofrecer una solución profesional (de momento). Por tanto es necesario entender de que debe ser visto como una ayuda en vuestro desarrollo personal el cual os pueda aportar ideas, trozos de código, etc.

Un saludo y que disfrutéis con el destripe del engine. El código lo podreis encontrar en la sección de Downloads.


Componente ambiente

Noviembre 14, 2008

Hola

Hoy empiezo mostrando el efecto que he conseguido mediante un sistema de luz ambiente. Concretamente se consigue mediante un objeto llamado CAmbientVolume, que es precisamente el código que os dije en el que estaba experimentando del cubemap simplificado.

ambient

Como podéis observar en la fotografía, tenemos una columna con un multi-material observada desde dos puntos de vista. En cada punto de vista podemos observar una tonalidad diferente, la de la izquierda tiene una tonalidad azul, la de la derecha tiene una tonalidad roja. Debemos recordar que la luz ambiente es solo una tonalidad aplicada al objeto, algo muy suave.

Por otro lado tengo una errata que comentar pues en el código de la idea del Cubemap simplificado faltan unas instrucciones, sino no funciona el proceso. Aquí tenéis el nuevo código:

	D3DXVECTOR3 vDir = D3DXVECTOR3(GetCameraActive()->GetTarget());
	D3DXVECTOR3 vNormDir;
	D3DXVec3Normalize(&vNormDir,&vDir);

	D3DXVECTOR3 vColX = Lerp(D3DXVECTOR3(m_vNegX.r,m_vNegX.g,m_vNegX.b),D3DXVECTOR3(m_vPosX.r,m_vPosX.g,m_vPosX.b),(vNormDir.x + 1.0f)*0.5f);// * Abs(vNormDir.x);
	D3DXVECTOR3 vColY = Lerp(D3DXVECTOR3(m_vNegY.r,m_vNegY.g,m_vNegY.b),D3DXVECTOR3(m_vPosY.r,m_vPosY.g,m_vPosY.b),(vNormDir.y + 1.0f)*0.5f);// * Abs(vNormDir.y);
	D3DXVECTOR3 vColZ = Lerp(D3DXVECTOR3(m_vNegZ.r,m_vNegZ.g,m_vNegZ.b),D3DXVECTOR3(m_vPosZ.r,m_vPosZ.g,m_vPosZ.b),(vNormDir.z + 1.0f)*0.5f);// * Abs(vNormDir.z);

	D3DXVECTOR3 vColTmp = Lerp(vColY,vColX,Abs(vNormDir.x));
	vColTmp = Lerp(vColTmp,vColZ,Abs(vNormDir.z));

Nótese las dos instrucciones Abs(…) añadidas.

Un saludo


Nuevo logo para el proyecto

Noviembre 13, 2008

Hola

Hoy os quería mostrar el logo que me ha hecho un amigo mío para el proyecto en sí. Y como a mí me gusta pues me lo quedo :) .

il_logo

Un saludo


Documentación no técnica de iL-engine

Noviembre 12, 2008

Hola

En la sección de Downloads teneis la memoria que presente para el Proyecto Final de Carrera (PFC). Es una documentación no técnica, es decir, es como una visión general de todo el proyecto, aunque esta el codigo de las ecuaciones de iluminación, etc.

Un saludo