Fix textures

master
Jeremy HU 2022-09-24 23:31:49 +10:00
parent 81063eaaaf
commit 29f7e06701
19 changed files with 472 additions and 86 deletions

View File

@ -1,13 +1,23 @@
#version 110
uniform vec3 eyePosition;
uniform sampler2D environmentIrradianceMapId[6];
uniform sampler2D environmentSpecularMapId[6];
uniform sampler2D textureId;
uniform int textureEnabled;
uniform sampler2D normalMapId;
uniform int normalMapEnabled;
uniform sampler2D metalnessRoughnessAoMapId;
uniform int metalnessMapEnabled;
uniform int roughnessMapEnabled;
uniform int aoMapEnabled;
uniform vec3 eyePosition;
varying vec3 pointPosition;
varying vec3 pointNormal;
varying vec3 pointColor;
varying vec2 pointTexCoord;
varying float pointAlpha;
varying float pointMetalness;
varying float pointRoughness;
varying mat3 pointTBN;
const float PI = 3.1415926;
@ -45,9 +55,34 @@ vec4 texturesAsCube(in sampler2D maps[6], in vec3 direction)
vec2 st;
cubemap(direction, texId, st);
vec4 color = vec4(0);
for (int i = 0; i < 6; ++i) {
vec4 side = texture2D(maps[i], st);
float select = step(float(i) - 0.5, texId) * step(texId, float(i) + 0.5);
{
vec4 side = texture2D(maps[0], st);
float select = step(0.0 - 0.5, texId) * step(texId, 0.0 + 0.5);
color = mix(color, side, select);
}
{
vec4 side = texture2D(maps[1], st);
float select = step(1.0 - 0.5, texId) * step(texId, 1.0 + 0.5);
color = mix(color, side, select);
}
{
vec4 side = texture2D(maps[2], st);
float select = step(2.0 - 0.5, texId) * step(texId, 2.0 + 0.5);
color = mix(color, side, select);
}
{
vec4 side = texture2D(maps[3], st);
float select = step(3.0 - 0.5, texId) * step(texId, 3.0 + 0.5);
color = mix(color, side, select);
}
{
vec4 side = texture2D(maps[4], st);
float select = step(4.0 - 0.5, texId) * step(texId, 4.0 + 0.5);
color = mix(color, side, select);
}
{
vec4 side = texture2D(maps[5], st);
float select = step(5.0 - 0.5, texId) * step(texId, 5.0 + 0.5);
color = mix(color, side, select);
}
return color;
@ -55,23 +90,48 @@ vec4 texturesAsCube(in sampler2D maps[6], in vec3 direction)
void main()
{
vec3 n = pointNormal;
vec3 color = pointColor;
float alpha = pointAlpha;
if (1 == textureEnabled) {
vec4 textColor = texture2D(textureId, pointTexCoord);
color = textColor.rgb;
alpha = textColor.a;
}
vec3 normal = pointNormal;
if (1 == normalMapEnabled) {
normal = texture2D(normalMapId, pointTexCoord).rgb;
normal = pointTBN * normalize(normal * 2.0 - 1.0);
}
float metalness = pointMetalness;
if (1 == metalnessMapEnabled) {
metalness = texture2D(metalnessRoughnessAoMapId, pointTexCoord).b;
}
float roughness = pointRoughness;
if (1 == roughnessMapEnabled) {
roughness = texture2D(metalnessRoughnessAoMapId, pointTexCoord).g;
}
float ambientOcclusion = 1.0;
if (1 == aoMapEnabled) {
ambientOcclusion = texture2D(metalnessRoughnessAoMapId, pointTexCoord).r;
}
vec3 n = normal;
vec3 v = normalize(eyePosition - pointPosition);
vec3 r = reflect(-v, n);
float NoV = abs(dot(n, v)) + 1e-5;
vec3 irradiance = texturesAsCube(environmentIrradianceMapId, r).rgb;
vec3 diffuse = irradiance * (1.0 - pointMetalness) * pointColor;
vec3 diffuse = irradiance * (1.0 - metalness) * pointColor;
vec3 f0 = mix(vec3(0.04), pointColor, pointMetalness);
vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, pointRoughness);
vec3 f0 = mix(vec3(0.04), pointColor, metalness);
vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness);
vec3 specular = fresnelFactor * texturesAsCube(environmentSpecularMapId, r).rgb;
vec3 color = diffuse + specular;
color = (diffuse + specular) * ambientOcclusion;
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
gl_FragColor = vec4(color, pointAlpha);
gl_FragColor = vec4(color, alpha);
}

View File

@ -8,24 +8,43 @@ attribute float roughness;
attribute vec3 tangent;
attribute float alpha;
uniform mat4 modelMatrix;
uniform mat3 normalMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform vec3 eyePosition;
uniform int normalMapEnabled;
varying vec3 pointPosition;
varying vec3 pointNormal;
varying vec3 pointColor;
varying vec2 pointTexCoord;
varying float pointAlpha;
varying float pointMetalness;
varying float pointRoughness;
varying mat3 pointTBN;
mat3 transpose(mat3 m)
{
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
void main()
{
pointPosition = (modelMatrix * vertex).xyz;
pointNormal = normalize((modelMatrix * vec4(normal, 1.0)).xyz);
pointColor = color;
pointTexCoord = texCoord;
pointAlpha = alpha;
pointMetalness = metalness;
pointRoughness = roughness;
gl_Position = projectionMatrix * viewMatrix * vec4(pointPosition, 1.0);
if (1 == normalMapEnabled) {
vec3 T = normalize(normalMatrix * tangent);
vec3 N = normalize(normalMatrix * normal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
pointTBN = mat3(T, B, N);
}
}

View File

@ -1,13 +1,23 @@
#version 330
uniform vec3 eyePosition;
uniform samplerCube environmentIrradianceMapId;
uniform samplerCube environmentSpecularMapId;
uniform sampler2D textureId;
uniform int textureEnabled;
uniform sampler2D normalMapId;
uniform int normalMapEnabled;
uniform sampler2D metalnessRoughnessAoMapId;
uniform int metalnessMapEnabled;
uniform int roughnessMapEnabled;
uniform int aoMapEnabled;
uniform vec3 eyePosition;
in vec3 pointPosition;
in vec3 pointNormal;
in vec3 pointColor;
in vec2 pointTexCoord;
in float pointAlpha;
in float pointMetalness;
in float pointRoughness;
in mat3 pointTBN;
out vec4 fragColor;
const float PI = 3.1415926;
@ -19,23 +29,48 @@ vec3 fresnelSchlickRoughness(float NoV, vec3 f0, float roughness)
void main()
{
vec3 n = pointNormal;
vec3 color = pointColor;
float alpha = pointAlpha;
if (1 == textureEnabled) {
vec4 textColor = texture(textureId, pointTexCoord);
color = textColor.rgb;
alpha = textColor.a;
}
vec3 normal = pointNormal;
if (1 == normalMapEnabled) {
normal = texture(normalMapId, pointTexCoord).rgb;
normal = pointTBN * normalize(normal * 2.0 - 1.0);
}
float metalness = pointMetalness;
if (1 == metalnessMapEnabled) {
metalness = texture(metalnessRoughnessAoMapId, pointTexCoord).b;
}
float roughness = pointRoughness;
if (1 == roughnessMapEnabled) {
roughness = texture(metalnessRoughnessAoMapId, pointTexCoord).g;
}
float ambientOcclusion = 1.0;
if (1 == aoMapEnabled) {
ambientOcclusion = texture(metalnessRoughnessAoMapId, pointTexCoord).r;
}
vec3 n = normal;
vec3 v = normalize(eyePosition - pointPosition);
vec3 r = reflect(-v, n);
float NoV = abs(dot(n, v)) + 1e-5;
vec3 irradiance = texture(environmentIrradianceMapId, r).rgb;
vec3 diffuse = irradiance * (1.0 - pointMetalness) * pointColor;
vec3 diffuse = irradiance * (1.0 - metalness) * pointColor;
vec3 f0 = mix(vec3(0.04), pointColor, pointMetalness);
vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, pointRoughness);
vec3 f0 = mix(vec3(0.04), pointColor, metalness);
vec3 fresnelFactor = fresnelSchlickRoughness(NoV, f0, roughness);
vec3 specular = fresnelFactor * texture(environmentSpecularMapId, r, 0.0).rgb;
vec3 color = diffuse + specular;
color = (diffuse + specular) * ambientOcclusion;
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
fragColor = vec4(color, pointAlpha);
fragColor = vec4(color, alpha);
}

View File

@ -8,24 +8,43 @@ layout(location = 5) in float roughness;
layout(location = 6) in vec3 tangent;
layout(location = 7) in float alpha;
uniform mat4 modelMatrix;
uniform mat3 normalMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform vec3 eyePosition;
uniform int normalMapEnabled;
out vec3 pointPosition;
out vec3 pointNormal;
out vec3 pointColor;
out vec2 pointTexCoord;
out float pointAlpha;
out float pointMetalness;
out float pointRoughness;
out mat3 pointTBN;
mat3 transpose(mat3 m)
{
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
void main()
{
pointPosition = (modelMatrix * vertex).xyz;
pointNormal = normalize((modelMatrix * vec4(normal, 1.0)).xyz);
pointColor = color;
pointTexCoord = texCoord;
pointAlpha = alpha;
pointMetalness = metalness;
pointRoughness = roughness;
gl_Position = projectionMatrix * viewMatrix * vec4(pointPosition, 1.0);
if (1 == normalMapEnabled) {
vec3 T = normalize(normalMatrix * tangent);
vec3 N = normalize(normalMatrix * normal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
pointTBN = mat3(T, B, N);
}
}

View File

@ -80,7 +80,6 @@ signals:
void turnaroundChanged();
void editModeChanged();
void resultTextureChanged();
void resultColorTextureChanged();
void postProcessedResultChanged();
void partSubdivStateChanged(dust3d::Uuid partId);
void partXmirrorStateChanged(dust3d::Uuid partId);

View File

@ -251,7 +251,6 @@ DocumentWindow::DocumentWindow()
m_modelRenderWidget->setMoveAndZoomByWindow(false);
m_modelRenderWidget->move(0, 0);
m_modelRenderWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
m_modelRenderWidget->enableEnvironmentLight();
m_modelRenderWidget->toggleWireframe();
m_modelRenderWidget->disableCullFace();
m_modelRenderWidget->setEyePosition(QVector3D(0.0, 0.0, -4.0));
@ -726,10 +725,6 @@ DocumentWindow::DocumentWindow()
resultTextureMesh->removeColor();
m_modelRenderWidget->updateMesh(resultTextureMesh);
});
connect(m_document, &Document::resultColorTextureChanged, [=]() {
if (nullptr != m_document->textureImage)
m_modelRenderWidget->updateColorTexture(new QImage(*m_document->textureImage));
});
connect(m_document, &Document::resultMeshChanged, [=]() {
auto resultMesh = m_document->takeResultMesh();

View File

@ -25,7 +25,7 @@ int main(int argc, char *argv[])
//freopen("dust3d.log", "w", stdout);
//setvbuf(stdout, 0, _IONBF, 0);
DocumentWindow *firstWindow = DocumentWindow::createDocumentWindow();
DocumentWindow::createDocumentWindow();
return app.exec();
}

View File

@ -50,7 +50,6 @@ MaterialEditWidget::MaterialEditWidget(const Document *document, QWidget *parent
m_previewWidget->setMinimumSize(128, 128);
m_previewWidget->resize(512, 512);
m_previewWidget->move(-128, -128);
m_previewWidget->enableEnvironmentLight();
m_previewWidget->setNotGraphics(true);
QFont nameFont;

View File

@ -13,7 +13,6 @@ MaterialWidget::MaterialWidget(const Document *document, dust3d::Uuid materialId
m_previewWidget->setFixedSize(Theme::materialPreviewImageSize, Theme::materialPreviewImageSize);
m_previewWidget->enableMove(false);
m_previewWidget->enableZoom(false);
m_previewWidget->enableEnvironmentLight();
m_nameLabel = new QLabel;
m_nameLabel->setAlignment(Qt::AlignCenter);

View File

@ -26,8 +26,8 @@ ModelMesh::ModelMesh(const ModelMesh &mesh) :
if (nullptr != mesh.m_normalMapImage) {
this->m_normalMapImage = new QImage(*mesh.m_normalMapImage);
}
if (nullptr != mesh.m_metalnessRoughnessAmbientOcclusionImage) {
this->m_metalnessRoughnessAmbientOcclusionImage = new QImage(*mesh.m_metalnessRoughnessAmbientOcclusionImage);
if (nullptr != mesh.m_metalnessRoughnessAmbientOcclusionMapImage) {
this->m_metalnessRoughnessAmbientOcclusionMapImage = new QImage(*mesh.m_metalnessRoughnessAmbientOcclusionMapImage);
this->m_hasMetalnessInImage = mesh.m_hasMetalnessInImage;
this->m_hasRoughnessInImage = mesh.m_hasRoughnessInImage;
this->m_hasAmbientOcclusionInImage = mesh.m_hasAmbientOcclusionInImage;
@ -46,8 +46,8 @@ void ModelMesh::removeColor()
delete this->m_normalMapImage;
this->m_normalMapImage = nullptr;
delete this->m_metalnessRoughnessAmbientOcclusionImage;
this->m_metalnessRoughnessAmbientOcclusionImage = nullptr;
delete this->m_metalnessRoughnessAmbientOcclusionMapImage;
this->m_metalnessRoughnessAmbientOcclusionMapImage = nullptr;
this->m_hasMetalnessInImage = false;
this->m_hasRoughnessInImage = false;
@ -185,7 +185,7 @@ ModelMesh::~ModelMesh()
m_triangleVertexCount = 0;
delete m_textureImage;
delete m_normalMapImage;
delete m_metalnessRoughnessAmbientOcclusionImage;
delete m_metalnessRoughnessAmbientOcclusionMapImage;
}
const std::vector<dust3d::Vector3> &ModelMesh::vertices()
@ -223,6 +223,13 @@ const QImage *ModelMesh::textureImage()
return m_textureImage;
}
QImage *ModelMesh::takeTextureImage()
{
auto image = m_textureImage;
m_textureImage = nullptr;
return image;
}
void ModelMesh::setNormalMapImage(QImage *normalMapImage)
{
m_normalMapImage = normalMapImage;
@ -233,14 +240,28 @@ const QImage *ModelMesh::normalMapImage()
return m_normalMapImage;
}
const QImage *ModelMesh::metalnessRoughnessAmbientOcclusionImage()
QImage *ModelMesh::takeNormalMapImage()
{
return m_metalnessRoughnessAmbientOcclusionImage;
auto image = m_normalMapImage;
m_normalMapImage = nullptr;
return image;
}
void ModelMesh::setMetalnessRoughnessAmbientOcclusionImage(QImage *image)
const QImage *ModelMesh::metalnessRoughnessAmbientOcclusionMapImage()
{
m_metalnessRoughnessAmbientOcclusionImage = image;
return m_metalnessRoughnessAmbientOcclusionMapImage;
}
QImage *ModelMesh::takeMetalnessRoughnessAmbientOcclusionMapImage()
{
auto image = m_metalnessRoughnessAmbientOcclusionMapImage;
m_metalnessRoughnessAmbientOcclusionMapImage = nullptr;
return image;
}
void ModelMesh::setMetalnessRoughnessAmbientOcclusionMapImage(QImage *image)
{
m_metalnessRoughnessAmbientOcclusionMapImage = image;
}
bool ModelMesh::hasMetalnessInImage()

View File

@ -25,19 +25,18 @@ public:
~ModelMesh();
ModelOpenGLVertex *triangleVertices();
int triangleVertexCount();
ModelOpenGLVertex *edgeVertices();
int edgeVertexCount();
ModelOpenGLVertex *toolVertices();
int toolVertexCount();
const std::vector<dust3d::Vector3> &vertices();
const std::vector<std::vector<size_t>> &faces();
const std::vector<dust3d::Vector3> &triangulatedVertices();
void setTextureImage(QImage *textureImage);
const QImage *textureImage();
QImage *takeTextureImage();
void setNormalMapImage(QImage *normalMapImage);
const QImage *normalMapImage();
const QImage *metalnessRoughnessAmbientOcclusionImage();
void setMetalnessRoughnessAmbientOcclusionImage(QImage *image);
QImage *takeNormalMapImage();
const QImage *metalnessRoughnessAmbientOcclusionMapImage();
QImage *takeMetalnessRoughnessAmbientOcclusionMapImage();
void setMetalnessRoughnessAmbientOcclusionMapImage(QImage *image);
bool hasMetalnessInImage();
void setHasMetalnessInImage(bool hasInImage);
bool hasRoughnessInImage();
@ -60,7 +59,7 @@ private:
std::vector<dust3d::Vector3> m_triangulatedVertices;
QImage *m_textureImage = nullptr;
QImage *m_normalMapImage = nullptr;
QImage *m_metalnessRoughnessAmbientOcclusionImage = nullptr;
QImage *m_metalnessRoughnessAmbientOcclusionMapImage = nullptr;
bool m_hasMetalnessInImage = false;
bool m_hasRoughnessInImage = false;
bool m_hasAmbientOcclusionInImage = false;

View File

@ -120,15 +120,18 @@ QImage ModelOffscreenRender::toImage(const QSize &size)
auto program = std::make_unique<ModelOpenGLProgram>();
program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile);
program->bind();
program->bindEnvironment();
program->bindMaps();
program->setUniformValue(program->getUniformLocationByName("eyePosition"), m_eyePosition);
program->setUniformValue(program->getUniformLocationByName("projectionMatrix"), projection);
program->setUniformValue(program->getUniformLocationByName("modelMatrix"), world);
program->setUniformValue(program->getUniformLocationByName("normalMatrix"), world.normalMatrix());
program->setUniformValue(program->getUniformLocationByName("viewMatrix"), camera);
object->draw();
program->releaseMaps();
program->release();
f->glFlush();

View File

@ -1,5 +1,6 @@
#include <QOpenGLFunctions>
#include <QFile>
#include <QMutexLocker>
#include <dust3d/base/debug.h>
#include "model_opengl_program.h"
#include "dds_file.h"
@ -29,6 +30,42 @@ bool ModelOpenGLProgram::isCoreProfile() const
return m_isCoreProfile;
}
void ModelOpenGLProgram::updateTextureImage(std::unique_ptr<QImage> image)
{
QMutexLocker lock(&m_imageMutex);
m_textureImage = std::move(image);
m_imageIsDirty = true;
}
void ModelOpenGLProgram::updateNormalMapImage(std::unique_ptr<QImage> image)
{
QMutexLocker lock(&m_imageMutex);
m_normalMapImage = std::move(image);
m_imageIsDirty = true;
}
void ModelOpenGLProgram::updateMetalnessRoughnessAmbientOcclusionMapImage(std::unique_ptr<QImage> image,
bool hasMetalnessMap,
bool hasRoughnessMap,
bool hasAmbientOcclusionMap)
{
QMutexLocker lock(&m_imageMutex);
m_metalnessRoughnessAmbientOcclusionMapImage = std::move(image);
m_hasMetalnessMap = hasMetalnessMap;
m_hasRoughnessMap = hasRoughnessMap;
m_hasAmbientOcclusionMap = hasAmbientOcclusionMap;
m_imageIsDirty = true;
}
void ModelOpenGLProgram::activeAndBindTexture(int location, QOpenGLTexture *texture)
{
if (0 == texture->textureId()) {
dust3dDebug << "Expected texture with a bound id";
return;
}
texture->bind(location);
}
void ModelOpenGLProgram::load(bool isCoreProfile)
{
if (m_isLoaded)
@ -54,8 +91,11 @@ void ModelOpenGLProgram::load(bool isCoreProfile)
m_isLoaded = true;
}
void ModelOpenGLProgram::bindEnvironment()
void ModelOpenGLProgram::bindMaps()
{
int bindLocation = 1;
// Bind environment maps
if (m_isCoreProfile) {
if (!m_environmentIrradianceMap) {
DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds");
@ -66,11 +106,13 @@ void ModelOpenGLProgram::bindEnvironment()
m_environmentSpecularMap.reset(irradianceFile.createOpenGLTexture());
}
m_environmentIrradianceMap->bind(0);
setUniformValue(getUniformLocationByName("environmentIrradianceMapId"), 0);
bindLocation++;
activeAndBindTexture(bindLocation, m_environmentIrradianceMap.get());
setUniformValue(getUniformLocationByName("environmentIrradianceMapId"), bindLocation);
m_environmentSpecularMap->bind(1);
setUniformValue(getUniformLocationByName("environmentSpecularMapId"), 1);
bindLocation++;
activeAndBindTexture(bindLocation, m_environmentSpecularMap.get());
setUniformValue(getUniformLocationByName("environmentSpecularMapId"), bindLocation);
} else {
if (!m_environmentIrradianceMaps) {
DdsFileReader irradianceFile(":/resources/cedar_bridge_irradiance.dds");
@ -81,19 +123,104 @@ void ModelOpenGLProgram::bindEnvironment()
m_environmentSpecularMaps = std::move(irradianceFile.createOpenGLTextures());
}
size_t bindPosition = 0;
auto oldBindLocationStart = bindLocation;
bindPosition = 0;
for (size_t i = 0; i < m_environmentIrradianceMaps->size(); ++i)
m_environmentIrradianceMaps->at(i)->bind(bindPosition++);
activeAndBindTexture(bindLocation++, m_environmentIrradianceMaps->at(i).get());
for (size_t i = 0; i < m_environmentSpecularMaps->size(); ++i)
m_environmentSpecularMaps->at(i)->bind(bindPosition++);
activeAndBindTexture(bindLocation++, m_environmentSpecularMaps->at(i).get());
bindLocation = oldBindLocationStart;
bindPosition = 0;
for (size_t i = 0; i < m_environmentIrradianceMaps->size(); ++i)
setUniformValue(getUniformLocationByName("environmentIrradianceMapId[" + std::to_string(i) + "]"), (int)(bindPosition++));
setUniformValue(getUniformLocationByName("environmentIrradianceMapId[" + std::to_string(i) + "]"), bindLocation++);
for (size_t i = 0; i < m_environmentSpecularMaps->size(); ++i)
setUniformValue(getUniformLocationByName("environmentSpecularMapId[" + std::to_string(i) + "]"), (int)(bindPosition++));
setUniformValue(getUniformLocationByName("environmentSpecularMapId[" + std::to_string(i) + "]"), bindLocation++);
}
// Bind texture, normal map, and other maps
if (m_imageIsDirty) {
QMutexLocker lock(&m_imageMutex);
if (m_imageIsDirty) {
m_imageIsDirty = false;
if (m_texture) {
m_texture->destroy();
m_texture.reset();
}
if (m_textureImage) {
m_texture = std::make_unique<QOpenGLTexture>(*m_textureImage);
}
if (m_normalMap) {
m_normalMap->destroy();
m_normalMap.reset();
}
if (m_normalMapImage) {
m_normalMap = std::make_unique<QOpenGLTexture>(*m_normalMapImage);
}
if (m_metalnessRoughnessAmbientOcclusionMap) {
m_metalnessRoughnessAmbientOcclusionMap->destroy();
m_metalnessRoughnessAmbientOcclusionMap.reset();
}
if (m_metalnessRoughnessAmbientOcclusionMapImage) {
m_metalnessRoughnessAmbientOcclusionMap = std::make_unique<QOpenGLTexture>(*m_metalnessRoughnessAmbientOcclusionMapImage);
}
m_metalnessMapEnabled = m_hasMetalnessMap;
m_roughnessMapEnabled = m_hasRoughnessMap;
m_ambientOcclusionMapEnabled = m_hasAmbientOcclusionMap;
}
}
bindLocation++;
if (m_texture) {
activeAndBindTexture(bindLocation, m_texture.get());
setUniformValue(getUniformLocationByName("textureId"), bindLocation);
setUniformValue(getUniformLocationByName("textureEnabled"), (int)1);
} else {
setUniformValue(getUniformLocationByName("textureId"), (int)0);
setUniformValue(getUniformLocationByName("textureEnabled"), (int)0);
}
bindLocation++;
if (m_normalMap) {
activeAndBindTexture(bindLocation, m_normalMap.get());
setUniformValue(getUniformLocationByName("normalMapId"), bindLocation);
setUniformValue(getUniformLocationByName("normalMapEnabled"), (int)1);
} else {
setUniformValue(getUniformLocationByName("normalMapId"), (int)0);
setUniformValue(getUniformLocationByName("normalMapEnabled"), (int)0);
}
bindLocation++;
if (m_metalnessRoughnessAmbientOcclusionMap) {
activeAndBindTexture(bindLocation, m_metalnessRoughnessAmbientOcclusionMap.get());
setUniformValue(getUniformLocationByName("metalnessRoughnessAoMapId"), bindLocation);
setUniformValue(getUniformLocationByName("metalnessMapEnabled"), (int)m_metalnessMapEnabled);
setUniformValue(getUniformLocationByName("roughnessMapEnabled"), (int)m_roughnessMapEnabled);
setUniformValue(getUniformLocationByName("aoMapEnabled"), (int)m_ambientOcclusionMapEnabled);
} else {
setUniformValue(getUniformLocationByName("metalnessRoughnessAoMapId"), (int)0);
setUniformValue(getUniformLocationByName("metalnessMapEnabled"), (int)0);
setUniformValue(getUniformLocationByName("roughnessMapEnabled"), (int)0);
setUniformValue(getUniformLocationByName("aoMapEnabled"), (int)0);
}
}
void ModelOpenGLProgram::releaseMaps()
{
if (m_texture)
m_texture->release();
if (m_normalMap)
m_normalMap->release();
if (m_metalnessRoughnessAmbientOcclusionMap)
m_metalnessRoughnessAmbientOcclusionMap->release();
if (m_environmentIrradianceMap)
m_environmentIrradianceMap->release();
if (m_environmentSpecularMap)
m_environmentSpecularMap->release();
if (m_environmentIrradianceMaps) {
for (size_t i = 0; i < m_environmentIrradianceMaps->size(); ++i)
m_environmentIrradianceMaps->at(i)->release();
}
if (m_environmentSpecularMaps) {
for (size_t i = 0; i < m_environmentSpecularMaps->size(); ++i)
m_environmentSpecularMaps->at(i)->release();
}
}

View File

@ -5,6 +5,7 @@
#include <QOpenGLShaderProgram>
#include <QOpenGLShader>
#include <QOpenGLTexture>
#include <QMutex>
class ModelOpenGLProgram: public QOpenGLShaderProgram
{
@ -12,10 +13,18 @@ public:
void load(bool isCoreProfile=false);
int getUniformLocationByName(const std::string &name);
bool isCoreProfile() const;
void bindEnvironment();
void bindMaps();
void releaseMaps();
void updateTextureImage(std::unique_ptr<QImage> image);
void updateNormalMapImage(std::unique_ptr<QImage> image);
void updateMetalnessRoughnessAmbientOcclusionMapImage(std::unique_ptr<QImage> image,
bool hasMetalnessMap = false,
bool hasRoughnessMap = false,
bool hasAmbientOcclusionMap = false);
private:
void addShaderFromResource(QOpenGLShader::ShaderType type, const char *resourceName);
void activeAndBindTexture(int location, QOpenGLTexture *texture);
bool m_isLoaded = false;
bool m_isCoreProfile = false;
@ -25,6 +34,20 @@ private:
std::unique_ptr<QOpenGLTexture> m_environmentSpecularMap;
std::unique_ptr<std::vector<std::unique_ptr<QOpenGLTexture>>> m_environmentIrradianceMaps;
std::unique_ptr<std::vector<std::unique_ptr<QOpenGLTexture>>> m_environmentSpecularMaps;
std::unique_ptr<QImage> m_textureImage;
std::unique_ptr<QImage> m_normalMapImage;
std::unique_ptr<QImage> m_metalnessRoughnessAmbientOcclusionMapImage;
std::unique_ptr<QOpenGLTexture> m_texture;
std::unique_ptr<QOpenGLTexture> m_normalMap;
std::unique_ptr<QOpenGLTexture> m_metalnessRoughnessAmbientOcclusionMap;
bool m_hasMetalnessMap = false;
bool m_hasRoughnessMap = false;
bool m_hasAmbientOcclusionMap = false;
QMutex m_imageMutex;
bool m_imageIsDirty = false;
bool m_metalnessMapEnabled = false;
bool m_roughnessMapEnabled = false;
bool m_ambientOcclusionMapEnabled = false;
};
#endif

View File

@ -174,16 +174,6 @@ bool ModelWidget::isWireframeVisible()
return m_isWireframeVisible;
}
void ModelWidget::enableEnvironmentLight()
{
m_isEnvironmentLightEnabled = true;
}
bool ModelWidget::isEnvironmentLightEnabled()
{
return m_isEnvironmentLightEnabled;
}
void ModelWidget::toggleRotation()
{
if (nullptr != m_rotationTimer) {
@ -371,9 +361,19 @@ void ModelWidget::setMousePickRadius(float radius)
void ModelWidget::updateMesh(ModelMesh *mesh)
{
if (!m_modelOpenGLProgram)
m_modelOpenGLProgram = std::make_unique<ModelOpenGLProgram>();
m_modelOpenGLProgram->updateTextureImage(std::unique_ptr<QImage>(nullptr != mesh ? mesh->takeTextureImage() : nullptr));
m_modelOpenGLProgram->updateNormalMapImage(std::unique_ptr<QImage>(nullptr != mesh ? mesh->takeNormalMapImage() : nullptr));
m_modelOpenGLProgram->updateMetalnessRoughnessAmbientOcclusionMapImage(std::unique_ptr<QImage>(nullptr != mesh ? mesh->takeMetalnessRoughnessAmbientOcclusionMapImage() : nullptr),
mesh && mesh->hasMetalnessInImage(),
mesh && mesh->hasRoughnessInImage(),
mesh && mesh->hasAmbientOcclusionInImage());
if (!m_modelOpenGLObject)
m_modelOpenGLObject = std::make_unique<ModelOpenGLObject>();
m_modelOpenGLObject->update(std::unique_ptr<ModelMesh>(mesh));
emit renderParametersChanged();
update();
}
@ -387,11 +387,6 @@ void ModelWidget::updateWireframeMesh(MonochromeMesh *mesh)
update();
}
void ModelWidget::updateColorTexture(QImage *colorTextureImage)
{
// TODO
}
int ModelWidget::widthInPixels()
{
return m_widthInPixels;
@ -513,17 +508,18 @@ void ModelWidget::paintGL()
}
drawModel();
if (m_isWireframeVisible)
if (m_isWireframeVisible) {
drawWireframe();
}
}
void ModelWidget::drawWireframe()
{
m_monochromeOpenGLProgram->bind();
m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("projectionMatrix"), m_projection);
m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("modelMatrix"), m_world);
m_monochromeOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("viewMatrix"), m_camera);
m_monochromeOpenGLProgram->setUniformValue(m_monochromeOpenGLProgram->getUniformLocationByName("projectionMatrix"), m_projection);
m_monochromeOpenGLProgram->setUniformValue(m_monochromeOpenGLProgram->getUniformLocationByName("modelMatrix"), m_world);
m_monochromeOpenGLProgram->setUniformValue(m_monochromeOpenGLProgram->getUniformLocationByName("viewMatrix"), m_camera);
if (m_wireframeOpenGLObject)
m_wireframeOpenGLObject->draw();
@ -538,12 +534,15 @@ void ModelWidget::drawModel()
m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("eyePosition"), m_eyePosition);
m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("projectionMatrix"), m_projection);
m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("modelMatrix"), m_world);
m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("normalMatrix"), m_world.normalMatrix());
m_modelOpenGLProgram->setUniformValue(m_modelOpenGLProgram->getUniformLocationByName("viewMatrix"), m_camera);
m_modelOpenGLProgram->bindEnvironment();
m_modelOpenGLProgram->bindMaps();
if (m_modelOpenGLObject)
m_modelOpenGLObject->draw();
m_modelOpenGLProgram->releaseMaps();
m_modelOpenGLProgram->release();
}

View File

@ -36,12 +36,9 @@ public:
~ModelWidget();
void updateMesh(ModelMesh *mesh);
void updateWireframeMesh(MonochromeMesh *mesh);
void updateColorTexture(QImage *colorTextureImage);
void toggleWireframe();
bool isWireframeVisible();
void toggleRotation();
void enableEnvironmentLight();
bool isEnvironmentLightEnabled();
void enableMove(bool enabled);
void enableZoom(bool enabled);
void enableMousePicking(bool enabled);
@ -113,7 +110,6 @@ private:
bool m_moveAndZoomByWindow = true;
bool m_enableCullFace = true;
bool m_notGraphics = false;
bool m_isEnvironmentLightEnabled = false;
bool m_isWireframeVisible = false;
std::pair<QVector3D, QVector3D> screenPositionToMouseRay(const QPoint &screenPosition);
void updateProjectionMatrix();

View File

@ -13,6 +13,45 @@ MonochromeMesh::MonochromeMesh(MonochromeMesh &&mesh)
MonochromeMesh::MonochromeMesh(const dust3d::Object &object)
{
/*
auto buildSection = [](const dust3d::Vector3 &origin,
const dust3d::Vector3 &faceNormal,
const dust3d::Vector3 &tagent,
double radius)
{
auto upDirection = dust3d::Vector3::crossProduct(tagent, faceNormal);
return std::vector<dust3d::Vector3> {
origin + tagent * radius,
origin - upDirection * radius,
origin - tagent * radius,
origin + upDirection * radius
};
};
auto calculateTagent = [](const dust3d::Vector3 &direction) {
const std::vector<dust3d::Vector3> axisList = {
dust3d::Vector3 {1, 0, 0},
dust3d::Vector3 {0, 1, 0},
dust3d::Vector3 {0, 0, 1},
};
float maxDot = -1;
size_t nearAxisIndex = 0;
bool reversed = false;
for (size_t i = 0; i < axisList.size(); ++i) {
const auto axis = axisList[i];
auto dot = dust3d::Vector3::dotProduct(axis, direction);
auto positiveDot = std::abs(dot);
if (positiveDot >= maxDot) {
reversed = dot < 0;
maxDot = positiveDot;
nearAxisIndex = i;
}
}
const auto& choosenAxis = axisList[(nearAxisIndex + 1) % 3];
auto startDirection = dust3d::Vector3::crossProduct(direction, choosenAxis).normalized();
return reversed ? -startDirection : startDirection;
};
*/
std::set<std::pair<size_t, size_t>> halfEdges;
for (const auto &face: object.triangleAndQuads) {
if (3 == face.size()) {
@ -33,6 +72,7 @@ MonochromeMesh::MonochromeMesh(const dust3d::Object &object)
halfEdges.insert({face[3], face[0]});
halfEdges.insert({face[0], face[3]});
}
//m_triangleVertices.reserve(halfEdges.size() * 24);
m_lineVertices.reserve(halfEdges.size() * 2);
for (const auto &halfEdge: halfEdges) {
// For two halfedges shared one edge, only output one line
@ -40,8 +80,60 @@ MonochromeMesh::MonochromeMesh(const dust3d::Object &object)
continue;
const auto &from = object.vertices[halfEdge.first];
const auto &to = object.vertices[halfEdge.second];
m_lineVertices.emplace_back(MonochromeOpenGLVertex {(GLfloat)from.x(), (GLfloat)from.y(), (GLfloat)from.z()});
m_lineVertices.emplace_back(MonochromeOpenGLVertex {(GLfloat)to.x(), (GLfloat)to.y(), (GLfloat)to.z()});
m_lineVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)from.x(),
(GLfloat)from.y(),
(GLfloat)from.z()
});
m_lineVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)to.x(),
(GLfloat)to.y(),
(GLfloat)to.z()
});
/*
auto direction = to - from;
auto sectionNormal = direction.normalized();
auto sectionTagent = calculateTagent(sectionNormal);
auto sectionTo = buildSection(to, sectionNormal, sectionTagent, 0.002);
auto sectionFrom = sectionTo;
for (auto &it: sectionFrom)
it = it - direction;
for (size_t i = 0; i < sectionTo.size(); ++i) {
size_t j = (i + 1) % sectionTo.size();
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionTo[i].x(),
(GLfloat)sectionTo[i].y(),
(GLfloat)sectionTo[i].z()
});
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionFrom[i].x(),
(GLfloat)sectionFrom[i].y(),
(GLfloat)sectionFrom[i].z()
});
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionTo[j].x(),
(GLfloat)sectionTo[j].y(),
(GLfloat)sectionTo[j].z()
});
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionFrom[i].x(),
(GLfloat)sectionFrom[i].y(),
(GLfloat)sectionFrom[i].z()
});
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionFrom[j].x(),
(GLfloat)sectionFrom[j].y(),
(GLfloat)sectionFrom[j].z()
});
m_triangleVertices.emplace_back(MonochromeOpenGLVertex {
(GLfloat)sectionTo[j].x(),
(GLfloat)sectionTo[j].y(),
(GLfloat)sectionTo[j].z()
});
}
*/
}
}

View File

@ -1,6 +1,7 @@
#ifndef DUST3D_APPLICATION_MONOCHROME_OPENGL_PROGRAM_H_
#define DUST3D_APPLICATION_MONOCHROME_OPENGL_PROGRAM_H_
#include <memory>
#include <QOpenGLShaderProgram>
#include <QOpenGLShader>

View File

@ -652,7 +652,7 @@ void TextureGenerator::generate()
if (nullptr != m_resultTextureNormalImage)
m_resultMesh->setNormalMapImage(new QImage(*m_resultTextureNormalImage));
if (hasMetalnessMap || hasRoughnessMap || hasAmbientOcclusionMap) {
m_resultMesh->setMetalnessRoughnessAmbientOcclusionImage(combineMetalnessRoughnessAmbientOcclusionImages(
m_resultMesh->setMetalnessRoughnessAmbientOcclusionMapImage(combineMetalnessRoughnessAmbientOcclusionImages(
m_resultTextureMetalnessImage,
m_resultTextureRoughnessImage,
m_resultTextureAmbientOcclusionImage));