Transparency issues with 3d particles and 3d models, libgdx - libgdx

I got some strange issues with transparency and 3d particles. A short vid to illustrate:
https://youtu.be/ZHKI1X3MjhY
As you can see I have a 3d particle effect, fire burning. Inside it is a 3 model with no alpha blending and it shows just fine. then in the far distance there is a small skeleton (with blending and alphatest turned on) and it also shows just fine through the fire. Then I turn camera and look at the warrior skeleton and it just disappear and instead you see what is behind him. I turn camera again and the mage skeleton also vanishes, but you can see the trees a bit further away just fine and they have the exact same settings for blending and alpha test. If I move the character say 20 yards away it also starts showing through the fire effect.
So it seems to have something to do with distance from the 3d particle effect...
The 3d particle batch is an extended BillboardParticleBatch like this:
protected Renderable allocRenderable(){
BlendingAttribute ba=new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE,1f);
Renderable r = super.allocRenderable();
r.material = new Material( ba,
// new DepthTestAttribute(GL20.GL_LEQUAL, 0.0f, 0.5f, true),
// r.material.set(new FloatAttribute(FloatAttribute.AlphaTest, 0.0f),
TextureAttribute.createDiffuse(texture));
return r;
}
All the characters and the trees are created with following attributes:
if (alpha) {
FloatAttribute floatAttribute = new FloatAttribute(FloatAttribute.AlphaTest, 0.5f);
BlendingAttribute blendingAttribute = new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, 1f);
for (int i = 0; i < bulletEntity.modelInstance.materials.size; i++){
bulletEntity.modelInstance.materials.get(i).set(blendingAttribute);
bulletEntity.modelInstance.materials.get(i).set(floatAttribute);
}
}
The models are drawn first then the particles, I tried changing order but no difference. I have tried a lot of different setups for alphatest, depthtest and blendingattribute but can not find anything that works.
EDIT
I removed the Blending attribute from the 3d-models and now it looks as it should regarding the particle effect. However I need most materials on my character models to have blending set..
Anyone got any clue why this is happening when I enable blending?
I also tried to use the BillboardParticleBatch without extending it in case I had done something there but the effect then is even worse. All models with blending enabled appear in-front of the particle effect even though they stand behind it.

ModelBatch sorts your render calls (check this link, really, it is a must read), to avoid incorrect behavior (as you're experiencing). The actual sorting/rendering happens at the call to ModelBatch#end. By default it uses the DefaultRenderableSorter, which is a default implementation. Of course, because that implementation isn't aware of your scene, it might not fit exactly your needs.
The DefaultRenderableSorter tries to guess the location of each model based on their transformation matrix. Based on that location and the camera's location it will sort them so that:
First all opaque objects are rendered from front to back (because whatever is behind an opaque object isn't visible anyway, so that reduces unneeded calls to the fragment shader).
Secondly all transparent objects are rendered from back to front (because as soon as a transparent object is rendered then everything that is rendered after that and is behind it, will not be visible).
To decide whether an object is transparent, the BlendingAttribute#blended member is used. (So you could, if you really wanted to, set that member to false to force it to be treated (sorted) as if it was opaque)
So, the order in which you call ModelBatch#render is not necessarily the order in which they are actually executed. If you want to force to render whatever you've added to the batch in between, then call the ModelBatch#flush(). Of course, doing this a lot defeats some of the purpose of ModelBatch in the first place.
Instead you could implement your own RenderableSorter which has more knowledge about your scene and can therefor do a better job sorting than the default implementation. (however if flush() works for you and there's no other issue, then just flush might be the easiest solution for you).
That said, there a various other solutions you could try as well. E.g. the regions of the particles are fully transparent, so the fragment shader might as well discard those all together. Try adding FloatAttribute.AlphaTest with a value of 0.5f to the particles. If that messes with your blending then gradually reduce the value to e.g. 0.05f.
Also, you could add a DepthTestAttribute with depthMask set to false (new DepthTestAttribute(false)). This will prevent the particles from writing to the depth buffer. (but also might cause other things to show in front of the particles).

Related

Cocos2D-X nodes loading in wrong positions have RemoveAllChildren()

I'm only using one scene object for my entire 2d sidescrolling platformer with two layers: There is a hudLayer for the controller, and the gameLayer for everything in the game.
When I control my character to walk into a door (sprite with a physicsBody that has a callback that takes me to the next level), the next level loads by these instructions:
remove all event listeners
stop all actions for both layers (the gameLayer typically has been doing a Follow action that follows the player, and is limited to the size of the backgroundSpriteNode)
remove all children from the gameLayer
set gameLayer position to Vec2(0,0)
load level 2 (a complete copy of what level 1 should look like... load the background sprite to gameLayer, playerSprite, add event listeners)
add event listeners back to the hudLayer
The only problem is that for whatever reason, the level only partially loads the way it should... For instance, coins appear in the spots they should, but platforms don't seem to. Neither that or the player, or other characters. Not sure really why these objects are specifically not loading in the correct positions, but maybe someone who has experienced this sort of problem before can help?
Most nodes (such as platforms) are appearing below the bottom of the screen when they should be fully shown at the bottom of the screen. Characters are appearing down there too when they should be appearing above the platforms.
P.S. After testing a bit more, I've come to realize that SOMETIMES some of the platforms are loading in the correct positions, but sometimes they aren't. Not sure why. A fix for this may be to load things one at a time with a delay between them. But I'd rather not have to put delays and just figure out what the deal is.
Figured it out: for whatever reason, I needed to add a delay in there. I think for whatever reason, by calling removeAllChildren(), something got messed up with the positions. It was my suspicion since SOME of the time, parts of the next level would load, but only some parts, and only sometimes.
Here's the code I added to run an action on the gameLayer once all children were removed, etc...
runAction(Sequence::createWithTwoActions(DelayTime::create(0.1), CallFunc::create( [&] ( ) {
loadLevel2(this);
})));

How to animate textures in a 3d model?

I wish to have a animated 3d texture in my LibGDX code but I am struggling to find out how to do it.
I assume how this "should" be done is either;
a) Directly accessing and modifying the texture on the model. (via a pixmap? ByteBuffer?)
or
b) Prerendering a big image containing all the frames (say, 20) and then moving the UV co-ordinates to create the illusion of the animation. (akin to ImageStrips in 2d/webdesign).
I did work out how I could completely replace the material eachtime, but that seems a much worse way of doing it. So if anyone could show the commands I need to do either a) or b) (or a similar optimal method) I would be great-fall.
Maths I am fine with. The intricacies of OpenGLES or GDX I am not :)
(The solution should at least work HTML/Android compiles, ideally everything)
Since the latest release it is very easy to play a 2d animation on a 3d surface. First make sure to get familiar with the 2d animation concept, as explained over here: https://github.com/libgdx/libgdx/wiki/2D-Animation. Then, instead of using a spritebatch, you can use the TextureRegion (which Animation#getKeyFrame returns) to set the material of the surface, as shown here: https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/g3d/TextureRegion3DTest.java. So basically you would get in your render method:
attribute.set(animation.getKeyFrame(stateTime, true));
Or if you want a more generic approach:
instance.getMaterial("<name of material>").get(TextureAttribute.class, TextureAttribute.Diffuse).set(animation.getKeyFrame(stateTime, true));
Or, if there's only one material in the ModelInstance:
instance.materials.get(0).get(TextureAttribute.class, TextureAttribute.Diffuse).set(animation.getKeyFrame(stateTime, true));
If you have the memory for it I would definetly choose b), it is easier on the processor. Also, you would only change a uniform's value. However, due to preprocessing it might take some time to open the application.
Get you uniform variable, where you compile your shaders, animationPos should be global.
Gluint animationPos = glGetUniformLocation(shaderProgram, "nameoftheuniform");
Your main loop should pass animationPos value to the shader:
Gluniform1i ( animationPos, curentAnimationIndex);
Add this your fragment shader variables:
uniform int animationPos;
Fragment shader main:
float texCoordY = texCoord.y; //texture coordinates should be passed from vertex shader
float texCoordX = texCoord.x/20.0f; //we are dividing it with 20 since it is the amount of textures that we have and if we use it directly it would try to use all the texture. Whereas the texture stores at 20 different textures.
float textureIndex = 1.0f*animationPos/20.0f; //Pointer to the start of the animation texture.
gl_fragColor = texture2D ( yourTexture, vec2( textureIndex + texCoordX, texCoordY));
Above code assumes that you expanded your textures in the x direction, you can also try to expand it like a matrix, then you need to change the texCoord calculation part. Also that we are using 20 textures.
The option a) is more heavy on the processor and you will be changing the texture every time so it will use pci a bit more, but easier on memory. The question is more like a design decision, but I guess 20 images can be handled so go with option b).
Edit: Added code.

Html Canvas - Translate, Rotate, Clip - Faster restores with using context.restore

After asking a question regarding animation speed a few days ago, the stackoverflow gang once again solved my problem. However, this has led to another question. [The more you know, the more you realise you don't know.]
Basically the fewer state changes to my canvas, the faster things will go. If I am just changing the fillStyle, then using ctx.save and ctx.restore is overkill, as all states are restored. Overkill = Slow. Instead just keep the oldvalue of fillStyle somewhere and put just that back in once you have finished.
So how do you do this for ctx.translate(x, y), ctx.rotate(angle) and ctx.clip()?
How can I restore these guys to their states before my changes WITHOUT having to use ctx.restore?
Your can untransform by using negative values.
ctx.translate(100,100);
// draw lots of stuff
ctx.translate(-100,-100);
ctx.scale(.75,.50);
// draw stuff
ctx.scale(-.75,-.50);
ctx.rotate(Math.PI/4);
// draw stuff
ctx.rotate(-Math.PI/4);
If you do multiple transforms, you must undo them in reverse order
ctx.translate(100,100);
ctx.scale(.75,.50);
ctx.rotate(Math.PI/4);
// draw lots of stuff
ctx.rotate(-Math.PI/4);
ctx.scale(-.75,-.50);
ctx.translate(-100,-100);
But when translating (moving) a few items, it's faster to use an offset instead of a transform.
strokeRect(20+100,20+100,50,30);
fillRect(20+100,20+100,50,30);
Clipping is semi-permanent so you must save/restore the entire context state to undo clip:
context.save();
// define a clipping path
context.clip();
// draw stuff
context.restore();
Transforms are done using a transformation matrix. Canvas gives you access to that matrix using the context.setTransform method.
scaleX=.75;
scaleY=.50;
skewX=0;
skewY=0;
translateX=100;
translateY=100;
context.setTransform(scaleX, skewX, skewY, scaleY, translateX, translateY);
// draw stuff
context.setTransform(-scaleX, -skewX, -skewY, -scaleY, -translateX, -translateY);
To also set the matrix for rotation, you must set a combination of the scale & skew values like this:
var radianAngle=Math.PI/4;
var cos=Math.cos(radianAngle);
var sin=Math.sin(radianAngle);
context.setTransform(cos,sin,-sin,-cos,0,0);
// draw stuff
context.setTransform(-cos,-sin,sin,cos,0,0);
To do rotation along with other transforms, just add the rotation values to the scale and skew values.
context.setTransform(scaleX+cos, skewX+sin, skewY-sin, scaleY-cos, translateX, translateY);
// draw stuff
context.setTransform(-scaleX-cos, -skewX-sin, -skewY+sin, -scaleY+cos, -translateX, -translate);
Just to correct the assumption of the question :
False : • The whole context state is saved/restored when using save()/restore() methods.
Let's be modest : An idea that comes to mind in 30 seconds is most likely to be found (and improved) by the developers of major Browsers. So truth is :
True : • Saving the context does almost nothing, and restore applies only on what just occurred.
If in doubt, you can look at the code, but it takes quite some time to be familiar with it (i did it with webKit's canvas => confirmed for this one ).
But it's much easier to look at the various jsperf made on the subject : they show that the gain when hand-saving/restoring one or two properties is moderate to small ==> only what changes is restored.
When hand-saving/restoring more things, then save and restore becomes faster because of Javascript's overhead.
(http://jsperf.com/save-restore-vs-translate-twice/4)
Another thing : talking about 'overkill' seems very exaggerated. Not only because, as seen before, context's save might be faster, but also because, best win is 2X, so we are talking about proudly taking 2ns instead of 4ns for the save. This has to be compared to the time taken for the draw, and might very well not be worth it.
Two last things :
• the bug risk induced by manually saving/restoring ('oops ! i forgot to restore that in that function !').
• the rounding errors that might occur (scale(x,x) => then scale(1/x, 1/x) )
In fact you can save time with no risk is by :
1) batching commands : whenever possible (it all depends on your app, really), batch all commands that expects a given context state.
2) similarly, you can define conventions/rules that prevents you to save/restore the context. For instance : 'always set fillStyle just before filling'. This way you never have to worry about current fillSyle. What you can do here also greatly depends on your app (and wether it's using external APIs or not), but can save a great deal of time for numerous draws.
So my advice would be to use the manual save/restore only for obvious simple case (ex: you just change globalAlpha), and to use conventions/rules to reduce the context state changes to a minimum.

hitTestPoint with 'shapeFlag=true' doesn't work in AS3

I simply added a sprite in AS3:
Sprite myspr = new Sprite();
myspr.addChild(mybitmap);
addChild(myspr);
Then I added an event. I did hitTestPoint for checking mouse is over my sprite or not.
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseCheck);
private function mouseCheck(evt:MouseEvent):void {
var xx:int = stage.mouseX;
var yy:int = stage.mouseY;
if(myspr.hitTestPoint(xx, yy, true)) {
...
// I'm checking mouse over here.
}
evt.updateAfterEvent();
}
Problem is: hitTestPoint gives true when mouse comes to full boundary box. But it should give true only if mouse comes on transparent isometric sprite.
Is there a solution for this, thanks in advance.
this should help. You need pixel perfect detection.
Actionscript 3 pixel perfect collision. How to? (learning purposes)
http://www.freeactionscript.com/2011/08/as3-pixel-perfect-collision-detection/
http://www.anotherearlymorning.com/2009/07/pixel-perfect-collision-detection-in-actionscript-3/
http://old.troygilbert.com/2009/08/pixel-perfect-collision-detection-revisited/
There's a few ways I usually do hit testing.
1) The easiest way is to use a an already made class that you can find online. Some people much smarter than me have created complex classes that allow for much better pixel to pixel interaction. The ones listed by Paras are all good. The problem with these is, for newer users, it can be hard to understand all the code and how to implement them. Usually it is simple once you understand what is going on though. You just replace your hit test with the class file and then enter in the correct arguments.
2) Another method is to actually go into the symbol, create a new layer, and then draw a rectangle(just turn the alpha down to 0%) where you want the hit test to work. This may seem like a stupid method, after all we are just confined to a square once again. BUT, it will actually work MUCH better than you'd expect. Just draw the square maybe slightly smaller than the height and width of your character you're detecting the hit test on, and you should be good to go. Give it an instance name (the hit square that is) and then just perform the hitTest with that square instead of the actual sprite. It works wonderfully and is a very simple solution. For what you're explaining though, this sounds like it might not work. This method is more from a gamer standpoint. It looks good when attacking and getting hit by enemies, but isn't necessarily exact. Also, if you want to do this with two characters (maybe a large attack hitting an enemy) simply draw a hit box for both sprites. This is probably a little more basic than using a pre-made pixel perfect hit detection test, but it works extremely well and takes only a few minutes.

slightly blurred text and bitmaps AFTER 3d transformation

I have a series of movieclips containing both bitmaps and text.
After applying some 3d transformations and moving in 3d space, my text and bitmaps are slightly blurred. This is AFTER I reset all the 3d coordinates (ie z=0, rotationX=0, rotationY=0)
Has anyone else encountered this? Is there a solution to get my crisp text and bitmaps back?
this is a very interesting error.
the blur that appears is actually improper anti-aliasing, or smoothing that is usually solved by rendering the font with fine colors along the edges. in this case, it is in fact caused by 3D transformations and can be solved by nullifying the matrix3D after the animation:
myTextContainer.transform.matrix3D = null;
you could also write:
myTextContainer.transform.matrix = new Matrix();
but with this approach you'll have to import flash.geom.Matrix.
both options will also reset to zero the x and y coordinates, and possibly other important settings of the animated display object, so you'll also have to assign those values to variables and reapply them after nullifying the transform matrix.
it seems that once a font is transformed, it loses this fine color tinting. non transformed fonts have these color details while transformed fonts become completely desaturated.
attached is a zoomed in detail of 12 point font which exhibits this loss of color detail. the top string has no 3D transformation while the bottom string was animated onto the stage via rotationY.
here is the same image saturated to 90% to show the colors more clearly:
these color details are easier to see on grey text.
i believe this error has been present since Flash Player 9 / AVM2 was first introduced. additionally, the fine color detail around the properly rendered font was much more saturated in early versions of the Flash player, which, in my opinion, made the fonts look much better - although the difference could be considered negligible by non perfectionists unlike myself.
You need to make sure you set the matrix3D property to null on any objects that you've applied 3D transformation to.
Looking up another post on 3d issues and came across the solution.
You need to remove all 3d transformations by applying a new transfrom.matrix
var tempMatrix:Matrix = new Matrix();
this.transform.matrix = tempMatrix;
An Even better answer is to use this fix. It's one I used to use all the time.
/**
* Fixes the slight distortion that occurs when an object has a 3D transform associated with it.
* #param di:DisplayObject The DisplayOjbect to fix.
*/
public function fix3DBlur(di:DisplayObject):void {
di.scaleX = di.width / (di.width - 1);
di.scaleY = di.height / (di.height - 1);
}
This function sets a slightly offset scaleX and scaleY. It seems weird, but they when you make 3d adjustments to the object using any 3d property it keep it from looking blurry. You can always remove the 3DTransform, but sometimes you need it to stay in place.
I place this function on a Utilities3D class I have.