Wenas, despues de activar el Z-Buffer en D3D estuve haciendo pruebas y ya consegui suplantar la interfaz D3DXSprite por un sistema de quads aunque solo me falta el detalle de como definir una porcion de textura que dibujar, pero eso ya es otro asunto aparte.
Estuve haciendo pruebas con el Z-Buffer y he descubierto algo que me ha fastidiado el tema por completo y es que fallan las transparencias segun la profundidad. Como no se explicarlo de forma que se entienda bien he subido el ejemplo compilado y con su codigo fuente incluido para que veais por vuestra cuenta a que me refiero y de paso me digais si esto es normal o no.
Prueba_Z-Buffer.zip - 36.7kb
El codigo del programa es el siguiente:
Option Explicit
Dim Dx As DirectX8
Dim D3D As Direct3D8
Dim D3DDevice As Direct3DDevice8
Dim bRunning As Boolean
Const FVF = D3DFVF_XYZRHW Or D3DFVF_TEX1 Or D3DFVF_DIFFUSE Or D3DFVF_SPECULAR
Private Type TLVERTEX
X As Single
Y As Single
Z As Single
rhw As Single
Color As Long
specular As Long
tu As Single
tv As Single
End Type
Dim D3DX As D3DX8
Dim Texture As Direct3DTexture8
Dim TransTexture As Direct3DTexture8
Dim mX As Single, mY As Single 'Posicion del raton.
Dim mA As Single 'Contador para el angulo del sprite.
Private Declare Function GetTickCount Lib "kernel32" () As Long
Dim LastTimeCheckFPS As Long
Dim FramesDrawn As Long
Dim FrameRate As Long
Dim Mode As Boolean
Public Function Initialise() As Boolean
On Error GoTo ErrHandler:
Dim DispMode As D3DDISPLAYMODE
Dim D3DWindow As D3DPRESENT_PARAMETERS
Set Dx = New DirectX8
Set D3D = Dx.Direct3DCreate()
Set D3DX = New D3DX8
D3D.GetAdapterDisplayMode D3DADAPTER_DEFAULT, DispMode
D3DWindow.Windowed = 1
D3DWindow.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC
D3DWindow.BackBufferFormat = DispMode.Format
D3DWindow.BackBufferHeight = 480 '//form.Height = 7590
D3DWindow.BackBufferWidth = 640 '//form.Width = 9675
D3DWindow.hDeviceWindow = frmMain.hWnd
D3DWindow.EnableAutoDepthStencil = 1
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16
Set D3DDevice = D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, frmMain.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DWindow)
D3DDevice.SetVertexShader FVF
D3DDevice.SetRenderState D3DRS_LIGHTING, False
D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA
D3DDevice.SetRenderState D3DRS_ALPHABLENDENABLE, True
D3DDevice.SetTextureStageState 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR
D3DDevice.SetTextureStageState 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR
D3DDevice.SetRenderState D3DRS_ZENABLE, 1
D3DDevice.SetRenderState D3DRS_ZWRITEENABLE, 0
Set Texture = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\logo.bmp", 50, 50, _
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, _
D3DPOOL_MANAGED, D3DX_FILTER_POINT, _
D3DX_FILTER_POINT, &HFF00FF00, _
ByVal 0, ByVal 0)
Set TransTexture = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\soldier.png", 131, 185, _
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, _
D3DPOOL_MANAGED, D3DX_FILTER_POINT, _
D3DX_FILTER_POINT, &HFF00FF00, _
ByVal 0, ByVal 0)
Initialise = True
Exit Function
ErrHandler:
Initialise = False
End Function
Public Sub Render()
D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &HFF0000FF, 1#, 0
D3DDevice.BeginScene
mA = mA + 0.1
If mA > 359.9 Then mA = 0
If Mode Then
Me.Tag = "ZBuffer = ON"
D3DDevice.SetRenderState D3DRS_ZWRITEENABLE, 1
'Dibujamos los quads definiendo su orden por su coordenada Z:
Call BlitFX(Texture, 200, 20, 0, 200, 200, 0, 0, &HFFFFFFFF, 0, False)
Call BlitFX(Texture, 0, 0, 0, 200, 200, 0, 0, &HFFFF7700, 2, False)
Call BlitFX(TransTexture, CLng(mX), CLng(mY), 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
Call BlitFX(TransTexture, CLng(mX) + 50, CLng(mY) + 50, 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
Call BlitFX(TransTexture, CLng(mX) + 100, CLng(mY) + 100, 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
Else
Me.Tag = "ZBuffer = OFF"
D3DDevice.SetRenderState D3DRS_ZWRITEENABLE, 0
'Dibujamos los quads por orden de profundidad:
Call BlitFX(TransTexture, CLng(mX) + 100, CLng(mY) + 100, 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
Call BlitFX(Texture, 200, 20, 0, 200, 200, 0, 0, &HFFFFFFFF, 0, False)
Call BlitFX(TransTexture, CLng(mX) + 50, CLng(mY) + 50, 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
Call BlitFX(Texture, 0, 0, 0, 200, 200, 0, 0, &HFFFF7700, 2, False)
Call BlitFX(TransTexture, CLng(mX), CLng(mY), 0, 185, 131, mA, 0, &HFFFFFFFF, 0, True)
End If
D3DDevice.EndScene
D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
If GetTickCount - LastTimeCheckFPS >= 1000 Then
LastTimeCheckFPS = GetTickCount
FrameRate = FramesDrawn
FramesDrawn = 0
Me.Caption = "DirectX-Graphics: {" & FrameRate & "fps}" & " {Pulsar 1 > Z-Buffer = ON / 2 > Z-Buffer = OFF: " & Me.Tag & "}"
End If
FramesDrawn = FramesDrawn + 1
End Sub
Private Sub Form_Click()
bRunning = False
End Sub
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKey1 Then Mode = True Else If KeyCode = vbKey2 Then Mode = False
End Sub
Private Sub Form_Load()
Me.Show
bRunning = Initialise()
Do While bRunning
Render
DoEvents
Loop
On Error Resume Next
Set D3DDevice = Nothing
Set D3D = Nothing
Set Dx = Nothing
Unload Me
End
End Sub
Private Function CreateTLVertex(X As Single, Y As Single, Z As Single, rhw As Single, Color As Long, specular As Long, tu As Single, tv As Single) As D3DTLVERTEX
CreateTLVertex.sx = X
CreateTLVertex.sy = Y
CreateTLVertex.sz = Z
CreateTLVertex.rhw = rhw
CreateTLVertex.Color = Color
CreateTLVertex.specular = specular
CreateTLVertex.tu = tu
CreateTLVertex.tv = tv
End Function
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
mX = X
mY = Y
End Sub
Private Sub BlitFX(Texture As Direct3DTexture8, X As Long, Y As Long, Optional Z As Single = 0, Optional Height As Long = 64, Optional Width As Long = 64, Optional Angle As Single, Optional AlphaBlendMode As Long, Optional Color As Long = -1, Optional Mirror As Long, Optional Center As Boolean)
On Error GoTo ErrOut
Const PI As Single = 3.14159265358979
Dim Quad(3) As D3DTLVERTEX
Dim vX As Long, vY As Long, tX As Long, tY As Long, tu(3) As Single, tv(3) As Single
'Generamos el poligono:
If Center Then
X = X - (Width / 2)
Y = Y - (Height / 2)
End If
Select Case Mirror
Case 0 'Normal
tu(0) = 0: tv(0) = 1
tu(1) = 0: tv(1) = 0
tu(2) = 1: tv(2) = 1
tu(3) = 1: tv(3) = 0
Case 1 'Horizontal
tu(0) = 0: tv(0) = 0
tu(1) = 0: tv(1) = 1
tu(2) = 1: tv(2) = 0
tu(3) = 1: tv(3) = 1
Case 2 'Vertical
tu(0) = 1: tv(0) = 1
tu(1) = 1: tv(1) = 0
tu(2) = 0: tv(2) = 1
tu(3) = 0: tv(3) = 0
Case 3 'Horizontal/Vertical
tu(0) = 1: tv(0) = 0
tu(1) = 1: tv(1) = 1
tu(2) = 0: tv(2) = 0
tu(3) = 0: tv(3) = 1
End Select
tX = -Width / 2
tY = -Height / 2
vX = tX * Cos(-Angle * PI / 180) + tY * -Sin(-Angle * PI / 180)
vY = tX * Sin(-Angle * PI / 180) + tY * Cos(-Angle * PI / 180)
Quad(0) = CreateTLVertex(vX + Width / 2 + X, -vY + Height / 2 + Y, Z, 1, Color, 0, tu(0), tv(0))
tX = -Width / 2
tY = Height / 2
vX = tX * Cos(-Angle * PI / 180) + tY * -Sin(-Angle * PI / 180)
vY = tX * Sin(-Angle * PI / 180) + tY * Cos(-Angle * PI / 180)
Quad(1) = CreateTLVertex(vX + Width / 2 + X, -vY + Height / 2 + Y, Z, 1, Color, 0, tu(1), tv(1))
tX = Width / 2
tY = -Height / 2
vX = tX * Cos(-Angle * PI / 180) + tY * -Sin(-Angle * PI / 180)
vY = tX * Sin(-Angle * PI / 180) + tY * Cos(-Angle * PI / 180)
Quad(2) = CreateTLVertex(vX + Width / 2 + X, -vY + Height / 2 + Y, Z, 1, Color, 0, tu(2), tv(2))
tX = Width / 2
tY = Height / 2
vX = tX * Cos(-Angle * PI / 180) + tY * -Sin(-Angle * PI / 180)
vY = tX * Sin(-Angle * PI / 180) + tY * Cos(-Angle * PI / 180)
Quad(3) = CreateTLVertex(vX + Width / 2 + X, -vY + Height / 2 + Y, Z, 1, Color, 0, tu(3), tv(3))
'Pintamos el poligono con la textura:
Select Case AlphaBlendMode
Case 1 'Efecto Glow:
D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_ONE
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_ONE
Case 2 'Efecto Inverso:
D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR
End Select
D3DDevice.SetTexture 0, Texture
D3DDevice.SetTextureStageState 0, D3DTSS_MIPFILTER, 3
D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 2, Quad(0), Len(Quad(0))
Exit Sub
ErrOut:
End Sub
Salu2...
Pues no puedo bajar el .zip, de todas formas creo que se lo que pasa por lo que dices, es algo muy tipico y que cuando se toca por primera vez puede llamar la atencion.
Has de dejar los poligonos trasparentes para renderizar al final, y dependiendo de el tipo de trasparencia puede ser necesario que los ordenes de tal forma, que primero se pinten los mas lejanos y termines por el mas proximo.
Saludos.
A _Grey se le ha olvidado decir que cuando pintes los sprites transparentes al final de todo, si no los tienes ordenados por distancia, debes desactivar la escritura del Z-Buffer.
Si miras a través de una ventana que es un polígono con alpha y la pintas lo primero, escribirá el z buffer y todo lo que pintes al otro lado será descartado el hacer el Z test, por eso hay que desactivarlo.
He subido el zip al server de mi web, desde ahi si os deberia dejar bajarlo sin problemas:
Prueba_Z-Buffer.zip - 36.7 kb
Aun asi he sacado dos capturas para que veais exactamente a lo que me refiero y que parece ser lo que me comentais:
(http://usuarios.lycos.es/vhd/ex3/ZOFF.gif)
En esta el zbuffer esta desactivado y dibujo los quads segun el orden de dibujo.
(http://usuarios.lycos.es/vhd/ex3/ZON.gif)
En esta el zbuffer esta activado y dibujo los quads sin orden de dibujo. Aplico el orden de dibujo mediante la coordenada Z.
Mi unica intencion de usar el Z-Buffer era poder olvidarme de tener que dibujar los graficos por orden, pudiendo asi pintar por partes y asignado su profundidad mediante la coordenada Z y hasta que probe lo de la transparencia todo iba por buen camino.
Salu2...
Ahora si pude ver el programa, y tiene toda la pinta de ser lo que comentamos Thenend y yo.
Tambien se puede aplicar una especie de colorKey por alpha, para ver mas sobre esto mira el parametro D3DRS_ALPHATESTENABLE de SetRenderState. De todas formas podria siguir dando problemas en los bordes visibles del sprite, me temo que tendras que ordenar.
Saludos.
Como bien dicen, si quieres utilizar alpha blending tendrás que renderizar de atrás hacia adelante. El problema que estás teniendo es precisamente por el orden incorrecto de render.
Por ejemplo, si cogemos el soldado que está delante de todos, ves que se mezcla bien con el sprite de DX. Eso es porque dicho sprite se renderizó antes que el soldado por lo que la operación de mezcla lo tuvo en cuenta. Pero ahora vemos que no se mezcla bien con el segundo soldado. Eso es porque dicho sprite se renderizó después que el primer soldado por lo que cuando Direct3D fue a calcular la mezcla al renderizar el primer soldado, los pixels que entraban en juego eran el del sprite y el del color actual del frame buffer que en este caso es el azul y no el del segundo soldado (ya que éste se renderizó después).
La otra opcion es, como ha dicho _Grey, utilizar alpha testing. En ese caso no necesitarías ordenar pero los bordes del sprite no te saldrán tan suavizados como con el alpha blending. Aunque es posible que puedas utilizar conjuntamente alpha testing y alpha blending y solucionar ambos problemas, pero de esto no estoy seguro.
Saludos.
Si tengo que ordenar me deja mi idea por los suelos, para eso prefiero quitar el z-buffer y hacerme unos arrays donde almaceno los parametros de los quads y textura asociada y me hago una lista de ordenacion, aunque no se como saldra el experimento.
[edit] Acabo de probar lo del alphatesting y cierto, ahora si funciona correctamente excepto por el borde de las texturas, que se difumina. Bueno, ya probe hacer lo de la lista de ordenacion y ya tengo una salida por si no logro solucionar del todo el tema del z-buffer :)
Salu2...
Usar el z-buffer acelerará las cosas; asi que si puedes, usalo.
Respecto a usar color-keying, ten en cuenta que no te valdra cuando quieras dibujar un sprite parcialmente transparente.
No se si es normal lo que me paso anoche a ultima hora, cuando hice la prueba del alphatest para lo del z-bufffer me dio por cambiar unas opciones de los drivers de mi tarjeta para forzar un poco mas los fps al programa, entre ellos el antialiasing, que lo puse a 2x y resulta que eso me anulaba el z-buffer en el programa. Deberia ocurrir tal cosa o es pirada de olla de mis drivers? :blink:
Salu2...