cocos2d - Showing only part of a sprite -- irregular shape - cocos2d-iphone

I'm really going crazy trying to figure this out, so any help would be really appreciated. I'm trying to hide most of a sprite and show it gradually. This works fine if I only work with rectangles. For example, I found someone's implementation of the "ClippingNode" class and it worked well, namely, this part of the code:
-(void) visit
{
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(clippingRegion.origin.x + positionInPixels_.x, clippingRegion.origin.y + positionInPixels_.y, clippingRegion.size.width, clippingRegion.size.height);
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
The problem is I need an irregular shape, not just a rectangle. I was hoping I could stack calls to glScissor and create a shape with many smaller rectangles, but unfortunately glScissor only works once (the last time it was called).
It seems that cocos2d doesn't support OpenGLs stencil buffer (does it?) and even if it did, I find OpenGL so hard to understand, I'd still need someone to explain it to me. If I could set a bezier path on the sprite as a mask (which I think you can do in Quartz), that would be great, but it doesn't seem like that's supported.
Please, if anyone has any bit of wisdom here, that'd be great!

Figured it out. You can call glScissor multiple times, you just also need to draw that scissored shape each time:
-(void) visit
{
NSEnumerator *enumerator;
NSValue *val;
CGRect aRegion;
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
enumerator = [regions objectEnumerator];
while ((val = (NSValue *)[enumerator nextObject])) {
aRegion = [val CGRectValue];
glScissor(aRegion.origin.x, aRegion.origin.y,
aRegion.size.width, aRegion.size.height);
[super visit];
}
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}

It isn't possible with glScissor, but you could easily achieve this effect using the stencil buffer. Here is the documentation:
http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html
There is also a NeHe tutorial on the stencil buffer, but it is in C++, not Objective C (though it should be easy to translate into whatever application you need):
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=26
EDIT: This is based on the assumption that you want to clip it to some arbitrary shape, for example a star, smiley whatever, instead of just a rectangle.

Related

Opacity overlap within the same OpenGl TriStrip in LibGdx

While my problem lies strictly in the opacity of the tristrip, I'd like to give some context first.
Recently I started developing a game through LibGdx which involves 2D circles which bounce around the screen. So as to provide a neat graphical effect, I created a small system that would provide a "tail" to the actors, which would fade over time. Visually, it looks like this:
Nice Trail Example
Now that ended up looking satisfactory. My problem, however, lies in situation where parts of the "trail" effect overlap, creating an ugly artifact which I would guess is the sum of the opacities of the points.
Ugly Trail Example
I believe this problem lies in the way with which the tristrip is drawn, specifically with the blending methods used.
The code used to generate the trail is as follows:
Array<Vector2> tristrip = new Array<Vector2>(); //Contains the vector information for OpenGL to build the strip.
Array<Vector2> texcoord = new Array<Vector2>(); //Contains the opacity information for the corresponding tristrip point.
// ... Code Here.... //
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
for (int i = 0; i < tristrip.size; i++) {
if (i == batchSize) {
gl20.end();
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
}
Vector2 point = tristrip.get(i);
Vector2 textcoord = texcoord.get(i);
gl20.color(color.r, color.g, color.b, color.a); // Color.WHITE
gl20.texCoord(textcoord.x, 0f);
gl20.vertex(point.x, point.y, 0);
}
gl20.end();
It is also important to note that the draw function for the strip is called within another class, in this fashion:
private void renderFX() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) { //Draws the trails for each actor
balls.get(i).drawFX();
}
}
Is this problem a rookie mistake on my part, or was my implementation of the drawing of the vector array tristrip flawed from the start? How can I fix the blending issue in order to create smoother trails even in the presence of sharp curves?
Thanks in advance...
Edit: Since originally asking this question, I've experimented with some possible solutions, also implementing Deniz Yılmaz's suggestion of using a FBO to facilitate blending. Given that, my render function currently looks like this:
private void renderFX() {
frameBuffer.begin();
Gdx.gl20.glDisable(GL20.GL_BLEND);
Gdx.gl20.glClearColor(0f, 0f, 0f, 0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glStencilMask(0xFF);
Gdx.gl20.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) {
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0, 0xFF);
balls.get(i).drawFX(1f, Color.RED);
}
frameBuffer.end();
}
As shown, I've also experimented with stencils so as to try and mask the overlapping portion of the trail. This approach, however, results in the following visuals:
Stenciled Version
Again, this is not ideal, and has made me realize that approaching this problem by masking is not a good idea, as the opacity gradient will never be smooth in the corners as there will always be a sharp line between the two overlapping opacity values, even if somehow the logic prevents blending.
Given that, how else could I approach this problem? Should I scrap this method entirely if I plan to achieve a smooth gradient for this trail effect?
Thanks again.
glBlendFunc() is useless in this case because by default the values calculated based on the blend function are added.
So something like glBlendEquation(GL_MAX) needed
BUT
blending alone won't work, since it can't tell the difference between what is the background and what is the overlapping shapes.
Instead use FrameBuffer to draw trail with a glBlendEquation.
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects

Rendering multiple 3D Objects

I'm learning how to render objects with libGdx. I have one square model, that creates a few model instance from them. If I have only one model it renders fine.
But if I have more instances it doesn't properly. Looks like the front objects are draw first, and the background the last one, so always the background objects are visible and the front objects you can see through them.
To render I use the following
Gdx.gl.glViewport(0,0,Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl20.glClearColor(1f, 1f, 1f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
mb.begin(cam);
worldManager.render(mb, environment);
mb.end();
mb variable is the ModelBatch instance, and inside worldManager.render each model instance is draw as follow:
mb.render(model, environment);
I'm not sure what is happening. But I think it is some GL attribute that I need enable
Is not 100% related to the following post because, yes it uses OPENGL like libgdx, but the solution provided in that post is not working and I think the problem comes from ModelBatch from libgdx
Reproduction of the problem
You didn't setup your camera correctly. First of all your camera's near plane is 0f, which means it is infinitely small. Set it to a value of at least 1f. Secondly you set the camera to look at it's own position, which is impossible (you can't look inside your own eyes, can you ;)).
So it would look something like:
camera = new PerspectiveCamera(90, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.position.set(0, 10, 0);
camera.lookAt(0,0,0);
camera.near = 1f;
camera.far = 100f;
camera.update();
You probably want to start here: https://xoppa.github.io/blog/basic-3d-using-libgdx/
For more information on how the camera works have a look at: http://www.badlogicgames.com/wordpress/?p=1550
Btw, calling Gdx.gl20.glEnable(GL20.GL_DEPTH_TEST); will not help at that location and should definitely not be done when mixed with ModelBatch. ModelBatch manages its own render context, see the documentation for more information: https://github.com/libgdx/libgdx/wiki/ModelBatch
There are a lot of possible answer, but I would say that
glEnable (GL_DEPTH_TEST) ;
could help if you haven't done it yet. Also, enabling depth buffer only works if you actually have a depth buffer, which means you must makes sure you have one, and the method for this depends on your window context.
for show the difference dimentions you can use the fog

Cocos2d: algorithm to get a shadow following a CCSprite in a realistic way

I am working with Cocos2d 2.0 and no else (no BOX2D etc..). I have a character and added a shadow to it as CCSprite child node. It gives a nice "flying effect" when it moves but unfortunately, when the character rotates also the children do and the shadow child moves in an unrealistic way. See this picture:
In 3D gaming this would be taken care in the graphic engine with a 3D Matrix and the the position of the light source in the game. However my game is much simpler and does not require any 3D graphics so I need to find a programmatic approximation of this.
To first attempted to ovverride the "setPosition" and "setRotation" methods but did not help much (the shadow doesn't change position).
-(void) setPosition:(CGPoint)position
{
[super setPosition:position];
CCSprite * shadow = (CCSprite *)[self getChildByTag:belowByOneZFirst];
if (shadow!=nil) {
[shadow setPosition:shadowOriginalPosition];
CCLOG(#"Setting shadow position");
}
}
-(void) setRotation:(float)rotation
{
[super setRotation:rotation];
CCSprite * shadow = (CCSprite *)[self getChildByTag:belowByOneZFirst];
if (shadow!=nil) {
[shadow setRotation:0];
CCLOG(#"Setting shadow rotation");
}
}
I have two possible paths to follow now. One is to make the shadow an indipendent CCSprite (and not add it as child) and the other one is to attempt to ovverride the setters modifying the "SET_DIRTY_RECURSIVELY()" macro (it could check if a child has a specific tag and if so does not apply the change).
The first approach is a bit overcomplicated and the second one sounds ok but still a bit too complex.
Also, just not "changing" the shadow relative position does not solve the matter fully. I should instead write some code to adapt the shadow relative position taking account of the relative position of the Sprite within the screen (say I set my sun to be in the top left corner then the shadow will change shape according to the relative position to the sun).
Has anyone else had a similar algorithm to implement with Cocos2d and if so are there any common patterns to solve this?
tip: add both sprite and shadow (with position offset) as child of a ccnode. Move the node, rotate only the sprite, shadow position is still an offset to sprite position. Problem solved (as far as I understood).

Animate CCSprite on Each Update

I have a CCSprite object of which I need to update the on screen (x,y) position as quickly as possible. It is an augmented reality app so the on screen position needs to appear fixed to a real world location.
Currently, during each update I check the heading and attitude of the device then move the sprite accordingly by determining the new x and y positions
[spriteObject setPosition:ccp(newX, newY)];
Each degree change in heading corresponds to 10 pixels in on screen position, so by setting the position this way the sprite jumps around in intervals of 10 pixels which looks stupid. I'd like to animate it smoothly, maybe by using
[spriteObject runAction:[CCMoveTo actionWithDuration:0.2f position:ccp(newX, newY)]];
but the problem here is that a new position update comes in while the sprite is animating and it sort of screws the whole thing up. Anyone know of a nice solution to this problem? Any help is much appreciated as I've tried numerous failed solutions to this point.
You can try to just animate your sprite movement to the point. I mean, you can several times during one second run animated position correction with duration of 1/numberOfUpdates in one second. Something like
- (void) onEnter
{
[super onEnter];
[self schedule:#selector(updatePositionAnimated) interval:0.2f];
}
- (void) updatePositionAnimated
{
[spriteObject runAction:[CCMoveTo actionWithDuration:0.2f position:ccp(newX, newY)]];
}
I suppose, you will have smooth enough animation in this case

OpenGl 2d zooming (using scale and translate instead of glOrtho)

It seems that this is quite a common question, but I can't find a person with my same circumstances. The closest seems to be: OpenGL: scale then translate? and how?.
The problem I'd really like some help with is to do with moving around while zoomed into (and out of) a 2d scene using OpenGl. The code for zooming out is pretty simple:
void RefMapGLScene::zoomOut(){
currentScale = currentScale-zoomFactor;
double xAdjust = (((get_width())*zoomFactor/2));
double yAdjust = ((get_height()*zoomFactor/2));
zoomTranslateX -= xAdjust;
zoomTranslateY -= yAdjust;
}
The code for zooming in is basically the same (add the zoomFactor to currentScale, and increment zoomTranslateX and Y).
The code for rending everything is also simple:
glPushMatrix();
glTranslated(-zoomTranslateX, -zoomTranslateY, 0);
glScaled(currentScale, currentScale, 1);
glTranslated(totalMovedX, totalMovedY, 0);
graph->draw();
glPopMatrix();
Essentially, zoomTranslate stores an adjustment needed to make the screen move a little towards the middle when zooming. I don't do anything nice like move to where the mouse is pointing, I just move to the middle (ie, to the right and up/down depending on your co-ordinate system). TotalMovedX and Y store the mouse movement as follows:
if (parent->rightButtonDown){
totalMovedX += (-(mousex-curx))/currentScale;
totalMovedY += (-(mousey-cury))/currentScale;
}
Dragging while not zoomed in or out works great. Zooming works great. Dragging while zoomed in/out does not work great :) Essentially, when zoomed in, the canvas moves a lot slower than the mouse. The opposite for when zoomed out.
I've tried everything I can think of, and have read a lot of this site about people with similar issues. I also tried reimplementing my code using glOrtho to handle the zooms, but ended up facing other problems, so came back to this way. Could anybody please suggest how I handle these dragging events?
The order of operations matter. Operations on matrices are applied in the reverse order in which you multiplied the matrices. In your case you apply the canvas movement before the scaling, so your mouse drag is also zoomed.
Change your code to this:
glPushMatrix();
glTranslated(-zoomTranslateX, -zoomTranslateY, 0);
glTranslated(totalMovedX, totalMovedY, 0);
glScaled(currentScale, currentScale, 1);
graph->draw();
glPopMatrix();
Also after changing that order you don't have to scale your mouse moves, so you can omit that division by currentScale
if (parent->rightButtonDown){
totalMovedX += (-(mousex-curx));
totalMovedY += (-(mousey-cury));
}