The realization principle of COCOS2DX Clippingnode

Source: Internet
Author: User

Clippingnode is implemented using OpenGL's clipping buffers, as it has recently been necessary to use this feature, and by the way this part of the implementation has been looked at.

The main steps of OpenGL clipping are as follows:

1. Turn on clip buffer

2. Set mask in the clipping buffer.

3, the normal drawing, this time will be based on the value of the clipping buffer and set a good comparison function to calculate, depending on whether or not to choose to know framebuffer

4. Close the crop buffer after drawing is complete

These steps are reflected in the following code in the COCOS2DX clippingnode:

<pre name= "code" class= "CPP" > _groupcommand.init (_globalzorder);    Renderer->addcommand (&_groupcommand);    Renderer->pushgroup (_groupcommand.getrenderqueueid ());    _beforevisitcmd.init (_globalzorder);   _beforevisitcmd.func = Cc_callback_0 (Clippingnode::onbeforevisit, this);    1 Renderer->addcommand (&_beforevisitcmd); if (_alphathreshold < 1) {#if (Cc_target_platform = = Cc_platform_mac | | Cc_target_platform = = Cc_platform_win32 | |        Cc_target_platform = = cc_platform_linux) #else//Since glalphatest do not exists on OES, use a shader that writes Pixel only if greater than an alpha threshold glprogram *program = glprogramcache::getinstance ()-&GT;GETGL        Program (GLPROGRAM::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST_NO_MV); Glint alphavaluelocation = glgetuniformlocation (Program->getprogram (), Glprogram::uniform_name_alpha_test_value        );        Set our Alphathreshold program->use (); Program->setunifoRMLOCATIONWITH1F (Alphavaluelocation, _alphathreshold); We need to recursively apply this shader to all the nodes in the stencil node//fixme:we should has a-to        Apply shader to all nodes without have to does this setprogram (_stencil, program);   #endif} _stencil->visit (renderer, _modelviewtransform, flags);    2 _afterdrawstencilcmd.init (_globalzorder);  _afterdrawstencilcmd.func = Cc_callback_0 (Clippingnode::onafterdrawstencil, this);    3 Renderer->addcommand (&_afterdrawstencilcmd);    int i = 0;    BOOL Visiblebycamera = Isvisitablebyvisitingcamera ();        4 if (!_children.empty ()) {Sortallchildren (); Draw children ZOrder < 0 for (; I < _children.size (); i++) {Auto node = _children.at (i                        ); if (node && node->getlocalzorder () < 0) node->visit (renderer, _modelviewtransform, flags            ); else BreAk                }//Self draw if (Visiblebycamera) This->draw (renderer, _modelviewtransform, flags); for (Auto It=_children.cbegin () +i; it! = _children.cend (); ++it) (*it)->visit (renderer, _modelviewtra    Nsform, flags);    } else if (Visiblebycamera) {This->draw (renderer, _modelviewtransform, flags);    } _aftervisitcmd.init (_globalzorder);   _aftervisitcmd.func = Cc_callback_0 (Clippingnode::onaftervisit, this); 5 Renderer->addcommand (&_aftervisitcmd);


There are 5 steps in this code:

1. Onbeforevisit function: The clipping buffer is started in this function, and the buffer comparison function is set.

2. Draw the cropped shape, where the alpha of the graph is used to determine what area can be drawn and what area is not drawn, and set the value of the clipping buffer by setting the comparison function.

3. After the clipping buffer setting is complete, the cropping parameters (comparison function and ref, mask, etc.) are reset.

4, draw the graph, pass the test will know Frambuffer.

5. Close the clip buffer. The above 1th, 2 steps together to complete the clipping buffer to mask the setup work.

3, 4 steps to complete the cutting work.

5 Steps clear the crop parameter configuration, close the clipping buffer, restore normal drawing.

Here's a look at how each step works:

The first step: to make it easy for me to comment directly in the code. (The Chinese note is my own understanding)

  <pre name= "code" class= "CPP" >/////////////////////////////////////INIT//increment the current layer s    _layer++;    This parameter is used in order to embed Clippingnode in Clippingnode, but through analysis I find a little bit of a bug here.    Mask of the current layer (ie:for layer 3:00000100) Glint Mask_layer = 0x1 << s_layer;    This value is used as a mask in the clipping buffer.    Mask of all layers less than the current (ie:for layer 3:00000011) Glint mask_layer_l = mask_layer-1; Mask of all layers less than or equal to the current (ie:for layer 3:00000111) _mask_layer_le = Mask_layer |    mask_layer_l;    Manually save the stencil state _currentstencilenabled = glisenabled (gl_stencil_test);    Glgetintegerv (Gl_stencil_writemask, (glint *) &_currentstencilwritemask);    Glgetintegerv (Gl_stencil_func, (glint *) &_currentstencilfunc);    Glgetintegerv (Gl_stencil_ref, &_currentstencilref);    Glgetintegerv (Gl_stencil_value_mask, (glint *) &_currentstencilvaluemask); Glgetintegerv (Gl_stencil_fail, (GLinT *) &_currentstencilfail);    Glgetintegerv (Gl_stencil_pass_depth_fail, (glint *) &_currentstencilpassdepthfail);    Glgetintegerv (Gl_stencil_pass_depth_pass, (glint *) &_currentstencilpassdepthpass);    Enable stencil use glenable (gl_stencil_test);    Check for OpenGL error while enabling stencil test check_gl_error_debug ();  All bits on the stencil buffer is readonly, except the current layer bit,//This means that operation like Glclear   Or Glstencilop is masked with this value glstencilmask (Mask_layer); Set the currently used see buffer ID//Manually save the depth test state glgetbooleanv (Gl_depth_writemask, &_currentdepthwritemask    );    Disable depth test while drawing the stencil//gldisable (gl_depth_test); Disable update to the depth buffer while drawing the stencil,//As the stencil are not meant to being rendered in the R EAL scene,//it should never prevent something else to being drawn,//Only disabling depth buffer update ShouLD do Gldepthmask (gl_false); Close depth detection/////////////////////////////////////clear stencil buffer//manually clear the stencil buffer by draw ing a fullscreen rectangle on it/setup the stencil test func like this://For each pixel in the fullscreen recta Ngle//Never draw it into the frame buffer//if not in inverted mode:set the current layer value to 0 in The stencil buffer//If in inverted mode:set the current layer value to 1 in the stencil buffer Glstencilfunc (  Gl_never, Mask_layer, Mask_layer); Sets the comparison function and parameter glstencilop of the clipping buffer (!_inverted?   Gl_zero:gl_replace, Gl_keep, gl_keep);    Sets the operation that the comparison failed or passed to the crop buffer after. These two functions are the most important two functions to operate the clipping buffer, followed by a detailed introduction//Draw a fullscreen solid rectangle to clear the stencil buffer//ccdrawsolidrect    (Vec2::zero, Ccpfromsize ([[Director Shareddirector] winsize]), color4f (1, 1, 1, 1));  Drawfullscreenquadclearstencil (); This is done once, as the test function is set to Gl_never, which means that it will never pass the test, so this draw will not be drawn to the clipping buffer, as shown by the Glstencilop function aboveIf you do not take the inverse then the buffer is all 0, otherwise it is all mask_layer. DRAW CLIPPING stencil//Setup the stencil test func like this://For EAC h pixel in the stencil node//never draw it into the frame buffer//if not in inverted mode:set the Curre NT layer value to 1 in the stencil buffer//If in inverted mode:set the current layer value to 0 in the stencil b    uffer//here again set the comparison function and operation: If not reversed, then the buffer will be set to Mask_layer, otherwise set to 0 glstencilfunc (Gl_never, Mask_layer, Mask_layer); Glstencilop (!_inverted?   Gl_replace:gl_zero, Gl_keep, gl_keep);          Because we are using the alpha of the image to crop, so for non-gles platform, directly use the Alphatest function://For the area passed Alpha test, if inverse, set to Mask_layer, otherwise set 0.  If it is a opengles platform, because Alphatest is not supported, a custom shader is used to implement Alphatest, this shader is simple, if the alpha is drawn, if not passed, directly discard.    Opengles set shader code in the above section of the code, is to modify node Shaderprogram. Enable Alpha Test only if the alpha threshold < 1,//indeed if alpha threshold = = 1, every pixel would be drawn a Nyways if (_alphathreshold &lT 1) {#if (Cc_target_platform = = Cc_platform_mac | | Cc_target_platform = = Cc_platform_win32 | | Cc_target_platform = = cc_platform_linux)//Manually save the alpha Test state _currentalphatestenabled = GL        IsEnabled (gl_alpha_test);        Glgetintegerv (Gl_alpha_test_func, (glint *) &_currentalphatestfunc);        GLGETFLOATV (Gl_alpha_test_ref, &_currentalphatestref);        Enable Alpha testing glenable (gl_alpha_test);        Check for OpenGL error while enabling Alpha Test check_gl_error_debug ();        Pixel'll be drawn only if greater than an alpha threshold Glalphafunc (Gl_greater, _alphathreshold); #else #endif}//draw _stencil


From the above note, after the function has been executed, the buffer has been set to the following conditions:

If not reversed, the buffer is now all 0

If reversed, it is all Mask_layer

Also, a new comparison function and alphatest are set, and if the next draw operation is performed, the buffer through the alphatest portion is reset:

If not reversed, the buffer through the alphatest portion is Mask_layer

If reversed, the buffer through the alphatest portion is 0

The second step: As mentioned above, the cropped image is drawn, when the buffered clipping mask has been set.

Step three: Re-set the cropping function and operation to crop the child nodes in node: Take a look at the parameter settings for the third step:

    Gldepthmask (_currentdepthwritemask);   <span style= "White-space:pre" ></span>//recovery before the depth detection settings    <span style= "White-space:pre" ></span >//set the comparison function to gl_equal, the meaning of this parameter is: Mask_layer_le & mask_layer_le = = mask & Mask_layer_le Pass the test, otherwise do not pass     // Mask refers to the value corresponding to the corresponding position in the clipping buffer. The calculation of Mask_leyer_le in the     above code and the setting of the clipping buffer: the Maks in the buffer is either 0 or mask_layer     //Fruit layer greater than 0, then Mask_layer & Mask_ Layer_le = Mask_layer     //And Mask_layer_le & mask_layer_le = Mask_layer_le and Mask_layer! = Mask_layer_le, That is, if the clippingnode has nested, then the second level nesting start all node will be cut off, and the original meaning does not match, in fact, it is only necessary to continue to set mask_layer, because each layer has its own clipping buffer. I do not know whether my understanding is correct, ask for advice. </span>    Glstencilfunc (gl_equal, _mask_layer_le, _mask_layer_le);    Glstencilop (Gl_keep, Gl_keep, gl_keep);  The meaning of this function is to ensure that the clipping buffer is no longer modified, either through or without clipping tests.


The fourth step: is to draw children, at the time of drawing according to the above mentioned cutting test way to cut;

If you do not take the inverse then pass the alphatest section to pass the test, that is, the cropped image transparency is greater than the alpha part is drawn

If reversed, it is not passed through the alphatest part of the test, that is, the cropped image transparency is less than the alpha portion being drawn.

Fifth step: Restore the saved cropping parameters (select the previous layer of the clipping buffer or close the clipping buffer, set the previous layer of the Cut function configuration)

These are the things that clippingnode do, and the following is a detailed description of the two functions used above:

Glstencilfunc (func, ref, mask) The function is used to set the comparison function of the clipping buffer, and each function corresponds to the following comparison method:

Gl_never
Always fails.

Gl_less
Passes if (ref & Mask) < (stencil & mask).

Gl_lequal
Passes if (ref & Mask) <= (stencil & mask).

Gl_greater
Passes if (ref & Mask) > (Stencil & Mask).

Gl_gequal
Passes if (ref & Mask) >= (stencil & mask).

Gl_equal
Passes if (ref & mask) = (stencil & mask).

Gl_notequal
Passes if (ref & mask)! = (stencil & mask).

Gl_always
Always passes.

Ii. Glstencilop (Sfail, Dpfail, Dppass)

These three parameters are used to manipulate the cropping buffer separately under different conditions

The first parameter represents an action that is done in the case of a clipping test failure

The second parameter represents the action when the clipping test passes and the depth test fails

The third parameter represents the operation when both the clipping and the depth test pass,

There are several ways to do this:

Gl_keep
Keeps the current value.

Gl_zero
Sets the stencil buffer value to 0.

Gl_replace
Sets the stencil buffer value to ref, as specified by Glstencilfunc.

Gl_incr
Increments the current stencil buffer value. Clamps to the maximum representable unsigned value.

Gl_incr_wrap
Increments the current stencil buffer value. Wraps stencil buffer value to zero when incrementing the maximum representable unsigned value.

Gl_decr
Decrements the current stencil buffer value. Clamps to 0.

Gl_decr_wrap
Decrements the current stencil buffer value. Wraps stencil buffer value to the maximum representable unsigned value when decrementing a stencil buffer value of zero.

Gl_invert
Bitwise inverts the current stencil buffer value.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

The realization principle of COCOS2DX Clippingnode

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.