0

I made simple viewer that allow you to import .obj file, what I want to achieve is, when user selecting the model, shaders will draw model outlines in different color.

What I use to represent the .obj file is a QEntity with Custom QMaterial, Custom QPickerObject and QMesh.

With my Custom QMaterial I made simple Flat Shading(coloring based on face normal)

// My Custom QMaterial : 

explicit CustomizedMaterial(Qt3DCore::QNode *parent = nullptr) : QMaterial(parent)
{
                // Create effect, technique, render pass and shader
                Qt3DRender::QEffect *effect = new Qt3DRender::QEffect();
                Qt3DRender::QTechnique *gl3Technique = new Qt3DRender::QTechnique();
                Qt3DRender::QRenderPass *gl3Pass = new Qt3DRender::QRenderPass();
                Qt3DRender::QShaderProgram *glShader = new Qt3DRender::QShaderProgram();

        QByteArray ver(
                    "#version 330\n"

                    "out vec3 vViewPos;\n"

                    "in vec3 vertexPosition;\n"
                    "in vec3 vertexNormal;\n"

                    "uniform mat4 modelView;\n"
                    "uniform mat3 modelViewNormal;\n"
                    "uniform mat4 mvp;\n"

                    "void main()\n"
                    "{\n"
                        "vec4 pos = vec4(vertexPosition, 1.0);\n"
                        "vec4 mpos = modelView * pos;\n"
                        "gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
                        "vViewPos = -mpos.xyz;\n"
                    "}\n");

            QByteArray frag(
                        "#version 330\n"

                        "vec3 normals(vec3 pos)\n"
                         "{\n"
                           "vec3 fdx = dFdx(pos);\n"
                           "vec3 fdy = dFdy(pos);\n"
                           "return normalize(cross(fdx, fdy));\n"
                         "}\n"

                        "in vec3 vViewPos;\n"
                        "out vec4 fragColor;\n"

                    "void main()\n"
                    "{\n"
                        "vec3 normal = normals(vViewPos);\n"
                        "vec3 gray = vec3(0.9, 0.9, 0.9);\n"
                        "float theta = dot(normal, vec3(0, 0, 1)) / length(normal);\n"
                        "fragColor = vec4(gray * theta , 1.0);\n"
                    "}\n");

        glShader->setVertexShaderCode(ver);
        glShader->setFragmentShaderCode(frag);

        // Set the shader on the render pass
        gl3Pass->setShaderProgram(glShader);

        // filter
        Qt3DRender::QFilterKey *m_filterKey = new Qt3DRender::QFilterKey(this);
        m_filterKey->setName(QStringLiteral("renderingStyle"));
        m_filterKey->setValue(QStringLiteral("forward"));

        // Add the pass to the technique
        gl3Technique->addRenderPass(gl3Pass);

        // Set the targeted GL version for the technique
        gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
        gl3Technique->graphicsApiFilter()->setMajorVersion(3);
        gl3Technique->graphicsApiFilter()->setMinorVersion(2);
        gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);

        // Add filter
        gl3Technique->addFilterKey(m_filterKey);

        // Add the technique to the effect
        effect->addTechnique(gl3Technique);

        // Set the effect on the materials
        setEffect(effect);
    }

From my searching I think the easiest way is by using two rendering pass technique, sadly there is no documentation or example in Qt3d/C++ show me how to do it, can some one help ?

Thanks in advance.

Saif_Qaher94
  • 72
  • 11
  • Did you already have a look into the ShadowMap Example? It uses a two pass rendering approach. Unfortunately it's not C++ but QML although it can be easily translated (to C++). – vre Feb 06 '18 at 07:15
  • Maybe this example helps you: https://github.com/alpqr/q3dpostproc. It's in QML but like @Saif_Qaher94 already said that's (sort of) easy to translate to C++. They used two render passes to enable transparent objects, I'm unsure though how to achieve outlines like this. – Florian Blume Feb 15 '18 at 21:50

1 Answers1

2

Yes there is not much information in this regard unfortunately. It is looks like that Qt put more effort and resource into QML and not C++ / all examples are 5 to 1 in favor of QML/. Ok I manage to make custom shader work. I played with your code and changed just a few:

  1. I moved the configuration of the QTechnique immediately after the creation plus I change the order of initialization of the technique:

    gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);

    gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);

    gl3Technique->graphicsApiFilter()->setMajorVersion(3);

    gl3Technique->graphicsApiFilter()->setMinorVersion(1);

  2. I put QFilterKey for the technique

    Qt3DRender::QFilterKey *filterkey = new Qt3DRender::QFilterKey(this);

    filterkey->setName(QStringLiteral("renderingStyle"));

    filterkey->setValue(QStringLiteral("forward"));

  3. and I load shaders from resource the same way as is shown in example QML code :

    glShader->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/MyShader/simpleColor.vert"))));

    glShader->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/MyShader/simpleColor.frag"))));

I did not investigate which one of those is the main reason but is working.

After that I found another confirmation - the same way of processing - in this post

How to make color of a section be different on a 3D object from @AdaRaider and @user3405291

JPM
  • 69
  • 5