Buenas.
Estoy portando una serie de clases que había implementado con OpenGL a Direct3d y me han surgido algunas dudas.
Una de ellas es la forma en que yo hacía una especie de "entintado" en las imágenes:
OPENGL
A cada frame:
glColor4f (1.0f, 1.0f, 1.0f, 0.5f);
glCallList (displayList);
Y ale, la imagen que estaba en displayList se entintaba.
DIRECT3D
¿Cómo hago eso a cada frame en Direct3d sin tener que lockear el vertex buffer, cambiar el color de todos los vértices, unlockear y dibujar?
Porque según tengo entendido, lockear a cada frame es muy costoso.
Un saludo!
Lo único que se me ocurre ahora mismo es, o bien utilizar un material o bien utilizar vertex shaders. Esta última me parece la mejor opción.
Ten en cuenta que con un vertex shader puedes modificar todas las propiedades de los vértices sin bloquear el vertex buffer para nada.
Saludos.
Sí, eso es lo que había pensado tras ver el código de la semana de Ak47 (que por cierto, se lo curró). Pero me parecía extranísimo que una cosa que es tan sencilla de hacer en OpenGl (sin pérdida de velocidad) sea bastante más complicada en DX9 (tirar de shaders).
No sé, me parece muy fuerte.
Sino hay más remedio...
Gracias
PD: ¿Cómo se haría con el material? ¿Sería muy costoso? Si necesito activar la iluminación sí...
Hola:
Si que se puede hacer lo que quieres sin necesidad de hacer algo tan complejo. Has de usar el TextureFactor.
Si quieres tener un color por vertice, textura y ademas todo esto poder tintarlo de un color, debes hacer:
En el stage 0 pones que se multiplique la textura y el color por vertice.
En el stage 1 pones que el resultado anterior se multiplique por el TextureFactor.
El codigo seria algo asi:
p_Device9->SetRenderState( D3DRS_TEXTUREFACTOR, color/* Aqui pon el color que quieras*/ );
p_Device9->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
p_Device9->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
p_Device9->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
p_Device9->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
p_Device9->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
p_Device9->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR );
Si solamente quieres texture y tintar de un color:
En el stage 0 pones que se multiplique la textura y el TextureFactor:
Y su codigo correspondiente:
p_Device9->SetRenderState( D3DRS_TEXTUREFACTOR, color/* Aqui pon el color que quieras*/ );
p_Device9->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
p_Device9->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
p_Device9->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR );
Espero que te sirva!
Un saludote!!
Ey! Muchas gracias, aún no lo he probado pero tiene buena pinta.
Un par de dudas:
- ¿El color se lo meto con esto? color = D3DCOLOR_COLORVALUE (r, g, b, a); ¿Si en a pongo un valor 128 se verá semitransparente siempre que esté activado el alphablending?
- ¿Esto es usando multitextura, no? Vaya, no la necesitaba en OGL. ¿Cómo se hace para saber si una tarjeta soporta multitextura?
Gracias
En realidad, creo que MChiz ha tenido un pequeño despiste (supongo que al copiar y pegar).
Si sólo quieres aplicar una textura y tintar la superficie, sólo necesitas una unidad de textura. El código sería:
p_Device9->SetRenderState( D3DRS_TEXTUREFACTOR, color/* Aqui pon el color que quieras*/ );
p_Device9->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
p_Device9->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
p_Device9->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );
De todas formas, ¿qué aceleradora no soporta al menos dos unidades de textura?. Que yo sepa la voodoo1 ya soportaba dos unidades.
Saludos.
¿Y en el caso en el que tb usa el diffuse tb se puede hacer todo en el stage 0?
No, sólo se pueden utilizar dos argumentos por textura. (textura+factor, o textura+vertexcolor, etc)
En ese caso creo que el código que necesitas es justamente el primer caso que te ha puesto MChiz. Ahí sí estarías utilizando multitextura. La otra opción para no utilizar multitextura ya sabes que es bloquear el vertex buffer y la otra, y la mejor opción, utilizar vertex shaders.
Saludos.
Juas, esto:
CitarPor cierto, después de probar los vertex & pixel shaders, la fixed pipeline acaba pareciéndote patética
lo quería decir en este mensaje no en el otro que ha puesto MChiz. Aunque bueno, nunca está de más decirlo :D
Buens!
Lo primerisimo de todo: Berserker tiene razon; me equivoque al copypastear :b Lo que ha puesto Berserker esta bien.
Una cosa que parece estar confundida: El usar 2 stages no significa utilizar multitextura ( CREO ). Lo digo porque he llegado a hacer muchas operaciones, sobrepasando el limite de texturas simultaneas de mi tarjeta, y todo rula. Asi que CREO que utilizar el primer metodo que expuse no te obliga a tener multitextura. Que alguien me corrija si me equivoco ( o pruebalo tu mismo : ) )
Y a lo otro que decias, Loover: Si, si le metes 128 de alpha y tienes el alpha blending activado, funcionara : )
Saludotes!!!!!
¿Podría ser que Direct3D hace automáticamente las siguientes pasadas si no se puede pintar todo en una pasada? :huh:
Me pareceria demasiado raro ( y bonito ;b ). Pensemoslo como si fuese un pixel shader:
float4 main( InData in, uniform sampler2D tex1, uniform sampler2D tex2 ) {
return ( float4 )tex2D( tex1, in.texCoord0 ) + ( float4 )tex2D( tex2, in.texCoord0 );
}
Este anterior shader NECESITA dos unidades de textura.
float4 main( InData in, uniform sampler2D tex1, uniform float4 textureFactor ) {
return ( float4 )tex2D( tex1, in.texCoord0 ) + textureFactor;
}
Y este utiliza UNA unidad de textura y ADEMAS tiene una constante que, en este caso, es el textureFactor.
Se me acaba de ocurrir... pienso que si va por este camino, esta claro que una stage NO equivale a una unidad de textura.
Saludoteeees!
glColor4f (1.0f, 1.0f, 1.0f, 0.5f);
glCallList (displayList);
Usa Material, y prepara el SetRenderSatge, para que te lo tenga encuenta, en lugar del color independiente de cada vertice.
PD: Por que sacais el tema de las texturas!? :blink: :ph34r:
Sigo pensando que es mas facil con el TextureFactor...
Yo uso el texture factor y va genial... será que todavía no me he metido con vs y ps.. como berserker.. pero todo llega.
Un saludo
PD: si usas el stage 0 y 1... a la vez es multitextura como por ejemplo..
SetTextureStageState(0, COLOR_OP, Select_arg_1)
SetTextureStageState(0, COLOR_ARG1, D3DTA_TEXTURE)
SetTextureStageState(1, COLOR_OP, MODULATE)
SetTextureStageState(1, COLOR_ARG1, D3DTA_TEXTURE)
SetTextureStageState(1, COLOR_ARG2, D3DTA_CURRENT)
m_pDevice->SetTexture(0, pTexture1);
m_pDevice->SetTexture(1, pTexture2);
.....................
Ajá, gracias a todos.
¿Sabe alguien como averiguar cuantas "stages" simultaneas por superficie soporta una tarjeta dada?
PD
Mchiz no me he enterao de tu post :blink: :
Citar
Me pareceria demasiado raro ( y bonito ;b ). Pensemoslo como si fuese un pixel shader:
...
Es que no sé nada de shaders... ¿cuál es la conclusión a la que llegas?
Lo que quiere decir es que sería genial que uno pudiera utilizar todos los stages que quisiera (digamos 16) y si la aceleradora sobre la que corre el programa tiene menos de 16 unidades de textura, el API se encargaría de separar los stages y dar tantas pasadas como fuese necesario. Evidentemente eso ahora mismo no es posible de forma que le toca a uno mismo dar tantas pasadas como sea necesario.
Me parece recordar que Carmack hablaba de que algún día eso será posible...
Y para saber cuántas texturas simultaneas puedes utilizar, creo recordar que te lo decía el flag MaxSimultaneousTextures de las Caps de Direct3D.
Saludos.
Cita de: "Loover"Es que no sé nada de shaders... ¿cuál es la conclusión a la que llegas?
Ah bueno, si te referías a qué intentaba explicar MChiz con el pixel shader que ha puesto...
Lo que estaba tratando de demostrar es que aunque hagamos la operación Texture * Diffuse * TextureFactor utilizando dos stages, si la fixed pipeline sigue el mismo criterio que el pixel shader, cuando estamos utilizando el stage en el que entra en juego el TextureFactor (en el ejemplo de MChiz, el stage 1), realmente no se está ocupando un registro de textura ya que en realidad TextureFactor sería una constante que se le pasa al pixel shader.
En definitiva, que si la fixed pipeline sigue la misma lógica que el pixel shader, aunque estés utilizando dos stages, en realidad no estás utilizando dos unidades de textura por lo que en teoría, con una aceleradora sin soporte para multitextura, debería funcionar.
Saludos.
Exacto. Lo que dice Berserker es lo que intentaba demostrar : )
Ah, y por eso decía MChiz que parecía como que Direct3D se encargaba sola de dar las pasadas si era necesario... lo que en realidad ocurría es que no estaba utilizando más registros de textura de los necesarios, sino la cte esa.
Ok, gracias, ahora lo entiendo (más o menos, pq nunca me he metido con shaders).
PD:
Por cierto, los shaders me recuerda un montón a asm... registros, etc. No parecen tan difíciles como pensaba.
Cita de: "Loover"Por cierto, los shaders me recuerda un montón a asm... registros, etc. No parecen tan difíciles como pensaba.
Cierto, pero si utilizas un lenguaje de alto nivel como HLSL (si usas Direct3D) o Cg, te resultará aún más sencillo.
Saludos.
Bueno, he vuelto con esto. En su tiempo probé el entintado y funcionaba bien. Sinembargo tengo problemas con el alpha:
Por un lado tengo este formato de vértice:
// Formato del vértice
struct CUSTOMVERTEX2D
{
// Posición
float mX, mY, mZ;
// Coordenadas de textura
float mU, mV;
};
#define D3DFVF_CUSTOMVERTEX2D (D3DFVF_XYZ | D3DFVF_TEX1)
Y luego al dibujar:
mRender->GetDevice()->SetRenderState (D3DRS_ALPHABLENDENABLE, TRUE);
mRender->GetDevice()->SetRenderState (D3DRS_TEXTUREFACTOR, D3DCOLOR_COLORVALUE (1.0f, 1.0f, 1.0f, 0.5f));
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_COLOROP, D3DTOP_MODULATE);
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
Si en el color pongo un rojo por ejemplo, la imagen se tinta de ese color. Sinembargo, si intento que la imagen apareza "medio transparente" (con un valor alpha 0.5f) se lo pasa por el pito del sereno y la dibuja normal y corriente. La textura sinembargo está creada con RGBA (A8R8G8B8).
¿Seguro que se puede hacer lo de cambiar el alpha sin lockear el vertex buffer?
¿Qué estoy haciendo mal?
Un saludo
No estoy muy seguro, pero no tienes que tocar algo del ALPHAOP? No he probado esto nunca, asi que si digo una chorrada, que salte el que quiera :b
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
Imagino que esto te multiplicara el alpha de la textura por el del TextureFactor. Si no quieres usar el alpha de la textura y asi tener la imagen en RGB8 para ocupar menos memoria, prueba con:
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
mRender->GetDevice()->SetTextureStageState (0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
Ya me diras que tal ha ido : )
Sip, tb había probado eso, lo había visto "rebuscando" por la ayuda. Pero nada.
Tengo fundadas sospechas de que no hay más remedio que lockear el buffer. Por lo menos en el Special Effects lo hace así. Pero claro este libro esta basado en dx 8.1 y quería ver si había alguna otra forma...
Aunque en la ayuda, sección "Texture Alpha" sale un ejemplo de una esfera semitransparente y lo hacen sin lockear, de la manera que tu has dicho y estaba probando. No sé que estoy haciendo mal.
Hey sí! Claro que funciona, solo que se me había olvidado poner esto:
mRender->GetDevice()->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
mRender->GetDevice()->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
;)
Por cierto, haciendo pruebas he visto como hacer un fade to color. Utilizando D3DTOP_BLENDFACTORALPHA (uoh)
Gracias!
Ole! Me alegro que lo hayas conseguido! : )
A que te refieres con un 'fade to color'??
Sip, ir cambiando progresivamente de la imagen a un color dado. Por ejemplo completamente rojo.
Lo normal son fades a negro o a blanco, y a pantalla completa. Pero bueno, ya que puedo dar la posibilidad por imagen tb bienvenida sea. Eso sí, con cuidado de solo activarla si el usuario le da valores R, G, B.
Un saludo!