Как сделать цвет сечения отличным на 3D-объекте - PullRequest
0 голосов
/ 16 октября 2018

У меня есть следующий 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-объекте, есть ли способ сделать это с помощью Qt3D?

Если это невозможно с Qt3D, как лучше всего это сделать с OpenGL ?


Я нашел обсуждение , которое, как мне кажется, было бы очень полезно.


После проведения некоторых исследований наилучший подход мог быиспользовать язык затенения OpenGL или GLSL .Я не уверен.

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

С помощью @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);
}

Когда я копирую код по умолчанию для шейдера Phong внутри моих файлов custom-shader.vert и custom-shader.frag, он работает точнокак и материал Phong, который показывает, что пользовательский эффект работает нормально.


Теперь, когда вышеупомянутый пользовательский эффект реализован, его шейдеры могут быть изменены методами, описанными @AdaRaider, для получения любого желаемого эффекта.

0 голосов
/ 17 октября 2018

В 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;
}
...