如何在3D对象上使部分的颜色不同

时间:2018-10-16 12:58:12

标签: opengl qt3d

我有以下3D对象:

tea pot

我的3D对象的材质使用Qt3D进行了这样的编码:

void MyClass::addMaterial(Qt3DCore::QEntity *entity)
{
    Qt3DExtras::QPhongMaterial * material = new Qt3DExtras::QPhongMaterial();
    material->setAmbient(QColor(245-30, 245-15, 245));
    material->setDiffuse(QColor(125-30, 125-15, 125));
    material->setSpecular(QColor(215-30, 255-15, 255));
    entity->addComponent(material);
}

上面的代码为3D对象实体统一赋予了相同的颜色。如何为实体的不同部分赋予不同的颜色?我想在我的3D对象上突出显示某些部分,是否可以使用Qt3D做到这一点?

如果Qt3D无法实现,那么 OpenGL 的最佳实践是什么?


我发现了一个discussion,我觉得这会很有帮助。


经过研究,最好的方法可能是使用OpenGL阴影语言或 GLSL 。我不确定。

2 个答案:

答案 0 :(得分:3)

在Qt中,我可以想象他们使用“材质”作为其预定义着色器的抽象。您创建了诸如QPhongMaterial这样的材质,您要使用该材质渲染实体并为其设置东西,这些东西将作为参数传递给着色器(均匀),例如环境,镜面反射和漫射照明颜色。

因此,您需要一个支持模型顶点颜色的着色器。因此,模型的每个顶点都将具有与之关联的颜色,并且这些值将传递到顶点着色器中并转发到片段着色器。使用OpenGL进行操作相当简单,但是您正在使用Qt3D,因此使用现有的基础结构可能会更容易。

Qt3D已经具有一些材质类,可用于创建其中一些着色器以应用于您的实体。您可以尝试改用QPerVertexColorMaterial。

https://doc.qt.io/qt-5/qt3dextras-qpervertexcolormaterial.html

  

Qt3DExtras :: QPerVertexColorMaterial的默认实现   渲染为每个顶点设置的颜色属性

很显然,您需要提供顶点颜色列表,以便对模型的各个部分进行不同的着色。除此之外,即使您要为三角形的每个顶点都上色相同的颜色(面色),也需要为每个顶点提供顶点颜色。

或者,您可以创建自己的着色器并将其提供给Qt3D以绑定到管道: (来自论坛)

  

Qt3D在运行时不会生成着色器。对于其默认管道,它带有预定义的默认着色器。但是,您可以随意更改管道(在C ++和QML中),并且可以使用自己的着色器。

对于定制材料,以下示例看起来很有希望: https://doc.qt.io/qt-5/qt3d-simplecustommaterial-example.html

有关Qt3D着色器的信息: https://doc.qt.io/qt-5/qml-qt3d-render-shaderprogram.html

  

ShaderProgram类封装了着色器程序。着色器程序由几个不同的着色器组成,例如顶点和片段着色器。   如果在着色器自省阶段遇到默认制服,则Qt3D将自动填充一组默认制服。

如果您从未用GLSL编写着色器并在OpenGL程序中对其进行编译,则可能需要首先了解如何完成顶点,几何和片段着色器的所有部分,以加快其完成速度以及属性和制服的作用。我想您仍然可以不做而完成工作,但我想这会困难得多。

着色器上有很多页面,但是只是短暂的...

着色器通常包括三个部分;顶点着色器,几何着色器和片段着色器是使用GLSL编写的,通常保存为三个文件。至少要编译着色器,您需要顶点着色器源和片段着色器源。

通常,人们喜欢使用相应的扩展名(例如.frag,.vert或.vs / .fs)保存这些文件,但最终它们只是文本文件。 要编译着色器并将其绑定到渲染管道,您需要从相应文件加载源并将其链接以创建着色器程序,然后将其绑定到渲染管道并渲染几何图形即可使用。 Lazy Foo有一个很棒的教程,介绍了如何在OpenGL中完成该操作:http://lazyfoo.net/tutorials/SDL/51_SDL_and_modern_opengl/index.php

如果仅使用OpenGL,则首先要编写一个顶点着色器,然后编写一个具有正确输入/输出的片段着色器,以渲染具有顶点颜色的几何图形,然后完成该过程以创建着色器程序。

对于着色器实现本身,这是顶点和片段着色器的外观的快速实现:

顶点着色器(Color.vs)

#version 330

in vec3 position;
in vec4 vertexColor;

uniform mat4 WORLD_VIEW_PROJECTION_MATRIX;

out vec4 fragColor;

void main()
{
  fragColor.x = vertexColor.x;
  fragColor.y = vertexColor.y;
  fragColor.z = vertexColor.z;
  fragColor.w = vertexColor.w; //alpha
  gl_Position = WORLD_VIEW_PROJECTION_MATRIX * vec4( position, 1 );
}

片段着色器(Color.fs)

#version 330 
out vec4 LFragment; 

in vec4 fragColor;

void main() 
{   
    LFragment = fragColor;
}

答案 1 :(得分:1)

在@AdaRaider的大力帮助下,我成功实现了具有可修改的顶点着色器和片段着色器的自定义效果。自定义效果可以这样使用:

#include "customeffect.h"

static const QColor ambientColor("#576675");  // Shader input
static const QColor diffuseColor("#5F6E7D");  // Shader input
static const QColor SpecularColor("#61707F"); // Shader input
static const float shininess(0.0);            // Shader input

void MyClass::addMaterial(Qt3DCore::QEntity *entity)
{
    Qt3DRender::QMaterial * material = new Qt3DRender::QMaterial();
    material->setEffect(new CustomEffect());
    material->addParameter(new Qt3DRender::QParameter(QStringLiteral("ka"), ambientColor));
    material->addParameter(new Qt3DRender::QParameter(QStringLiteral("kd"), diffuseColor));
    material->addParameter(new Qt3DRender::QParameter(QStringLiteral("ks"), SpecularColor));
    material->addParameter(new Qt3DRender::QParameter(QStringLiteral("shininess"), shininess));
    entity->addComponent(material);
}

自定义效果标题为:

#ifndef CUSTOMEFFECT_H
#define CUSTOMEFFECT_H

#include <Qt3DRender/QEffect>

class CustomEffect : public Qt3DRender::QEffect
{
public:
    explicit CustomEffect(Qt3DCore::QNode *parent = nullptr);
};

#endif // CUSTOMEFFECT_H

自定义效果的实现考虑了OpenGL的两个版本,即OpenGL ES 2.0 和OpenGL 3.1

#include "customeffect.h"

#include <Qt3DRender/QTechnique>
#include <Qt3DRender/QGraphicsApiFilter>
#include <QtCore/QUrl>

CustomEffect::CustomEffect(Qt3DCore::QNode *parent)
    : Qt3DRender::QEffect(parent)
{

    Qt3DRender::QTechnique *techniqueES20 = new Qt3DRender::QTechnique();
    techniqueES20->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
    techniqueES20->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGLES);
    techniqueES20->graphicsApiFilter()->setMajorVersion(2);
    techniqueES20->graphicsApiFilter()->setMinorVersion(0);

    Qt3DRender::QTechnique *techniqueGL31 = new Qt3DRender::QTechnique();
    techniqueGL31->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
    techniqueGL31->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
    techniqueGL31->graphicsApiFilter()->setMajorVersion(3);
    techniqueGL31->graphicsApiFilter()->setMinorVersion(1);

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

    techniqueES20->addFilterKey(filterkey);
    techniqueGL31->addFilterKey(filterkey);

    Qt3DRender::QShaderProgram *shader2 = new Qt3DRender::QShaderProgram();
    shader2->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/qt3deditorlib/shaders/es2/custom-shader.vert"))));
    shader2->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/qt3deditorlib/shaders/es2/custom-shader.frag"))));

    Qt3DRender::QShaderProgram *shader3 = new Qt3DRender::QShaderProgram();
    shader3->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/qt3deditorlib/shaders/gl3/custom-shader.vert"))));
    shader3->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/qt3deditorlib/shaders/gl3/custom-shader.frag"))));

    Qt3DRender::QRenderPass *renderPass2 = new Qt3DRender::QRenderPass();
    renderPass2->setShaderProgram(shader2);

    Qt3DRender::QRenderPass *renderPass3 = new Qt3DRender::QRenderPass();
    renderPass3->setShaderProgram(shader3);

    techniqueES20->addRenderPass(renderPass2);
    techniqueGL31->addRenderPass(renderPass3);

    addTechnique(techniqueES20);
    addTechnique(techniqueGL31);
}

当我在custom-shader.vertcustom-shader.frag文件中复制Phong着色器默认代码时,它的工作原理与Phong材质完全一样,表明自定义效果很好。


现在已实现上述自定义效果,可以使用@AdaRaider描述的方法修改其着色器以产生任何所需的效果。