Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Problemas con el canal Alpha al intentar efecto en textura

Iniciado por [EX3], 10 de Enero de 2008, 10:51:24 AM

« anterior - próximo »

[EX3]

Wenas.

Estos dias he estado retomando unos deberes que me deje guardado para ultimo momento en el apartado grafico de la dx_lib32 y estos son intentar aplicar ciertos efectos de modificacion de color en texturas sin usar shaders: invertir colores, exclusion y conversion a escala de grises.

La inversion de color la he logrado pero con el inconveniente de que siempre le aplica traslucencia como si se le aplicara opacidad aditiva (render states srcblend=zero y destblend=invsrccolor) y la exclusion la aplica sin problemas (render states srcblend=invdestcolor y destblend=invsrccolor). El problema lo tengo en la forma de aplicar la conversion a escala de grises. Despues de patearme medio google he visto que en muchos sitios lo hacen aplicando dotProduct3 a la textura con el factor de conversion de color a escala de gris.

El asunto es que al igual que con la inversion de color y la exclusion lo aplica con una traslucencia en plan aditivo (resultado innesperado pero posiblemente util en otros usos) e invirtiendo los colores en la conversion a grises (esto lo he solucionado re-invirtiendo los colores con srcblend=zero y destblend=invsrccolor). El problema en si es que la informacion del canal alpha en texturas PNG se come, pintando las zonas transparentes como solidas, en este caso en negro y me fastidia el invento para usarlo en sprites (la idea era usarlo a nivel global).

El codigo que aplico es el siguiente:
D3DDevice.SetRenderState D3DRS_TEXTUREFACTOR, D3DColorMake(0.299, 0.587, 0.114, 1.0)
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
D3DDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG2, D3DTA_TFACTOR
D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_ZERO
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR

He probado cambiando destblend=invsrcalpha y los estados de textura a D3DTSS_ALPHAOP y D3DTSS_ALPHAARGn  en vez de D3DTSS_COLOROP y D3DTSS_COLORARGn y no logro los resultados esperados (hace un invertido de colores en solido pero no aplica escala de grises).

Notese que no ando muy puesto en temas de estados de textura y de renderizados (este ultimo lo justo) y sus combinaciones por lo que posiblemente este metiendo la pata hasta el fondo en algun detalle que desconozco.

En caso de ir por mal camino, existe otra forma que no sea mediante shaders de este efecto "basico"? De ser mediante los estados de textura y renderizado, cual seria la combinacion es correcta para lograr este efecto o aproximacion al mismo?

Gracias.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

Pasa que estas meando fuera del tarro.

srcblend y destblend dicen como se va a mezclar el resultado del shader con lo que hay en pantalla.

Si quieres que ande el canal alpha tienes que si o si poner:
srcblend = alpha y destblend = one_minus_alpha

o si lo premultiplicas por el canal alpha:
srcblend = one y destblend = one_minus_alpha

Para hacer la escala de grises, como dices usas el dot3 pero al canal alpha lo debes dejar intacto.

Otro problema es que no todas las placas tienen dot3 para ese caso lo que puedes hacer es una primera pasada modulado en negro, luego habilitas solo la escritura de cada canal y pones el blending en suma y premultiplicando por alpha y por la constante de cada canal haces las tres pasadas.

Para la inversion de color tienes dos opciones:
1 - Invertir el color en el shader y dejar el alpha tal cual.
2 - Invertir el color en el blending y premultiplicar ek color en el shader pero dejando el canal alpha tal cual.

Saludos

[EX3]

Cita de: "Pogacha"Pasa que estas meando fuera del tarro.
Con razon me estaba salpicando je :D

Cita de: "Pogacha"Si quieres que ande el canal alpha tienes que si o si poner:
srcblend = alpha y destblend = one_minus_alpha
(...)
o si lo premultiplicas por el canal alpha:
srcblend = one y destblend = one_minus_alpha
Cual constante es "one_minus_alpha"? Tal que asi no esta documentada en DirectX:
Cita de: "CONST_D3DBLEND"D3DBLEND_ZERO            =  1
   D3DBLEND_ONE             =  2
   D3DBLEND_SRCCOLOR        =  3
   D3DBLEND_INVSRCCOLOR     =  4
   D3DBLEND_SRCALPHA        =  5
   D3DBLEND_INVSRCALPHA     =  6
   D3DBLEND_DESTALPHA       =  7
   D3DBLEND_INVDESTALPHA    =  8
   D3DBLEND_DESTCOLOR       =  9
   D3DBLEND_INVDESTCOLOR    = 10
   D3DBLEND_SRCALPHASAT     = 11
   D3DBLEND_BOTHSRCALPHA    = 12
   D3DBLEND_BOTHINVSRCALPHA = 13
D3DBLEND_INVSRCALPHA quizas?

Cita de: "Pogacha"Otro problema es que no todas las placas tienen dot3 para ese caso lo que puedes hacer es una primera pasada modulado en negro, luego habilitas solo la escritura de cada canal y pones el blending en suma y premultiplicando por alpha y por la constante de cada canal haces las tres pasadas.
Aqui me he quedado un poco perdido. Seria pintar 3 veces la misma textura cambiando los render states y render textures o se puede en la misma pasada cambiando los estados usando multitextura (diferentes stages)?

Cita de: "Pogacha"Para hacer la escala de grises, como dices usas el dot3 pero al canal alpha lo debes dejar intacto.
Supongo que dices de desactivar el estado de render del alphablending. Si es haciendo multiples pasadas bajo multitextura en una de las pasadas deberia poder reactivar el alphablending ya que el objetivo que busco es poder modular la opacidad o transparencia mediante canal alpha del color. Es posible o es incompatible?

Por cierto, cuando te refieres a "shaders" supongo que te refieres a la operacion que se genera mediante la combinacion de estados, por que programacion a bajo nivel de shaders como tal no estoy aplicando (lo que viene a ser comun a dia de hoy, un bloque de codigo, un pixel shader).

Salu2...

P.D.: Webs o articulos que conozcais y que traten el tema en detalle? Todo lo que he encontrado ha sido en su mayoria entradas de foros donde lo trataban con pinzas el asunto de la escala de grises y ninguno concreto sobre la inversion de colores.
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

D3DBLEND_INVSRCALPHA quizas?
Si, one_minus_src_alpha es de openGL :P

Aqui me he quedado un poco perdido. Seria pintar 3 veces la misma textura cambiando los render states y render textures o se puede en la misma pasada cambiando los estados usando multitextura (diferentes stages)?
No, aqui me equivoque yo, en OpenGL puedes cambiar el origen y destino de los canales pero tiene menos disponibilidad que el Dot3.
Dot3 es a partir de GeForce2 y Ati9200 asi que no es para tanto, incluso antes ya habia, practicamente fue el paso siguiente que agregaron las placas despues de la multitextura.

Para invertir el color te diria que pruebes con:
CitarD3DDevice.SetTextureStageState 0, D3DTSS_COLORARG1, (D3DTA_TEXTURE Or D3DTA_COMPLEMENT)
D3DDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
D3DDevice.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE
D3DDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1
D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA

[EX3]

Hey, genial, funciono a la perfeccion :D Le hice una ligera modificacion y he logrado poder graduar por el canal alpha del color de los vertices:
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG1, (D3DTA_TEXTURE Or D3DTA_COMPLEMENT)
                                   D3DDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
                                   D3DDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE
                                   D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
                                   D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA

Funciona de maravillas, mil gracias :D

He estado tambien intentado aplicar tu codigo a la implementacion de conversion a escala de grises pero no logro combinacion adecuada para que me respete el canal alpha de la textura. Lo mas que he logrado ha sido que respete el alpha pero el resultado es que dibuja la silueta "visible" de la textura en blanco :? Mañana seguire intentandolo con mas calma.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

Sobre la escala de grises, en teoria seria así:

Primera pasada:

D3DDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_DISABLE
D3DDevice.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE
D3DDevice.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1

D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_ZERO
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA


Segunda pasada:
D3DDevice.SetRenderState D3DRS_TEXTUREFACTOR, D3DColorMake(0.299, 0.587, 0.114, 1.0)
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG1, D3DTA_TEXTURE
D3DDevice.SetTextureStageState 0, D3DTSS_COLOROP, D3DTOP_MODULATE
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG2, (D3DTA_TEXTURE Or D3DTA_ALPHAREPLICATE)

D3DDevice.SetTextureStageState 1, D3DTSS_COLORARG1, D3DTA_CURRENT
D3DDevice.SetTextureStageState 1, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3
D3DDevice.SetTextureStageState 1, D3DTSS_COLORARG2, D3DTA_TFACTOR

D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_ONE
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_ONE


Luego me cuentas ...

Loover

Oye, pues conforme vayas consiguiendo resultados (inversión de color, borde del sprite, escala de grises, etc), podrías ir poniendo el código y el resultado del sprite. Me parece algo muy útil.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

[EX3]

Lo de las pasadas me confunde un poco, pensaba que eso era lo de aplicar estados en diferentes stages de una textura (multitextura). Se supone que deberia dibujar dos veces la textura, una con los primeros estados, y otra con los estados en los dos stages de la textura?

Cita de: "Loover"Oye, pues conforme vayas consiguiendo resultados (inversión de color, borde del sprite, escala de grises, etc), podrías ir poniendo el código y el resultado del sprite. Me parece algo muy útil.
Por supuesto :) De momento ahi tienes la de inversion de colores que hizo Pogacha con la modificacion para modular por el alpha del color de vertice que funciona a las mil maravillas. Lo del borde del sprite, te refieres a sacar el contorno solido?

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

Si, lamentablemente tendrás que dibujarlo dos veces, si no utilizas shaders el muy maldito Dot3 se propaga a todos los canales incluido el canal alpha. Es algo que no está especificado muy claramente en el SDK.
Leelo un poco:
http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dx81_c/directx_cpp/Graphics/Reference/CPP/D3D/Enums/d3dtextureop.asp
CitarD3DTOP_DOTPRODUCT3
   Modulate the components of each argument as signed components, add their products; then replicate the sum to all color channels, including alpha. This operation is supported for color and alpha operations.

   In DirectX 6.0 and 7.0 multitexture operations the above inputs are all shifted down by half (y = x - 0.5) before use to simulate signed data, and the scalar result is automatically clamped to positive values and replicated to all three output channels. Also, note that as a color operation this does not updated the alpha it just updates the rgb components.

   However, in DirectX 8.1 shaders you can specify that the output be routed to the .rgb or the .a components or both (the default). You can also specify a separate scalar operation on the alpha channel.

La unica solucion que encontre es hacer el blending en 2 etapas, primero el fondo*=(1-alpha) y luego +=(alpha*color) Dot3 ConstanteGris
En teoria debe andar la desgracia es que tienes que dibujar dos veces el quad para que funcione.

[EX3]

Vale. He dibujado primero la textura con el primer bloque de estados que has puesto y despues vuelvo a dibujar superpuesto la misma textura con el segundo bloque y activando el stage 1 de la textura. El resultado es que se ve en escala de grises invertido y sin respetar el alpha:



El verde que se ve en la primera captura forma parte del fondo de renderizado (en el momento de borrar) y no de la textura.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

Que te dibuja si solo haces la primera pasada?
En teoria deberia ser la sombra del dibujo tan solo.

[EX3]

Me dibuja la textura integra en negro, sin respetar alpha tampoco.

Estos son los resultados por separado de cada pasada:


Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Pogacha

En la primera pasada no deberia hacer eso, prueba a poner los render states del pipeline por defecto y deja los states del blending, cersiorate de estar desactivando el segundo stage para la primera pasada.

No se por que pero en la segunda pasada te esta invirtiendo el color.
Prueba a cambiar esto.
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG2, (D3DTA_TEXTURE Or D3DTA_ALPHAREPLICATE Or D3DTA_COMPLEMENT)

senior wapo

Una vez limpiado el fondo a negro en el interior del área que ocupará el sprite, lo mismo te da usar para la segunda pasada blend aditivo que imodular con invsrcalpha.

Una vez tengas arreglada la primera pasada, prueba en la segunda pasada con:

D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA


En teoría debería dar igual pero tú prueba.

[EX3]

Cita de: "Pogacha"En la primera pasada no deberia hacer eso, prueba a poner los render states del pipeline por defecto y deja los states del blending, cersiorate de estar desactivando el segundo stage para la primera pasada.
Desactive todos los renderstates que inicializa dx_lib32 excepto los de blending de esta pasada (SrcBelnd=Zero e DestBlend=InvSrcAlpha) y ahora sale en blanco en vez de negro :?

Cita de: "Pogacha"No se por que pero en la segunda pasada te esta invirtiendo el color.
Prueba a cambiar esto.
D3DDevice.SetTextureStageState 0, D3DTSS_COLORARG2, (D3DTA_TEXTURE Or D3DTA_ALPHAREPLICATE Or D3DTA_COMPLEMENT)
Lo de la inversion de color es normal por lo que decian aqui, que es donde empece a hacer pruebas con el DotProduct3. He añadido el flag para la inversion y se ve que en combinacion de AlphaReplicate hace un efecto algo extraño:

No se aprecia apenas pero como que difumina los pixeles de la textura con el fondo.

Cita de: "senior wapo"Una vez limpiado el fondo a negro en el interior del área que ocupará el sprite, lo mismo te da usar para la segunda pasada blend aditivo que imodular con invsrcalpha.
Antes de nada quiero asegurarme. Asi en pseudocodigo seria como estoy implementando el asunto de las pasadas, por si resulta que estoy haciendo algo mal:
   // Pasada 1
   SetTextureStageRender(0, D3DTSS_COLOROP, D3DTOP_DISABLE)
   SetTextureStageRender(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE)
   SetTextureStageRender(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1)

   SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO)
   SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA)

   SetTexture(0, Textura)
   DibujoTextura()

   // Pasada 2
   SetRenderState(D3DRS_TEXTUREFACTOR, D3DColorMake(0.299, 0.587, 0.114, 1.0)
   SetTextureStageRender(0, D3DTSS_COLORARG1, D3DTA_TEXTURE)
   SetTextureStageRender(0, D3DTSS_COLOROP, D3DTOP_MODULATE)
   SetTextureStageRender(0, D3DTSS_COLORARG2, (D3DTA_TEXTURE Or D3DTA_ALPHAREPLICATE))
                                   
   SetTextureStageRender(1, D3DTSS_COLORARG1, D3DTA_CURRENT)
   SetTextureStageRender(1, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3)
   SetTextureStageRender(1, D3DTSS_COLORARG2, D3DTA_TFACTOR)
                                   
   SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE)
   SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE)

   SetTexture(0, Textura)
   SetTexture(1, Textura)
   DibujoTextura()

A ver si es que lo estoy haciendo mal y por eso los resultados no son los esperados.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.