feat: Add Blinn-Phong shading for faces
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
@@ -14,5 +14,7 @@
|
|||||||
<file alias="simple.frag">src/shaders/simple.frag</file>
|
<file alias="simple.frag">src/shaders/simple.frag</file>
|
||||||
<file alias="texture.vert">src/shaders/texture.vert</file>
|
<file alias="texture.vert">src/shaders/texture.vert</file>
|
||||||
<file alias="texture.frag">src/shaders/texture.frag</file>
|
<file alias="texture.frag">src/shaders/texture.frag</file>
|
||||||
|
<file alias="lit.vert">src/shaders/lit.vert</file>
|
||||||
|
<file alias="lit.frag">src/shaders/lit.frag</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <TopoDS_Face.hxx>
|
#include <TopoDS_Face.hxx>
|
||||||
#include <Poly_Triangulation.hxx>
|
#include <Poly_Triangulation.hxx>
|
||||||
#include <BRep_Tool.hxx>
|
#include <BRep_Tool.hxx>
|
||||||
|
#include <gp_Dir.hxx>
|
||||||
|
#include <gp_Trsf.hxx>
|
||||||
|
|
||||||
struct PntComparator {
|
struct PntComparator {
|
||||||
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
|
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
|
||||||
@@ -79,6 +81,7 @@ ViewportWidget::~ViewportWidget()
|
|||||||
{
|
{
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
delete m_shaderProgram;
|
delete m_shaderProgram;
|
||||||
|
delete m_litShaderProgram;
|
||||||
delete m_viewCube;
|
delete m_viewCube;
|
||||||
delete m_sketchGrid;
|
delete m_sketchGrid;
|
||||||
m_vbo.destroy();
|
m_vbo.destroy();
|
||||||
@@ -601,6 +604,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
|
|||||||
|
|
||||||
if (!lineVertices.isEmpty()) {
|
if (!lineVertices.isEmpty()) {
|
||||||
m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat));
|
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);
|
glDrawArrays(GL_LINES, 0, lineVertices.size() / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,9 +664,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
|
|||||||
|
|
||||||
// Draw faces
|
// Draw faces
|
||||||
if (!sketch->shape().IsNull()) {
|
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<GLfloat> faceVertices;
|
QVector<GLfloat> faceData;
|
||||||
TopExp_Explorer explorer(sketch->shape(), TopAbs_FACE);
|
TopExp_Explorer explorer(sketch->shape(), TopAbs_FACE);
|
||||||
for (; explorer.More(); explorer.Next()) {
|
for (; explorer.More(); explorer.Next()) {
|
||||||
TopoDS_Face face = TopoDS::Face(explorer.Current());
|
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);
|
Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(face, location);
|
||||||
|
|
||||||
if (!triangulation.IsNull()) {
|
if (!triangulation.IsNull()) {
|
||||||
|
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) {
|
for (int i = 1; i <= triangulation->NbTriangles(); ++i) {
|
||||||
const Poly_Triangle& triangle = triangulation->Triangle(i);
|
const Poly_Triangle& triangle = triangulation->Triangle(i);
|
||||||
gp_Pnt p1 = triangulation->Node(triangle.Value(1)).Transformed(location);
|
gp_Pnt p1 = triangulation->Node(triangle.Value(1)).Transformed(location);
|
||||||
gp_Pnt p2 = triangulation->Node(triangle.Value(2)).Transformed(location);
|
gp_Pnt p2 = triangulation->Node(triangle.Value(2)).Transformed(location);
|
||||||
gp_Pnt p3 = triangulation->Node(triangle.Value(3)).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();
|
QVector3D v1(p1.X(), p1.Y(), p1.Z());
|
||||||
faceVertices << p3.X() << p3.Y() << p3.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()) {
|
if (!faceData.isEmpty()) {
|
||||||
glEnable(GL_BLEND);
|
m_litShaderProgram->bind();
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
m_litShaderProgram->setUniformValue(m_litProjMatrixLoc, projection);
|
||||||
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(0.5f, 0.5f, 1.0f, 0.5f));
|
m_litShaderProgram->setUniformValue(m_litMvMatrixLoc, m_camera->modelViewMatrix());
|
||||||
|
m_litShaderProgram->setUniformValue(m_litNormalMatrixLoc, m_camera->modelViewMatrix().normalMatrix());
|
||||||
|
|
||||||
m_vbo.bind();
|
m_vbo.bind();
|
||||||
m_vbo.allocate(faceVertices.constData(), faceVertices.size() * sizeof(GLfloat));
|
m_vbo.allocate(faceData.constData(), faceData.size() * sizeof(GLfloat));
|
||||||
glDrawArrays(GL_TRIANGLES, 0, faceVertices.size() / 3);
|
|
||||||
glDisable(GL_BLEND);
|
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()
|
void ViewportWidget::initShaders()
|
||||||
{
|
{
|
||||||
|
// Simple shader for lines and grids
|
||||||
m_shaderProgram = new QOpenGLShaderProgram(this);
|
m_shaderProgram = new QOpenGLShaderProgram(this);
|
||||||
|
|
||||||
if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert")) {
|
if (!m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert")) {
|
||||||
qCritical() << "Vertex shader compilation failed:" << m_shaderProgram->log();
|
qCritical() << "Vertex shader compilation failed:" << m_shaderProgram->log();
|
||||||
return;
|
return;
|
||||||
@@ -710,10 +752,27 @@ void ViewportWidget::initShaders()
|
|||||||
qCritical() << "Shader program linking failed:" << m_shaderProgram->log();
|
qCritical() << "Shader program linking failed:" << m_shaderProgram->log();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_projMatrixLoc = m_shaderProgram->uniformLocation("projectionMatrix");
|
m_projMatrixLoc = m_shaderProgram->uniformLocation("projectionMatrix");
|
||||||
m_mvMatrixLoc = m_shaderProgram->uniformLocation("modelViewMatrix");
|
m_mvMatrixLoc = m_shaderProgram->uniformLocation("modelViewMatrix");
|
||||||
m_colorLoc = m_shaderProgram->uniformLocation("objectColor");
|
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()
|
void ViewportWidget::drawSelectionPlanes()
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ private:
|
|||||||
|
|
||||||
QMatrix4x4 projection;
|
QMatrix4x4 projection;
|
||||||
QOpenGLShaderProgram* m_shaderProgram = nullptr;
|
QOpenGLShaderProgram* m_shaderProgram = nullptr;
|
||||||
|
QOpenGLShaderProgram* m_litShaderProgram = nullptr;
|
||||||
QOpenGLVertexArrayObject m_vao;
|
QOpenGLVertexArrayObject m_vao;
|
||||||
QOpenGLBuffer m_vbo;
|
QOpenGLBuffer m_vbo;
|
||||||
|
|
||||||
@@ -104,6 +105,11 @@ private:
|
|||||||
int m_projMatrixLoc = -1;
|
int m_projMatrixLoc = -1;
|
||||||
int m_mvMatrixLoc = -1;
|
int m_mvMatrixLoc = -1;
|
||||||
int m_colorLoc = -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;
|
Camera* m_camera = nullptr;
|
||||||
ViewCube* m_viewCube;
|
ViewCube* m_viewCube;
|
||||||
SketchGrid* m_sketchGrid = nullptr;
|
SketchGrid* m_sketchGrid = nullptr;
|
||||||
|
|||||||
33
src/shaders/lit.frag
Normal file
33
src/shaders/lit.frag
Normal file
@@ -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);
|
||||||
|
}
|
||||||
17
src/shaders/lit.vert
Normal file
17
src/shaders/lit.vert
Normal file
@@ -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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user