如何使一个部分的颜色在 3D 对象上不同
How to make color of a section be different on a 3D object
我有以下 3D 对象:
我的 3D 对象的 material 使用 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。我不确定。
在 Qt 中,我想他们正在使用 "materials" 作为他们预定义着色器的抽象。您创建一个 material,例如 QPhongMaterial,您希望使用它来渲染实体并为其设置内容 material,它将作为参数传递给着色器(制服),例如环境光、镜面反射和漫射照明颜色.
所以您需要一个支持模型顶点颜色的着色器。所以模型的每个顶点都会有一个与之关联的颜色,这些值会传递到顶点着色器并转发到片段着色器。使用 OpenGL 执行此操作相当简单,但您使用的是 Qt3D,因此使用已有的基础结构可能更容易。
Qt3D 已经有一些 material 类 可以用来创建其中一些着色器以应用于您的实体。您可以尝试改用 QPerVertexColorMaterial。
https://doc.qt.io/qt-5/qt3dextras-qpervertexcolormaterial.html
Qt3DExtras::QPerVertexColorMaterial Default implementation for
rendering the color properties set for each vertex
显然,您需要提供顶点颜色列表,以便对模型的各个部分进行不同的着色。除此之外,您还需要为每个顶点提供顶点颜色,即使您想为三角形的每个顶点都涂上相同的颜色(面颜色)。
或者,您可以创建自己的着色器并将其提供给 Qt3D 以绑定到管道:
(来自论坛)
Qt3D does not generate shaders at runtime. For its default pipeline it comes with predefined default shaders. But you are free to change the pipeline as you wish (in C++ and also in QML) and you can use your own shaders.
对于自定义 materials,以下示例看起来很有希望:
https://doc.qt.io/qt-5/qt3d-simplecustommaterial-example.html
关于 Qt3D 着色器的信息:
https://doc.qt.io/qt-5/qml-qt3d-render-shaderprogram.html
ShaderProgram class encapsulates a shader program. A shader program consists of several different shaders, such as vertex and fragment shaders.
Qt3D will automatically populate a set of default uniforms if they are encountered during the shader instrospection phase.
如果您从未在 GLSL 中编写过着色器并在 OpenGL 程序中编译过它,您可能希望首先了解如何完成,因为您需要了解顶点、几何和片段的部分着色器都扮演着属性和制服的角色。我想你仍然可以在不这样做的情况下完成工作,但我想这会更加困难。
着色器上有很多页面,但只是短暂...
一个着色器一般由三部分组成;顶点着色器、几何着色器和片段着色器,这些是使用 GLSL 编写的,通常保存为三个文件。至少要编译着色器,您需要顶点着色器源和片段着色器源。
通常人们喜欢用相应的扩展名保存这些文件,例如 .frag、.vert 或 .vs/.fs,但最终它们只是文本文件。
要编译着色器并将其绑定到渲染管道,您需要从相应的文件加载源代码并 link 它们来创建您的着色器程序,然后您可以通过将其绑定到渲染管道并渲染几何图形来使用它。 Lazy Foo 有一个关于如何在 OpenGL 中完成的很棒的教程:http://lazyfoo.net/tutorials/SDL/51_SDL_and_modern_opengl/index.php
如果您只是使用 OpenGL,您将首先编写一个顶点着色器,然后编写一个具有正确 inputs/outputs 的片段着色器来渲染具有顶点颜色的几何体,然后您将完成该过程以创建您的着色器程序.
至于着色器实现本身,这里是顶点和片段着色器的快速实现:
顶点着色器(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;
}
在@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);
}
自定义效果header是:
#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.vert
和 custom-shader.frag
文件中复制 Phong 着色器默认代码时,它的工作方式与 Phong material 完全一样,这表明自定义效果工作正常。
既然已经实现了上面的自定义效果,那么可以通过@AdaRaider 描述的方法修改它的着色器来产生任何想要的效果。
我有以下 3D 对象:
我的 3D 对象的 material 使用 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。我不确定。
在 Qt 中,我想他们正在使用 "materials" 作为他们预定义着色器的抽象。您创建一个 material,例如 QPhongMaterial,您希望使用它来渲染实体并为其设置内容 material,它将作为参数传递给着色器(制服),例如环境光、镜面反射和漫射照明颜色.
所以您需要一个支持模型顶点颜色的着色器。所以模型的每个顶点都会有一个与之关联的颜色,这些值会传递到顶点着色器并转发到片段着色器。使用 OpenGL 执行此操作相当简单,但您使用的是 Qt3D,因此使用已有的基础结构可能更容易。
Qt3D 已经有一些 material 类 可以用来创建其中一些着色器以应用于您的实体。您可以尝试改用 QPerVertexColorMaterial。
https://doc.qt.io/qt-5/qt3dextras-qpervertexcolormaterial.html
Qt3DExtras::QPerVertexColorMaterial Default implementation for rendering the color properties set for each vertex
显然,您需要提供顶点颜色列表,以便对模型的各个部分进行不同的着色。除此之外,您还需要为每个顶点提供顶点颜色,即使您想为三角形的每个顶点都涂上相同的颜色(面颜色)。
或者,您可以创建自己的着色器并将其提供给 Qt3D 以绑定到管道: (来自论坛)
Qt3D does not generate shaders at runtime. For its default pipeline it comes with predefined default shaders. But you are free to change the pipeline as you wish (in C++ and also in QML) and you can use your own shaders.
对于自定义 materials,以下示例看起来很有希望: https://doc.qt.io/qt-5/qt3d-simplecustommaterial-example.html
关于 Qt3D 着色器的信息: https://doc.qt.io/qt-5/qml-qt3d-render-shaderprogram.html
ShaderProgram class encapsulates a shader program. A shader program consists of several different shaders, such as vertex and fragment shaders. Qt3D will automatically populate a set of default uniforms if they are encountered during the shader instrospection phase.
如果您从未在 GLSL 中编写过着色器并在 OpenGL 程序中编译过它,您可能希望首先了解如何完成,因为您需要了解顶点、几何和片段的部分着色器都扮演着属性和制服的角色。我想你仍然可以在不这样做的情况下完成工作,但我想这会更加困难。
着色器上有很多页面,但只是短暂...
一个着色器一般由三部分组成;顶点着色器、几何着色器和片段着色器,这些是使用 GLSL 编写的,通常保存为三个文件。至少要编译着色器,您需要顶点着色器源和片段着色器源。
通常人们喜欢用相应的扩展名保存这些文件,例如 .frag、.vert 或 .vs/.fs,但最终它们只是文本文件。 要编译着色器并将其绑定到渲染管道,您需要从相应的文件加载源代码并 link 它们来创建您的着色器程序,然后您可以通过将其绑定到渲染管道并渲染几何图形来使用它。 Lazy Foo 有一个关于如何在 OpenGL 中完成的很棒的教程:http://lazyfoo.net/tutorials/SDL/51_SDL_and_modern_opengl/index.php
如果您只是使用 OpenGL,您将首先编写一个顶点着色器,然后编写一个具有正确 inputs/outputs 的片段着色器来渲染具有顶点颜色的几何体,然后您将完成该过程以创建您的着色器程序.
至于着色器实现本身,这里是顶点和片段着色器的快速实现:
顶点着色器(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;
}
在@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);
}
自定义效果header是:
#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.vert
和 custom-shader.frag
文件中复制 Phong 着色器默认代码时,它的工作方式与 Phong material 完全一样,这表明自定义效果工作正常。
既然已经实现了上面的自定义效果,那么可以通过@AdaRaider 描述的方法修改它的着色器来产生任何想要的效果。