diff --git a/resources.qrc b/resources.qrc index 698a12f..e17b1e0 100644 --- a/resources.qrc +++ b/resources.qrc @@ -14,5 +14,7 @@ src/shaders/simple.frag src/shaders/texture.vert src/shaders/texture.frag + src/shaders/lit.vert + src/shaders/lit.frag diff --git a/src/ViewportWidget.cpp b/src/ViewportWidget.cpp index ed16748..057e1ff 100644 --- a/src/ViewportWidget.cpp +++ b/src/ViewportWidget.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include struct PntComparator { bool operator()(const gp_Pnt& a, const gp_Pnt& b) const { @@ -79,6 +81,7 @@ ViewportWidget::~ViewportWidget() { makeCurrent(); delete m_shaderProgram; + delete m_litShaderProgram; delete m_viewCube; delete m_sketchGrid; m_vbo.destroy(); @@ -601,6 +604,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch) if (!lineVertices.isEmpty()) { m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat)); + m_shaderProgram->enableAttributeArray(0); + m_shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0); + m_shaderProgram->disableAttributeArray(1); glDrawArrays(GL_LINES, 0, lineVertices.size() / 3); } @@ -658,9 +664,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch) // Draw faces if (!sketch->shape().IsNull()) { - BRepMesh_IncrementalMesh(sketch->shape(), 0.1); // Linear deflection + BRepMesh_IncrementalMesh(sketch->shape(), 0.1, Standard_False, 0.5, Standard_True); // Linear deflection, compute normals - QVector faceVertices; + QVector faceData; TopExp_Explorer explorer(sketch->shape(), TopAbs_FACE); for (; explorer.More(); explorer.Next()) { TopoDS_Face face = TopoDS::Face(explorer.Current()); @@ -668,26 +674,62 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch) Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location); if (!triangulation.IsNull()) { - for (int i = 1; i <= triangulation->NbTriangles(); ++i) { - const Poly_Triangle& triangle = triangulation->Triangle(i); - gp_Pnt p1 = triangulation->Node(triangle.Value(1)).Transformed(location); - gp_Pnt p2 = triangulation->Node(triangle.Value(2)).Transformed(location); - gp_Pnt p3 = triangulation->Node(triangle.Value(3)).Transformed(location); - faceVertices << p1.X() << p1.Y() << p1.Z(); - faceVertices << p2.X() << p2.Y() << p2.Z(); - faceVertices << p3.X() << p3.Y() << p3.Z(); + gp_Trsf locTrsf = location.Transformation(); + + if (triangulation->HasNormals()) { + for (int i = 1; i <= triangulation->NbTriangles(); ++i) { + const Poly_Triangle& triangle = triangulation->Triangle(i); + for (int j = 1; j <= 3; ++j) { + int nodeIdx = triangle.Value(j); + gp_Pnt p = triangulation->Node(nodeIdx).Transformed(location); + gp_Dir n = triangulation->Normal(nodeIdx); + n.Transform(locTrsf); + + if (face.Orientation() == TopAbs_REVERSED) { + n.Reverse(); + } + faceData << p.X() << p.Y() << p.Z(); + faceData << n.X() << n.Y() << n.Z(); + } + } + } else { + for (int i = 1; i <= triangulation->NbTriangles(); ++i) { + const Poly_Triangle& triangle = triangulation->Triangle(i); + gp_Pnt p1 = triangulation->Node(triangle.Value(1)).Transformed(location); + gp_Pnt p2 = triangulation->Node(triangle.Value(2)).Transformed(location); + gp_Pnt p3 = triangulation->Node(triangle.Value(3)).Transformed(location); + + QVector3D v1(p1.X(), p1.Y(), p1.Z()); + QVector3D v2(p2.X(), p2.Y(), p2.Z()); + QVector3D v3(p3.X(), p3.Y(), p3.Z()); + QVector3D faceNormal = QVector3D::crossProduct(v2 - v1, v3 - v1).normalized(); + if (face.Orientation() == TopAbs_REVERSED) { + faceNormal = -faceNormal; + } + faceData << p1.X() << p1.Y() << p1.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z(); + faceData << p2.X() << p2.Y() << p2.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z(); + faceData << p3.X() << p3.Y() << p3.Z() << faceNormal.x() << faceNormal.y() << faceNormal.z(); + } } } } - if (!faceVertices.isEmpty()) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(0.5f, 0.5f, 1.0f, 0.5f)); + if (!faceData.isEmpty()) { + m_litShaderProgram->bind(); + m_litShaderProgram->setUniformValue(m_litProjMatrixLoc, projection); + m_litShaderProgram->setUniformValue(m_litMvMatrixLoc, m_camera->modelViewMatrix()); + m_litShaderProgram->setUniformValue(m_litNormalMatrixLoc, m_camera->modelViewMatrix().normalMatrix()); + m_vbo.bind(); - m_vbo.allocate(faceVertices.constData(), faceVertices.size() * sizeof(GLfloat)); - glDrawArrays(GL_TRIANGLES, 0, faceVertices.size() / 3); - glDisable(GL_BLEND); + m_vbo.allocate(faceData.constData(), faceData.size() * sizeof(GLfloat)); + + m_litShaderProgram->enableAttributeArray(0); + m_litShaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat)); + m_litShaderProgram->enableAttributeArray(1); + m_litShaderProgram->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat)); + + glDrawArrays(GL_TRIANGLES, 0, faceData.size() / 6); + m_shaderProgram->bind(); // rebind simple shader for subsequent draws } } @@ -696,8 +738,8 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch) void ViewportWidget::initShaders() { + // Simple shader for lines and grids m_shaderProgram = new QOpenGLShaderProgram(this); - if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert")) { qCritical() << "Vertex shader compilation failed:" << m_shaderProgram->log(); return; @@ -710,10 +752,27 @@ void ViewportWidget::initShaders() qCritical() << "Shader program linking failed:" << m_shaderProgram->log(); return; } - m_projMatrixLoc = m_shaderProgram->uniformLocation("projectionMatrix"); m_mvMatrixLoc = m_shaderProgram->uniformLocation("modelViewMatrix"); m_colorLoc = m_shaderProgram->uniformLocation("objectColor"); + + // Lit shader for faces + m_litShaderProgram = new QOpenGLShaderProgram(this); + if (!m_litShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/lit.vert")) { + qCritical() << "Lit vertex shader compilation failed:" << m_litShaderProgram->log(); + return; + } + if (!m_litShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/lit.frag")) { + qCritical() << "Lit fragment shader compilation failed:" << m_litShaderProgram->log(); + return; + } + if (!m_litShaderProgram->link()) { + qCritical() << "Lit shader program linking failed:" << m_litShaderProgram->log(); + return; + } + m_litProjMatrixLoc = m_litShaderProgram->uniformLocation("projectionMatrix"); + m_litMvMatrixLoc = m_litShaderProgram->uniformLocation("modelViewMatrix"); + m_litNormalMatrixLoc = m_litShaderProgram->uniformLocation("normalMatrix"); } void ViewportWidget::drawSelectionPlanes() diff --git a/src/ViewportWidget.h b/src/ViewportWidget.h index 2b2420d..34790c7 100644 --- a/src/ViewportWidget.h +++ b/src/ViewportWidget.h @@ -97,6 +97,7 @@ private: QMatrix4x4 projection; QOpenGLShaderProgram* m_shaderProgram = nullptr; + QOpenGLShaderProgram* m_litShaderProgram = nullptr; QOpenGLVertexArrayObject m_vao; QOpenGLBuffer m_vbo; @@ -104,6 +105,11 @@ private: int m_projMatrixLoc = -1; int m_mvMatrixLoc = -1; int m_colorLoc = -1; + + // Lit shader uniform locations + int m_litProjMatrixLoc = -1; + int m_litMvMatrixLoc = -1; + int m_litNormalMatrixLoc = -1; Camera* m_camera = nullptr; ViewCube* m_viewCube; SketchGrid* m_sketchGrid = nullptr; diff --git a/src/shaders/lit.frag b/src/shaders/lit.frag new file mode 100644 index 0000000..bd92772 --- /dev/null +++ b/src/shaders/lit.frag @@ -0,0 +1,33 @@ +#version 330 core +out vec4 FragColor; + +in vec3 FragPos; +in vec3 Normal; + +void main() +{ + vec3 viewPos = vec3(0.0, 0.0, 0.0); // View position is origin in view space + vec3 lightPos = vec3(0.0, 10.0, 5.0); // Light position in view space + vec3 lightColor = vec3(1.0, 1.0, 1.0); + vec3 objectColor = vec3(0.5, 0.5, 1.0); + + // Ambient + float ambientStrength = 0.3; + vec3 ambient = ambientStrength * lightColor; + + // Diffuse + vec3 norm = normalize(Normal); + vec3 lightDir = normalize(lightPos - FragPos); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = diff * lightColor; + + // Specular + float specularStrength = 0.5; + vec3 viewDir = normalize(viewPos - FragPos); + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = specularStrength * spec * lightColor; + + vec3 result = (ambient + diffuse + specular) * objectColor; + FragColor = vec4(result, 1.0); +} diff --git a/src/shaders/lit.vert b/src/shaders/lit.vert new file mode 100644 index 0000000..f0dd74e --- /dev/null +++ b/src/shaders/lit.vert @@ -0,0 +1,17 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; + +out vec3 FragPos; +out vec3 Normal; + +uniform mat4 modelViewMatrix; +uniform mat4 projectionMatrix; +uniform mat3 normalMatrix; + +void main() +{ + FragPos = vec3(modelViewMatrix * vec4(aPos, 1.0)); + Normal = normalMatrix * aNormal; + gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0); +}