Texture Fading Problem

Blitz3D Forums/Blitz3D Programming/Texture Fading Problem

jfk EO-11110(Posted 2010) [#1]
Howdy all. Is there any B3D Guru out there who knows a trick to fade between two textures on an animated mesh? I need to be able to fade between 5 textures, so any of these should be able to fade to any other one of these.

I have tried and evaluated several methods so far.

-Preredered tween textures eat too much memory, so this is not an option (it multiplies the vram needs by 6, even with only one tween frame, no way).

-Using the alpha channel of the texels of a 2nd texture layer: is too slow (writepixelfast...Vram Bottleneck problem)

-creating a clone of the wanted surface and parent it to the original mesh: new surface is not bound to the original bones, and since it's animated B3D, even if I parent it to the bone/pivot, the vertices are still not weighted the same way.

-I tried to AddMesh the new Surface that I just described to the original mesh, but for some reason it vanishes. Probably I just cannot see it because it's using the same brush, and maybe due to surface count optimation by the system the new surface is unified with the old one. I used Brushcolor to make the new surfaces brush special - to prevent the fusion, but this didn't work. I have a slight suspect that BrushColor is the one Command that does not prevent Surface Fusion of identic Brushes when AddMesh-ing things, unlike eg. BrushAlpha or so. Still got to check that later, however.

So, is there anybody who has an idea on how to smoothly fade from one texture to another, on a surface of an animated mesh?

Thanks.


Rroff(Posted 2010) [#2]
2 quads normally invisible - with the current and fade to textures - hide main world/camera show the quads on screen - probably using the orthos camera mode - and set the entity alpha appropriatly - copyrect into a texture thats applied to the model, hide the quads again and switch back to the world view for flip?


OJay(Posted 2010) [#3]
a few months ago, i prototyped successfully an animated fade from one texture to another through an animated alphalayer...depending on the duration and speed of the fade you need, you may have to create quite a lot of frames though...

anyway, this is the alphalayer i used (pretty much coder art, shopped together in 5mins or so...):


the code to use it (used fastext, but may be possible without):
CaptureFadeTexture = LoadAnimTexture( "textures\capture_fade.png", 1+2, 128,128, 0,10 )
basetexture = LoadTexture ("textures\entities\vehicles\buggy\buggy_neutral.dds")
teamtexture = LoadTexture ("textures\entities\vehicles\buggy\buggy_yellow.dds")

cub4=LoadMesh("meshes\entities\vehicles\buggy\buggy_chassis.b3d")

TextureBlend CaptureFadeTexture,FE_ALPHAMODULATE
TextureBlend teamtexture ,FE_ALPHACURRENT

EntityTexture cub4,basetexture ,0,0
EntityTexture cub4,CaptureFadeTexture,0,1
EntityTexture cub4,teamtexture ,0,2


in the mainloop as usual:
frame = (frame + (KeyDown(KEY_ARROW_RIGHT)-KeyDown(KEY_ARROW_LEFT)))
EntityTexture cub4,CaptureFadeTexture,frame,1


result looks like this:


you could make it smoother by creating more alpha layer fade frames...

maybe its of any use for you...


jfk EO-11110(Posted 2010) [#4]
Rroff - thanks - tho I kind of don't understand it :). It sounds rather complicated, and with the Copyrect it may also be rather slow. What makes copyrect to texturebuffers so slow is when they don't use the flag 256. But even with this flag it is still rather slow. You easily hit the limit, gameplaywise.

OJay - as far as I see you are using prerendered Frames. This would of course be an option. But I have 5 Textures, and let's say I want 3 tweenframes then I'd need to load 5*5*3 textures. I probably could load the animation sequences at runtime, but I don't like the idea. I guess this would result in new problems, pauses etc..

Let me be a bit more specific: I need this morphing because I have only a very limited number of phoneme mimic textures in a NPC lipsync animation system, and it looks rather unsmooth, even when the M is at the right place an so on. Now I want to try to fade between the Phoneme Textures to make it look more natural, liquid motion. As you may guess the texture must be faded often, along the speech of an NPC. I also don't need too much tween frames, because there ain't so many frames in one "O" or "A" or so. In fact I only want to smooth the transition a little bit.

Currently I am thinking about this way:
I will use 2 Texture layers on the Face surface. the 2nd Texture is created with the alpha flag, as well as the 256 VRam-Residence flag for better speed (at the cost of no mipmapping I am afraid -this could be a new problem / gfx artefact). A function SetTexAlpha allows to set all Texels alpha channels to a certain value. This way I can fade in the 2nd layer Texture as smoothly as I want. The textures are 256*256, so speedwise it could be bearable, esp. since it is done only during dialogs.
The amount of Vram is doubled this way. That's still much better than the prerendered Frames option.

How it works (eg. the word "Wodka"):



set layer 0 to texture "W"
set layer 1 to texture "o", alpha zero
slowly increase alpha, so layer 0 will fade to layer 1

when alpha reaches 1.0:
set layer 0 to texture "o"
set layer 1 to texture "d", alpha zero
slowly increase alpha, so layer 0 will fade to layer 1

when alpha reaches 1.0:
set layer 0 to texture "d"
set layer 1 to texture "k", alpha zero

slowly increase alpha, so layer 0 will fade to layer 1
when alpha reaches 1.0:
set layer 0 to texture "k"
set layer 1 to texture "a", alpha zero
slowly increase alpha, so layer 0 will fade to layer 1
...

Sorry, a lot of text to explain something simple.

Nonetheless thank you very much for your help. I still hope to find something better. Wouldn't it be cool if we could apply multiple brushes to a surface? I mean, like textures, BrushAlpha would then allow to do exactly what we're talking about.

BTW. did I mention that I fixed a bug today that I was trying to debug since several months now? Yeah. </offtopic>


OJay(Posted 2010) [#5]
ehm...no, you dont need 5*5*3 textures with my method...you can use ONE animated texture with the alpha information for ALL transitions!

lets take your example:

set layer 0 to texture "W"
set layer 1 to alpha fade texture, frame 0
set layer 2 to texture "o"
slowly increase frame, so layer 0 will fade to layer 2

when alpha frame reaches max frames:
set layer 0 to texture "o"
set layer 1 to alpha fade texture, frame 0
set layer 2 to texture "d"
slowly increase frame, so layer 0 will fade to layer 2

etc etc...its the same process, with the same alpha texture, just with different "base" and "team" texture (see my code sample)


for your solution, you probably dont want to use such a "cloudy" alpha fade texture...a 1x1 pixel texture with simple linear interpolated alpha would be good enough. so you could easily create 50 frame for a very smooth transition with quite a small memory footprint. ;)


jfk EO-11110(Posted 2010) [#6]
You're right, please excuse, I've misunderstood it in the fisrt place, then later I realized that you must have used some kind of blending magic. I think I tried the same some time ago, but failed. So thanks for this essential info, that I will backup right now..

Indeed, with one pixel textures it makes sense, absolutely. Thanks a lot!


jfk EO-11110(Posted 2010) [#7]
I still have a problem with this. I don't know exactly how to set the Blendmodes of the textures. I hope it doesn't require FastExt. What are the plain B3D modes?

I have assigned the textures this way:

base layer 0
alpha layer 1
team layer 2

then I tried various settings, eg.

layer 0 blend 1
layer 1 blend 3
layer 2 blend 2

(
0: Do not blend
1: No blend, or Alpha (alpha when texture loaded with alpha flag)
2: Multiply (default)
3: Add
4: Dot3
5: Multiply 2
)

and so on, I probably tried all combinations of 1,2 and 3, as well as some experiments with 4 and 5. I managed to fade from or to black or white, but not between base and team texture. I have to say I am using a Brush and TextureBrush, then PaintEntity, but this shouldn't make a diffrence, right?

Adding FastExt might be an option, but I am not really amused by the thought. It may or may not bring up new problems, and since I haven't got it yet: also new costs.

Is it possible with Blitz3D only?


OJay(Posted 2010) [#8]
sorry, i dont know if it is possible without the blendmodes fastext introduces...you might consider buying it...isnt really that expensive and you really unleash the full potential of dx7. plus there're a lots of astonishing samples, like the shadowmapping stuff...

if fastext is such a no go for you, you may have to look for another solution...animating the mouth with bone animation or an animated texture are coming to my mind too...but dunno if that fits your needs...


Rroff(Posted 2010) [#9]
Your going to need fastext with that method to get best results imo - tho if your only blending between 2 textures you can get away without - extra layers would requite additional surfaces.

I highly reccomend getting FastExt - I've had pretty much no problems with it - very easy to slipstream into your current code base and gives you access to a great range of features and performance increases.

Aslong as the game isn't running a resolution below the texture resolution my method should be very very quick and have better granularity over the fade... tho I do kinda like OJay's method with the ability to use stylish fade patterns. The only downside to the method I propose is dealing with mipmaps to make sure the texture stays sharp.


jfk EO-11110(Posted 2010) [#10]
Thanks for your answers. I really wanted to keep it plain vanilla Blitz3D, and for this little feature of smoothing the transition I didn't want to add something like FastExt. I however hear a lot of good things, but might also remember some problems with new versions of Blitz3D (no?).

I tried hard to find a blendmode combination that allows to use the texels of one layer for the alphachannel of an other layer, which is about what OJay did with FastExt, but I am afraid (and this may also be the reason why I failed to do this a couple of years ago) it simply isn't possible in Blitz.

I will think about to buy FastExt. Unfort. I also have already spent too much money for this production, content etc., esp. when it may be Freeware one day.

I have implemented the brute force alpha channel blending I described earlier. It really works. But there is one little problem that is driving me insane:

When I fade in texture 2 over texture 1 then I must use Blendmode 1 for texture 2. But this Mode completely ignores any EntitxColor, BrushColor or Shading, so itis fading from texture 1 (with EntityColor and Shading) to a completely fullbright texture 2, an ugly, blinking artefact.

I have tried many combinations, but faied to fix this very little, very mean problem.

Here's a standalone sample:

Note: As the original DOcs say, using Alphablending Mode (1) together with multiple Texture Layers is explicitely not recommended and may result in unexpected behaviour of gfx hardware (it may quit and leave the building, you never know). So even if I can fix the problem of the fullbright alphablended layer tex2, there is still this compatibility problem.

When you run this, and when it works like on my machine, then you'll see the textures blending back and forth (pingpong like), the content of the textures are exchanged after every transition. As soon as layer 0 bcomes fully visible (because layer 1 is alphaed to zero) there will be full shading. Shading will be reduced during the transition, until it reaches the fullbright state of tex2 with alpha 1.0.

Replace

brush1=CreateBrush()
TextureBlend tex1,2
TextureBlend tex2,1

by

brush1=CreateBrush()
TextureBlend tex1,1
TextureBlend tex2,1

Now both layers are "fullbright" (actually more than that, they ignore EntityColor Brushcolor and Fading as well) and the artefact is not visible anymore, but I really don't want to use EntitxFX 1, plus EntityColor is absolutely required.

If you have any idea to solve this probem, this would be great.



Graphics3D 800,600,32,2
SetBuffer BackBuffer()

Dim sta_rgb(255,255) ; used to cache readpixelfast data, for speed optimation

; for some strange reason I don't need to set the alpha flag here to make it work (at least on this hardware here)
; I tried flag 256, but for some other strange reason it's much slower (thought it should be faster)
tex1=CreateTexture(256,256) ; base texture buffer
tex2=CreateTexture(256,256) ; fade-in texture buffer

tex3=CreateTexture(256,256) ; this is only used to buffer one texture when the 2 are flipped.


; creating some GFX for 2 individual textures...------------------------------------
fofo=LoadFont("Verdana",72)
SetFont fofo

Color 50,50,50
Rect 0,0,256,256,1
Color 127,127,127
Goto nix1
Color 255,0,0
For i=0 To 256 Step 32
 Rect i,0,16,256,1
Next
.nix1
Color 127,127,127
Text 2,2,"Hello"

For i=0 To 127 
 g=(255-(i+i))*1.0
 Color g,g,g
 Oval 120-i/2,120-i/2,i,i,0
 Oval 121-i/2,121-i/2,i,i,0
Next

CopyRect 0,0,256,256,0,0,BackBuffer(),TextureBuffer(tex1)

Color 50,50,50
Rect 0,0,256,256,1
Color 127,127,127
Goto nix2
Color 0,0,255
For i=0 To 256 Step 32
 Rect 0,i,256,16,1
Next
.nix2

Color 127,127,127
Text 12,6,"Hello2"


For i=0 To 127 
 g=(255-(i+i))*1.0
 Color g,g,g
 Oval 160-i/2,160-i/2,i,i,0
 Oval 161-i/2,161-i/2,i,i,0
Next

CopyRect 0,0,256,256,0,0,BackBuffer(),TextureBuffer(tex2)
; END OF creating some GFX for 2 individual textures...------------------------------------



; a simple scene setup

cube=CreateCube()
RotateEntity cube,45,45,45
;EntityFX cube,1 ; doesn't fix it.
;EntityColor cube,127,127,127 ; has no influence when texture is blended "1-ish"

camera=CreateCamera()
TranslateEntity camera,0,0,-3
CameraClsColor camera,70,70,70

light=CreateLight()
RotateEntity light,45,45,0

brush1=CreateBrush()
TextureBlend tex1,2
TextureBlend tex2,1
; problem: 1 causes fullbright blending, and ignores brushcolor and entitycolor etc.!

BrushTexture brush1, tex1,0,0
BrushTexture brush1, tex2,0,1

PaintEntity cube,brush1


fo2=LoadFont("") ; reset font
SetFont fo2


; MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMainloop
While KeyHit(1)=0

 ms=MilliSecs()
 If ms> ms2
  If fade>15 Then 
   fade=0
   ; for demo purposes: flip the textures when fading is complete.
   CopyRect 0,0,256,256,0,0,TextureBuffer(tex1),TextureBuffer(tex3)
   CopyRect 0,0,256,256,0,0,TextureBuffer(tex2),TextureBuffer(tex1)
   CopyRect 0,0,256,256,0,0,TextureBuffer(tex3),TextureBuffer(tex2)
  EndIf
  dur = SetTexAlpha(tex2,(Float(fade)/15.0))
  ;PaintEntity cube,brush1
  ms2=ms+50
  fade=fade+1

 EndIf

; TurnEntity cube,  .1  ,  .2  ,  .3
 UpdateWorld()
 RenderWorld()
 Text 0,0," "+dur+" ms for SetTexAlpha"
 Flip
Wend
; EO mainloop


Function SetTexAlpha(tex,al#) ; wants a texture handle and alpha from 0.0 to 1.0.Note, No DDS!
 Local al2,ts1,ts2,x,y
 ts1=MilliSecs()
 al2=(al#*255.0)
 If al2<0 Then al2=0
 If al2>255 Then al2=255
 SetBuffer TextureBuffer(tex)
 LockBuffer()
 For y=0 To TextureHeight(tex)-1
  For x=0 To TextureWidth(tex)-1
   sta_rgb(x,y)=ReadPixelFast(x,y) And $FFFFFF
  Next
 Next
 For y=0 To TextureHeight(tex)-1
  For x=0 To TextureWidth(tex)-1
   WritePixelFast x,y, (al2 Shl 24) Or sta_rgb(x,y)
  Next
 Next
 UnlockBuffer()
 SetBuffer BackBuffer()
 ts2=MilliSecs()
 Return ts2-ts1
End Function



BTW I was wrong about the speed gain of Texture Flag 256. The only thing that is getting faster is Copyrect between Textures and Backbuffer (and maybe from 256 to 256). In many other cases it makes things even slower.

Readpixelfast for example is getting 40 times slower, Writepixelfast at the other hand has the same speed, with or without Flag 256. And there may also be diffrences between various gfx harware. Here's a litte example to see the diffrences:




Graphics3D 800,600,32,2
SetBuffer BackBuffer()

tex1=CreateTexture(256,256,0) 
tex2=CreateTexture(256,256,256) 
tex3=CreateTexture(256,256,0) 
tex4=CreateTexture(256,256,256) 


Text 0,0, "testing readpixelfast without flag 256"
t1=MilliSecs()
SetBuffer TextureBuffer(tex1)
LockBuffer()
For i=0 To 1000000
 argb=ReadPixelFast(10,10)
Next
UnlockBuffer()
SetBuffer BackBuffer()
t2=MilliSecs()
Text 0,16, (t2-t1)+" ms"


Text 0,32, "testing readpixelfast with flag 256"
t1=MilliSecs()
SetBuffer TextureBuffer(tex2)
LockBuffer()
For i=0 To 1000000
 argb=ReadPixelFast(10,10)
Next
UnlockBuffer()
SetBuffer BackBuffer()
t2=MilliSecs()
Text 0,48, (t2-t1)+" ms"


Text 0,64, "testing writepixelfast without flag 256"
t1=MilliSecs()
SetBuffer TextureBuffer(tex1)
LockBuffer()
For i=0 To 1000000
 WritePixelFast 10,10,0
Next
UnlockBuffer()
SetBuffer BackBuffer()
t2=MilliSecs()
Text 0,80, (t2-t1)+" ms"


Text 0,96, "testing writepixelfast with flag 256"
t1=MilliSecs()
SetBuffer TextureBuffer(tex2)
LockBuffer()
For i=0 To 1000000
 WritePixelFast 10,10,0
Next
UnlockBuffer()
SetBuffer BackBuffer()
t2=MilliSecs()
Text 0,112, (t2-t1)+" ms"


n=200

Text 0,128, "testing copyrect, flagwise 0 to 256"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex1),TextureBuffer(tex2)
Next
t2=MilliSecs()
Text 0,144, (t2-t1)+" ms"


Text 0,160, "testing copyrect, flagwise 0 to 0"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex1),TextureBuffer(tex3)
Next
t2=MilliSecs()
Text 0,176, (t2-t1)+" ms"


Text 0,192, "testing copyrect, flagwise 256 to 256"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex2),TextureBuffer(tex4)
Next
t2=MilliSecs()
Text 0,208, (t2-t1)+" ms"


Text 0,224, "testing copyrect, flagwise 256 to 0"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex2),TextureBuffer(tex1)
Next
t2=MilliSecs()
Text 0,240, (t2-t1)+" ms"


Text 0,256, "testing copyrect, flagwise backbuffer to 256"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,BackBuffer(),TextureBuffer(tex2)
Next
t2=MilliSecs()
Text 0,272, (t2-t1)+" ms"


Text 0,288, "testing copyrect, 256 to backbuffer"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex2),BackBuffer()
Next
t2=MilliSecs()
Text 0,304, (t2-t1)+" ms"



Text 0,320, "testing copyrect, flagwise backbuffer to 0"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,BackBuffer(),TextureBuffer(tex1)
Next
t2=MilliSecs()
Text 0,336, (t2-t1)+" ms"



Text 0,352, "testing copyrect, 0 to backbuffer"
t1=MilliSecs()
For i=0 To n
 CopyRect 0,0,256,256,0,0,TextureBuffer(tex1),BackBuffer()
Next
t2=MilliSecs()
Text 0,368, (t2-t1)+" ms"










Flip
WaitKey()
End






jfk EO-11110(Posted 2010) [#11]
I however just purchased FastExt, now reduced from 30 to 12 us$, I mean, that's pretty much nothing. See you later and thanks again :)


jfk EO-11110(Posted 2010) [#12]
Ok, PS 2:

Rroff - I read your suggestion again, and due to my limited english it took quite some time until I understood what you mean. I have now implemented it and WOW, it's pretty good. I had some troubles to align the camera pixelperfectly since my gfx card cannot use the monitors native pixel resolution, so the screen is a bit blur all the time, makes it hard to have control over the said pixelperfection over here.

But the very positive aspect is: I can EntityTexture both quads, Renderworld it, then do one CopyRect from the backbuffer to the Texturebuffer that is actually used by the NPC's Face Surface (one layer only!), job done. Using the bespoken Flag 256 for this copyrect from backbuffer to the texture is rather fast. On my old machine it toggles between 0 and 1 ms for the whole Morphing function call.

This solution is also very robust, since it does not rely on Nonstandard Blending Operations etc. So therefor, thumbs up, tho I am a bit worried about the fact that I it wasn't my idea :).

Even if I have FastExt now, I think I'll implement it this way and play with FastExt later.


Kryzon(Posted 2010) [#13]
I was just thinking of other method now - it uses FastEXT. Using the 2nd UV coordinate-set to assign a 512x2 "animated" texture, with shades of gray from black to white in this texture's Alpha Channel.

You'd have to make all your mesh's UVs in the second channel be completely (or almost) collapsed, so as to fit in the center of a single frame of this texture (and thus have your entire mesh be sunk in the shade of gray). Each frame would be 2x2 pixels (yeah, pretty collapsed UVs).

Then you'd bind [using fastExt] your UV1 diffuse texture's alpha channel to this animated UV2 alpha-channel-only texture, and by animating the UV2 alpha-channel-only texture you'd have your UV1 texture smoothly fade into oblivion, showing the map below.

You can even set up an easy expression to get the appropriate frame, in a black to white alpha-channel-only texture:
frame = Int(alpha*255) / 255
EntityTexture mesh, fadeTexture, żindex?, frame
This is not very consuming since you can\should recycle this alpha-channel-only texture to all of your meshes that need this type of transition.


RifRaf(Posted 2010) [#14]
have you considered using a larger texture on two seperate UV sets with alpha channels, and simply moving the UVs around on each channel for unique blends between them.


jfk EO-11110(Posted 2010) [#15]
Thanks for these 2 further Ideas - I see threre are still many ways to rome.

Currently I stick with Rroffs Solution, it's really straingt forward and stabile, and also fast enough. Fastlib - a very powerull Extension to Blitz3D, unfortunately isn't as stabile/omnicompatible as Blitz3D alone. EG. 95% of the samples didn't work on this laptop with noname onboard graphics (of course, a lot of games don't work on it, but for me it's always a good compatibility check).