viromedia / virocore

ViroCore cross-platform AR/VR renderer
MIT License
370 stars 108 forks source link

Transparent textures for intersecting VRONode not rendered as expected #318

Closed k4r1 closed 5 years ago

k4r1 commented 5 years ago

Environment

Please provide the following information about your environment:

  1. Development OS: Mac
  2. Device OS & Version: iPhone XS - iOS 13.1.2
  3. Version:
    • ViroCore: 2.17.0
  4. Device(s):
    • iPhone XS

Description

Rendering two intersecting nodes with transparent textures results in one of the textures being falsely occluded by transparent regions of the other, dependent on rendering order.

Note: This behaviour is observed in react-viro (https://github.com/viromedia/viro/issues/762) but it can also be recreated in ViroCore. So it seems like either:

Reproducible Demo

This is based on an issue I first experienced with Viro React and have now confirmed it is also present in ViroCore. To recreate, I hacked up the ARShadowTest.cpp with an example:

void AddCircle(std::shared_ptr<VROPortal> rootNode, float angle) {
    std::shared_ptr<VROImageiOS> image = std::make_shared<VROImageiOS>([UIImage imageNamed:@"debug-circle3.png"], VROTextureInternalFormat::RGBA8);
    std::shared_ptr<VROTexture> texture = std::make_shared<VROTexture>(true, VROMipmapMode::None, image, VROStereoMode::None);

    std::shared_ptr<VRONode> imageNode = std::make_shared<VRONode>();
    std::shared_ptr<VROSurface> imageSurface = VROSurface::createSurface(0.5, 0.5, 0, 0, 1, 1);

    imageNode->setPosition({ 0, 0, -6 });
    imageNode->setGeometry(imageSurface);

    imageNode->getGeometry()->getMaterials().front()->getDiffuse().setTexture(texture);
    imageNode->getGeometry()->getMaterials().front()->setTransparency(1.0);
    imageNode->setPosition({ 0, 0, -1 });
    imageNode->setRotation({ angle, angle, angle });
    rootNode->addChildNode(imageNode);
}

void VROARShadowTest::build(std::shared_ptr<VRORenderer> renderer,
                            std::shared_ptr<VROFrameSynchronizer> frameSynchronizer,
                            std::shared_ptr<VRODriver> driver) {

    _sceneController = std::make_shared<VROARSceneController>();
    std::shared_ptr<VROScene> scene = _sceneController->getScene();

    std::shared_ptr<VROPortal> rootNode = scene->getRootNode();
    rootNode->setPosition({0, 0, 0});

    std::shared_ptr<VROLight> ambient = std::make_shared<VROLight>(VROLightType::Ambient);
    ambient->setColor({ 0.3, 0.3, 0.3 });

    rootNode->addLight(ambient);

    AddCircle(rootNode, -0.7853);
    AddCircle(rootNode, 0.7853);
}

Note: debug-circle3.png is an image of a circle with transparency.

Similarly to https://github.com/viromedia/viro/issues/762, this renders the following (between screenshots I swapped the rendering order):

image

Expected: Two full circles to render

k4r1 commented 5 years ago

The issue becomes more apparent when you outline the planes on which the images are being rendered

image

dthian commented 5 years ago

Hey @k4r1, thanks for reaching out. I don't think changing the rendering order would help you here, as it looks like it might be a depth issue.

When rendering the second circle, if we see that there was something already drawn on that pixel that is closer to the camera in the depth buffer, the rendering is ignored (to avoid drawing a redundant pixel behind another pixel)

Could you try setting the imageNode material's setReadsFromDepthBuffer and/or setWritesToDepthBuffer to false and see if the issue occurs?

k4r1 commented 5 years ago

~Yes I just tried that and it did the trick!~ Thanks very much for your help.

(Edit: this wasn’t really fixed, it just seemed that way because the circles are transparent. Continuing discussion on the react-viro issue for now.)

The question remains as to what to do about this behaviour in react-viro, do you think we should change the usage such that setReadsFromDepthBuffer is false? Or give the user a way to toggle that from React?

k4r1 commented 5 years ago

Closing the issue here since this is an API usage issue and therefore the fix needs to be done in react-viro.