problems using setVertexZ

Hi all, i am trying to build an isometric game with a lot of objects on screen, so setZOrder wont be enough(uses int). instead i am trying to use setVertexZ. in my app delegate i have

pDirector->setDepthTest(true); 
pDirector->setProjection(kCCDirectorProjection2D);  

and in my scene i use

CCSprite* bg=new CCSprite();
bg->initWithFile("HelloWorld.png"); 
bg->setAnchorPoint(ccp(0,0));   
bg->setVertexZ(0.0f);    
this->addChild(bg,0);



CCSprite* a=new CCSprite();
a->initWithFile("blue.png");  
a->setPosition(ccp(150,150));   
a->setVertexZ(1.0f);    
this->addChild(a,1);  


CCSprite* b=new CCSprite();  
b->initWithFile("red.png");   
b->setPosition(ccp(170,170));  
b->setVertexZ(0.5f);    
this->addChild(b,1);

so in theory, i should have one background, a red dot behind (vertex z 0.5f), and a blue dot on the front (vertex z 1.0f). But here is what i have:

Not good. this should be just two dots, not a red pacman…

Now, while trying i tried setting the background on layer 2 instead of layer 0 (so i expect to only see the background and no dots)

this->addChild(bg,0);

becomes

this->addChild(bg,2);

here is the result

so could someone please tell me what i am missing? thanks :slight_smile:

See my post here: http://www.cocos2d-x.org/boards/6/topics/25129

You need to apply the alpha test shader.

thanks, I actually saw your post but i thought it was only relevant when using a sprite batch. I will try to make it work this way.

Kevin, I tried doing like you explained in another post, and the issue is still there. I have the depth test and the 2d projection in the appdelegate as before. my code is now this:

  // spritebatch
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("batch1.plist");
    CCSpriteBatchNode *spriteBatch=CCSpriteBatchNode::create("batch1.png", 2);
    spriteBatch->setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey( kCCShader_PositionTextureColorAlphaTest )); 
    this->addChild(spriteBatch);

    //add the sprites
    CCSprite* a1=CCSprite::createWithSpriteFrameName("blue.png");
    CCSprite* a2=CCSprite::createWithSpriteFrameName("red.png");

    a1->setPosition(ccp(150,150));
    a2->setPosition(ccp(165,165));

    //red should be under blue
    a1->setVertexZ(1.0f);
    a2->setVertexZ(0.5f);

    this->addChild(a1,1);
    this->addChild(a2,1);

and the red dot is still masked by the part of the blue dot that was supposed to be transparent. any ideas what i should try? also, don’t you have issues with parts of the assets that you cannot add in the spritebatch? (i think it doesn’t work with particles for example?)
thanks

Ok I’ll try to clear up the confusion for you.

In the original code that you posted you would have needed to apply the shader to the scene node (CCLayer node).

pDirector->setDepthTest(true); 
pDirector->setProjection(kCCDirectorProjection2D);  

CCSprite* bg=new CCSprite();
bg->initWithFile("HelloWorld.png"); 
bg->setAnchorPoint(ccp(0,0));   
bg->setVertexZ(0.0f);    
this->addChild(bg,0);

CCSprite* a=new CCSprite();
a->initWithFile("blue.png");  
a->setPosition(ccp(150,150));   
a->setVertexZ(1.0f);    
this->addChild(a,1); 

CCSprite* b=new CCSprite();  
b->initWithFile("red.png");   
b->setPosition(ccp(170,170));  
b->setVertexZ(0.5f);    
this->addChild(b,1);

this->setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey( kCCShader_PositionTextureColorAlphaTest )); 

I think that your understanding of sprite batch nodes is a little wrong. Here is a pseudo example of a sprite batch hierarchy.

CCSpriteBatchNode* mybatch = CCSpriteBatchNode::create("myspritesheet.png");
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("myspritesheet.plist", "myspritesheet.png");
CCSprite* mysprite = CCSprite::createWithSpriteFrameName("myspriteframe.png");

mybatch->addChild(mysprite);
this->addChild(mybatch);

mybatch->setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey( kCCShader_PositionTextureColorAlphaTest ));

The files “myspritesheet.png” and “myspritesheet.plist” are actual files created from using a program such as TexturePacker.
The “myspriteframe.png” is not an actual file but is a frame that is loaded from the plist.

Hope this helps. (Btw, I’d recommend using the “create” functions instead of calling the “new” operator in most cases.)

Thanks a lot Kevin, this was very helpful.

To sum up, the batch method works, in my case the “batch1.png” and “batch1.plist” files were created in zwoptex from “blue.png” and "red.png; but I guess my method for creating the batch did not work very well with setVertexZ (it was working when I was not trying to reorder). For the first method however (setting the shader directly on the node), it doesn’t seem to work.

now, there are little transparent artefacts around the dots (a few pixels, I think I saw you mention this somewhere too), i hope this wont be a problem later!

thanks

Ah okay, thanks for the info. You may need to set the shader for each sprite instead of the CCLayer for the method that doesn’t use a sprite batch. The artifacts will go away if you rearrange the draw order (see the thread I linked). I arrange the draw order for most of my objects only once and then update the vertexz as the game progresses. You may be able to tweak the alpha test shader by changing the cutoff… I’m not 100% sure it will help but it may be worth trying. Here is a code snippet to show you what I mean.

alphashader = CCShaderCache::sharedShaderCache()->programForKey( kCCShader_PositionTextureColorAlphaTest );
alphaloc = glGetUniformLocation(alphashader->getProgram(), kCCUniformAlphaTestValue);
alphashader->setUniformLocationWith1f(alphaloc, alphacutoff);

thanks for that, I will give it a shot. i am still a super shader newbie, so i’m impressed by all this :slight_smile:

one other solution I may try is to switch to setZOrder altogether and use integers only. I plan to have my game scene not too big (maybe 4,000 pixels high max along the y axis), and I will rarely have to fine tune in which order two objects at the same y height should draw. so, let’s say I have to order 3 different objects max at the same y height (for example, hero weapon, hero, and a particle effect); that would be 12,000 z-order layers. it is ugly, but it seems robust.

do you think it would be worse, performance wise? after all, how bad can it be to use ints instead of floats…

If the order rarely changes on only a few objects you can could just use the reorderChild function every frame and set it to the inverted y axis value. If you do it this way you wouldn’t need to use the vertex z at all and could rely on the z order. This would keep you from having to use the alpha shader, 2d projection, depth testing, etc…

Here is some psuedocode:

void update(float dt)
{
  mybatch->reorderChild( mysprite1, -(mysprite1->getPositionY()+0.5f) );
  mybatch->reorderChild( mysprite2, -(mysprite2->getPositionY()+0.5f) );
}

Adding 0.5f would just simply round the value up or down to the closest integer value when the float is converted to int.
With only a few objects I think that reorderChild performance would be ok. If you find that you have quite a lot of things being reordered I would suggest switching to using the vertex z so that the ordering can be done on the GPU instead of the draw order.

hmm ok… I believe I won’t have too many objects that change their order often, so I will try to go this route. I will keep in my that it is not optimal when the number of objects increases however.
thanks a lot for your help!