【问题标题】:Nested Stencil - OpenGL ES嵌套模板 - OpenGL ES
【发布时间】:2013-08-20 14:39:51
【问题描述】:

我有一个 2D 节点场景图,我正在尝试“嵌套”模板剪辑。

我在想我能做的就是在绘制模板时,将它写入的任何像素递增 1,并跟踪我所在的当前“层”是什么。

然后在绘制时,仅当该像素的模板值>=当前图层#时,才将像素数据写入颜色缓冲区。

这是我现在拥有的代码。这不太行。我在哪里搞砸了?

首先我调用 SetupStencilForMask()。 然后绘制模板图元。 接下来,调用 SetupStencilForDraw()。 现在绘制实际图像 完成图层后,调用 DisableStencil()。

编辑:已更新解决方案。它不适用于同一层上的单个项目,但其他都可以。 找到了一篇关于如何真正实现这一点的好文章,尽管它相当有限。 http://cranialburnout.blogspot.com/2014/03/nesting-and-overlapping-translucent.html

// glClear(GL_STENICL_BIT) at start of each draw frame
static int stencilLayer = 0;

void SetupStencilForMask(void)
{
    if (stencilLayer == 0)
        glEnable(GL_STENCIL_TEST);

    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glStencilFunc(GL_LESS, stencilLayer, 0xff);
    glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
    glStencilMask(0xff);

    if (stencilLayer == 0)
        glClear(GL_STENCIL_BUFFER_BIT);

    stencilLayer++;
}

void SetupStencilForDraw()
{   
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glStencilFunc(GL_EQUAL, stencilLayer, 0xff);
    glStencilMask(0x00);
}

void DisableStencil(void)
{
    if (--stencilLayer == 0)
        glDisable(GL_STENCIL_TEST);
}

【问题讨论】:

  • 嘿,成功了吗?我有一个类似的问题。将获得帮助。
  • 很遗憾,没有。如果您找到解决方案将不胜感激。我知道这是可能的,我只是对模板面具不太熟悉,而且它对我来说并不是什么大事。
  • 我同时找到了解决方案。我将在明天发布答案。

标签: c opengl-es


【解决方案1】:

我已经找到了在 libgdx 中执行此操作的方法。我不确定你是否仍然需要这个,但这里是代码供将来参考:

/**
 * Start cropping
 * 
 * @param cropMask
 *            Mask plane
 */
public void startCropping(Plane cropMask) {

    // Check if there is active masking group
    if (activeCropMaskGroup == null) {

        // Create new one
        activeCropMaskGroup = new CropMaskingGroupDescriptor(cropMask);
    } else {

        // Increase hierarchy level
        activeCropMaskGroup.increaseHierachy(cropMask);
    }

}

/** End cropping */
public void endCropping() throws IllegalStateException {

    // Check if there is active group mask
    if (activeCropMaskGroup == null) {
        throw new IllegalStateException("Call start cropping before this!");
    }

    if (activeCropMaskGroup.getHierachy() > 0) {

        activeCropMaskGroup.decreaseHierachy();
    } else {

        // Finish setup of crop data
        cropMaskGroups.add(activeCropMaskGroup);
        activeCropMaskGroup = null;
    }

}

/** Crop registered planes for cropping */
private void cropRender(CropMaskingGroupDescriptor cropMaskGroupDescriptor) {

    // Draw mask to stencil buffer
    Gdx.gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);

    // setup drawing to stencil buffer
    Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);

    // Number of registered hierarchy levels
    int hierarchyLevels = cropMaskGroupDescriptor.getRegisteredBatch().size();

    // Loop trough hierarchy
    for (int hierarchyLevel = 0; hierarchyLevel < hierarchyLevels; hierarchyLevel++) {

        Gdx.gl20.glStencilFunc(GL20.GL_ALWAYS, 0x1, 0xffffffff);
        Gdx.gl20.glStencilOp(GL20.GL_INCR, GL20.GL_INCR, GL20.GL_INCR);
        Gdx.gl20.glColorMask(false, false, false, false);
        Gdx.gl20.glDepthMask(false);

        // Draw mask with decal batch
        cropMaskBatch.add(((NativePlane) cropMaskGroupDescriptor.getCroppingMasks().get(hierarchyLevel)).getPlane());
        cropMaskBatch.flush();

        // fix stencil buffer, enable color buffer
        Gdx.gl20.glColorMask(true, true, true, true);
        Gdx.gl20.glDepthMask(true);
        Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP);

        // draw where pattern has been drawn
        Gdx.gl20.glStencilFunc(GL20.GL_LEQUAL, hierarchyLevel + 1, 0xffffffff);

        // Loop trough registered masked layers and found which one belongs
        // to
        // current hierarchy level
        for (int i = 0; i < cropMaskGroupDescriptor.getMaskedLayers().size(); i++) {

            if (cropMaskGroupDescriptor.getMaskedLayers().get(i).getHierarchyId() == hierarchyLevel) {

                Plane plane = cropMaskGroupDescriptor.getMaskedLayers().get(i).getMaskedPlane();
                cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).add(((NativePlane) plane).getPlane());
            }

        }

        cropMaskGroupDescriptor.getRegisteredBatch().get(hierarchyLevel).flush();

    }

    Gdx.gl20.glDisable(GL20.GL_STENCIL_TEST);

}

渲染器模块内部的内部类。

/** * 裁剪层描述符 * * @author Veljko Ilkic * */ 私有类 CropMaskLayerDescriptor {

    /** Layer that needs to be masked */
    private Plane maskedPlane;

    /** Hierarchy level in which belongs */
    private int hierarchyId = 0;

    /** Constructor 1 */
    public CropMaskLayerDescriptor(Plane maskedPlane, int hierarchyId) {
        this.maskedPlane = maskedPlane;
        this.hierarchyId = hierarchyId;
    }

    public Plane getMaskedPlane() {
        return maskedPlane;
    }

    public int getHierarchyId() {
        return hierarchyId;
    }

}

/**
 * Crop masking group descriptor class
 * 
 * @author Veljko Ilkic
 * 
 */
private class CropMaskingGroupDescriptor {

    /** Crop mask */
    private ArrayList<Plane> croppingMasks = new ArrayList<Plane>();

    /** Planes that will be masked by crop mask */
    private ArrayList<CropMaskLayerDescriptor> maskedLayers = new ArrayList<Renderer.CropMaskLayerDescriptor>();

    /** Batch for drawing masked planes */
    private ArrayList<DecalBatch> hierarchyBatches = new ArrayList<DecalBatch>();

    private int activeHierarchyLayerId = 0;

    /** Constructor 1 */
    public CropMaskingGroupDescriptor(Plane topLevelCropMask) {

        // Create batch for top level hierarchy
        hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));

        // Register top level crop mask
        croppingMasks.add(topLevelCropMask);
    }

    /** Increase hierarchy level of the group */
    public void increaseHierachy(Plane hierarchyCropMask) {
        activeHierarchyLayerId++;

        // Create individual batch for hierarchy level
        hierarchyBatches.add(new DecalBatch(new CameraGroupStrategy(perspectiveCamera)));

        // Register crop mask for current hierarchy level
        croppingMasks.add(hierarchyCropMask);
    }

    /** Decrease hierarchy group */
    public void decreaseHierachy() {
        activeHierarchyLayerId--;
    }

    /** Get current hierarchy level */
    public int getHierachy() {
        return activeHierarchyLayerId;
    }

    /** Register plane for masking */
    public void registerLayer(Plane maskedPlane) {
        hierarchyBatches.get(activeHierarchyLayerId).add(((NativePlane) maskedPlane).getPlane());
        maskedLayers.add(new CropMaskLayerDescriptor(maskedPlane, activeHierarchyLayerId));
    }

    /** Get all registered batched */
    public ArrayList<DecalBatch> getRegisteredBatch() {
        return hierarchyBatches;
    }

    /** Get registered cropping masks */
    public ArrayList<Plane> getCroppingMasks() {
        return croppingMasks;
    }

    /** Get layer that should be masked */
    public ArrayList<CropMaskLayerDescriptor> getMaskedLayers() {
        return maskedLayers;
    }

    /** Dispose */
    public void dispose() {
        for (int i = 0; i < hierarchyBatches.size(); i++) {
            hierarchyBatches.get(i).dispose();
            hierarchyBatches.set(i, null);
        }

        hierarchyBatches.clear();
    }
}

希望这会有所帮助。

【讨论】:

  • 我在我的实现中尝试了您的解决方案,但在让它工作时遇到了问题,经过大量测试,我确定根据使用情况,模板缓冲区操作不允许我一直在寻找的功能。但是你确实让我更接近它的工作,我已经更新了我的原始帖子,它可以正常工作,除非你想在同一层次结构级别上剪辑多个单独的项目。
猜你喜欢
  • 2011-11-26
  • 2010-12-14
  • 2013-01-22
  • 2011-03-09
  • 2020-04-10
  • 2014-12-18
  • 2012-06-18
  • 1970-01-01
  • 2012-02-22
相关资源
最近更新 更多