/**************************************************************************** ** ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt3D module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "scenemodifier.h" #include #include #include #include #include #include #include #include SceneModifier::SceneModifier(Qt3DCore::QEntity *rootEntity) : m_rootEntity(rootEntity) { m_Camera = nullptr; // Text Qt3DExtras::QText2DEntity* pTextEntity = new Qt3DExtras::QText2DEntity(m_rootEntity); pTextEntity->setText("Mouse is over cuboid!"); pTextEntity->setFont(QFont("monospace", 1)); pTextEntity->setHeight(8); pTextEntity->setWidth(10); pTextEntity->setColor(Qt::blue); m_textTransform = new Qt3DCore::QTransform(); m_textTransform->setTranslation(QVector3D(-5.0f, -2.0f, -0.0f)); m_textTransform->setScale(0.5); pTextEntity->addComponent(m_textTransform); m_textEntity = pTextEntity; m_textEntity->setEnabled(false); Qt3DRender::QObjectPicker* pPicker = MakePicker(); pPicker->setHoverEnabled(true); pPicker->setDragEnabled(true); connect(pPicker, &Qt3DRender::QObjectPicker::clicked, this,&SceneModifier::On_PickerClicked ); connect(pPicker, &Qt3DRender::QObjectPicker::moved, this,&SceneModifier::On_PickerMoved ); connect(pPicker, &Qt3DRender::QObjectPicker::entered, [=] { On_PickerExited(); }); connect(pPicker, &Qt3DRender::QObjectPicker::exited, [=] { On_PickerExited(); }); m_Pickers.push_back(pPicker); MakeAllTriangles(); MakeAllPickers(); } void SceneModifier::MakeAllTriangles() { for (auto* pEntity : m_pTriangleEntities) { delete pEntity; } m_pTriangleEntities.clear(); m_pTriangleEntities.push_back(MakeTrianglesEntity(QVector3D(0.1, 2.1, 0.0), QVector3D(2.0, 2.0, 0.0), QVector3D(0.0, 4.0, 0.0))); m_pTriangleEntities.push_back(MakeTrianglesEntity(QVector3D(-0.1, -0.1, 0.0), QVector3D(-2.0, 0.0, 0.0), QVector3D(0.0, -2.0, 0.0))); m_pTriangleEntities.push_back(MakeTrianglesEntity(QVector3D(0.1, -0.1, 0.0), QVector3D(0.0, -2.0, 0.0), QVector3D(2.0, 0.0, 0.0))); } void SceneModifier::MakeAllPickers() { m_Pickers.clear(); Qt3DRender::QObjectPicker* pPicker = MakePicker(); m_pTriangleEntities[0]->addComponent(pPicker); m_Pickers.push_back(pPicker); pPicker = MakePicker(); m_pTriangleEntities[1]->addComponent(pPicker); m_Pickers.push_back(pPicker); pPicker = MakePicker(); m_pTriangleEntities[2]->addComponent(pPicker); m_Pickers.push_back(pPicker); int Count = 1; for (auto* pLocalPicker : m_Pickers) { connect(pLocalPicker, &Qt3DRender::QObjectPicker::pressed,this , &SceneModifier::On_PickerPressed); connect(pLocalPicker, &Qt3DRender::QObjectPicker::released, this, &SceneModifier::On_PickerReleased); connect(pLocalPicker, &Qt3DRender::QObjectPicker::entered, [=] { On_PickerEntered(QString("Triangle%1").arg(Count),pLocalPicker); }); connect(pLocalPicker, &Qt3DRender::QObjectPicker::exited, [=] { On_PickerExited(QString("Triangle%1").arg(Count),pLocalPicker); }); Count++; } for (auto* pTriangleEntity : m_pTriangleEntities) { pTriangleEntity->setEnabled(true); } emit TriangleSelected("Pickers Reset"); } Qt3DRender::QObjectPicker* SceneModifier::MakePicker() { Qt3DRender::QObjectPicker* pPicker = new Qt3DRender::QObjectPicker(); pPicker->setHoverEnabled(true); pPicker->setDragEnabled(true); Qt3DRender::QPickingSettings* pSettings = new Qt3DRender::QPickingSettings(pPicker); pSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontFace); pSettings->setPickMethod( Qt3DRender::QPickingSettings::TrianglePicking // Qt3DRender::QPickingSettings::BoundingVolumePicking ); pSettings->setPickResultMode( Qt3DRender::QPickingSettings::NearestPick // Qt3DRender::QPickingSettings::AllPicks ); return pPicker; } SceneModifier::~SceneModifier() { } void SceneModifier::SetCamera(Qt3DRender::QCamera* pCamera) { m_Camera = pCamera; } void SceneModifier::viewMatrixChanged() { if (m_Camera != nullptr) { m_textTransform->setRotation(m_Camera->transform()->rotation()); } } void SceneModifier::On_PickerClicked(Qt3DRender::QPickEvent *event) { qDebug() << __func__ ; Qt3DRender::QPickTriangleEvent *eventTri = static_cast(event); qDebug() << __func__ << "Pick Triangle Index: " << eventTri->triangleIndex(); qDebug() << __func__ << "Pick Triangle Vertex 1: " << eventTri->vertex1Index(); qDebug() << __func__ << "Pick Triangle Vertex 2: " << eventTri->vertex2Index(); qDebug() << __func__ << "Pick Triangle Vertex 3: " << eventTri->vertex3Index(); } void SceneModifier::On_PickerReleased(Qt3DRender::QPickEvent *event) { qDebug() << __func__ ; Qt3DRender::QPickTriangleEvent *eventTri = static_cast(event); qDebug() << __func__ << "Pick Triangle Index: " << eventTri->triangleIndex(); qDebug() << __func__ << "Pick Triangle Vertex 1: " << eventTri->vertex1Index(); qDebug() << __func__ << "Pick Triangle Vertex 2: " << eventTri->vertex2Index(); qDebug() << __func__ << "Pick Triangle Vertex 3: " << eventTri->vertex3Index(); } void SceneModifier::On_PickerPressed(Qt3DRender::QPickEvent *event) { Qt3DRender::QPickTriangleEvent *eventTri = static_cast(event); qDebug() << __func__ << "Pick Triangle Index: " << eventTri->triangleIndex(); qDebug() << __func__ << "Pick Triangle Vertex 1: " << eventTri->vertex1Index(); qDebug() << __func__ << "Pick Triangle Vertex 2: " << eventTri->vertex2Index(); qDebug() << __func__ << "Pick Triangle Vertex 3: " << eventTri->vertex3Index(); for (auto Picker : m_Pickers) { m_textEntity->setEnabled(false); } } void SceneModifier::On_PickerMoved() { // dragEnabled qDebug() << __func__; } void SceneModifier::On_PickerEntered(QString Text,Qt3DRender::QObjectPicker* Picker) { qDebug() << this << Picker << __func__ << Text; // On_PickerEntered(Text); } void SceneModifier::On_PickerEntered(QString Text) { qDebug() << __func__ << this << Text; Qt3DExtras::QText2DEntity* pTextEntity = dynamic_cast(m_textEntity); if (pTextEntity != nullptr) { pTextEntity->setText(Text); } m_textEntity->setEnabled(true); } void SceneModifier::On_PickerExited(QString Text,Qt3DRender::QObjectPicker* Picker) { qDebug() << this << Picker << __func__ << Text; if (Text == "Triangle1") { qDebug(); qDebug(); } // On_PickerEntered(Text); } void SceneModifier::On_PickerExited() { // qDebug() << __func__ << this; m_textEntity->setEnabled(false); emit TriangleSelected(""); } void SceneModifier::reset_button_clicked() { MakeAllTriangles(); MakeAllPickers(); } void SceneModifier::enableSelection(bool Enable) { for (auto* pSelector : m_Pickers) { pSelector->setEnabled(Enable); } } Qt3DCore::QEntity* SceneModifier::MakeTrianglesEntity(const QVector3D& Point0_3D, const QVector3D& Point1_3D, const QVector3D& Point2_3D) { Qt3DCore::QEntity* pTriangleEntity = new Qt3DCore::QEntity(m_rootEntity); Qt3DExtras::QPhongMaterial *torusMaterial = new Qt3DExtras::QPhongMaterial(); torusMaterial->setDiffuse(QColor(QRgb(0xbeb32b))); //auto pTrianglesMaterial = new Qt3DExtras::QPerVertexColorMaterial(); auto pTrianglesTransform = new Qt3DCore::QTransform(); Qt3DRender::QGeometryRenderer *trianglemesh = PrepareTriangleMesh(pTriangleEntity, Point0_3D, Point1_3D, Point2_3D); pTriangleEntity->addComponent(PrepareTriangleMesh(pTriangleEntity, Point0_3D, Point1_3D, Point2_3D)); //pTriangleEntity->addComponent(pTrianglesMaterial); pTriangleEntity->addComponent(torusMaterial); // pTriangleEntity->addComponent(planeMaterial); pTriangleEntity->addComponent(pTrianglesTransform); return pTriangleEntity; } Qt3DRender::QGeometryRenderer* SceneModifier::PrepareTriangleMesh(Qt3DCore::QEntity* pParentEntity, const QVector3D& Point0_3D, const QVector3D& Point1_3D, const QVector3D& Point2_3D) const { auto pTriangleMesh = new Qt3DRender::QGeometryRenderer(pParentEntity); auto pTriangleGeometry = new Qt3DRender::QGeometry(pTriangleMesh); auto pTriangleDataBuffer = new Qt3DRender::QBuffer(pTriangleGeometry); auto pTriangleNormalBuffer = new Qt3DRender::QBuffer(pTriangleGeometry); auto pTriangleColorBuffer = new Qt3DRender::QBuffer(pTriangleGeometry); QByteArray VertexBufferData; QByteArray NormalBufferData; QByteArray ColorBufferData; QVector Vertices; QVector Normals; QVector Colors; QVector4D Point0(Point0_3D, 0.0f); QVector4D Point1(Point1_3D, 0.0f); QVector4D Point2(Point2_3D, 0.0f); //So for a triangle p1, p2, p3, if the vector U = p2 - p1 and the vector V = p3 - p1 then the normal N = U X V and can be calculated by : // Nx = UyVz - UzVy // Ny = UzVx - UxVz // Nz = UxVy - UyVx float Ux = Point1_3D.x() - Point0_3D.x(); float Uy = Point1_3D.y() - Point0_3D.y(); float Uz = Point1_3D.z() - Point0_3D.z(); float Vx = Point2_3D.x() - Point1_3D.x(); float Vy = Point2_3D.y() - Point1_3D.y(); float Vz = Point2_3D.z() - Point1_3D.z(); float Nx = Uy * Vz - Uz * Vy; float Ny = Uz * Vx - Ux * Vz; float Nz = Ux * Vy - Uy * Vx; QVector4D TriangleNormal4D(Nx, Ny, Nz, 0.0f); QVector4D VertexColor(0.5f, 0.5f, 0.5f, 1.0); Vertices.push_back(Point0); Normals.push_back(TriangleNormal4D); Colors.push_back(VertexColor); Vertices.push_back(Point1); Normals.push_back(TriangleNormal4D); Colors.push_back(VertexColor); Vertices.push_back(Point2); Normals.push_back(TriangleNormal4D); Colors.push_back(VertexColor); VertexBufferData.resize(Vertices.size() * 4 * sizeof(float)); float *pRawVertexArray = reinterpret_cast(VertexBufferData.data()); int Idx = 0; Q_FOREACH(const QVector4D &v, Vertices) { pRawVertexArray[Idx++] = v.x(); pRawVertexArray[Idx++] = v.y(); pRawVertexArray[Idx++] = v.z(); pRawVertexArray[Idx++] = v.w(); } pTriangleDataBuffer->setData(VertexBufferData); float *data = reinterpret_cast(((QByteArray)(pTriangleDataBuffer->data())).data()); for (int i = 0; i < 12; i++) { qDebug() << data[i] << " "; if (!((i+1) % 4)) { qDebug() << "\n"; } } NormalBufferData.resize(Normals.size() * 4 * sizeof(float)); float *pRawNormalArray = reinterpret_cast(NormalBufferData.data()); int IdNormal = 0; Q_FOREACH(const QVector4D &v, Normals) { pRawNormalArray[IdNormal++] = v.x(); pRawNormalArray[IdNormal++] = v.y(); pRawNormalArray[IdNormal++] = v.z(); pRawNormalArray[IdNormal++] = v.w(); } pTriangleNormalBuffer->setData(NormalBufferData); ColorBufferData.resize(Colors.size() * 4 * sizeof(float)); float *pRawColorArray = reinterpret_cast(ColorBufferData.data()); int IdColor = 0; Q_FOREACH(const QVector4D &v, Colors) { pRawColorArray[IdColor++] = v.x(); pRawColorArray[IdColor++] = v.y(); pRawColorArray[IdColor++] = v.z(); pRawColorArray[IdColor++] = v.w(); } pTriangleColorBuffer->setData(ColorBufferData); //Triangle attribute //auto pTriangleAttribute = new Qt3DRender::QAttribute(pParentEntity); Qt3DRender::QAttribute *pTriangleAttribute = new Qt3DRender::QAttribute(pParentEntity); pTriangleAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); pTriangleAttribute->setBuffer(pTriangleDataBuffer); pTriangleAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); pTriangleAttribute->setVertexSize(3);//3 means 3 float numbers, that is, x,y,z pTriangleAttribute->setByteOffset(0); pTriangleAttribute->setByteStride(4 * sizeof(float)); pTriangleAttribute->setCount(Vertices.size()); pTriangleAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); pTriangleGeometry->addAttribute(pTriangleAttribute); //Normal attribute Qt3DRender::QAttribute* pNormalAttribute = new Qt3DRender::QAttribute(); pNormalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); pNormalAttribute->setBuffer(pTriangleNormalBuffer); pNormalAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); pNormalAttribute->setVertexSize(3); pNormalAttribute->setByteOffset(0); pNormalAttribute->setByteStride(4 * sizeof(float)); pNormalAttribute->setCount(Normals.size()); pNormalAttribute->setName(Qt3DRender::QAttribute::defaultNormalAttributeName()); pTriangleGeometry->addAttribute(pNormalAttribute); //Color attribute auto pColorAttribute = new Qt3DRender::QAttribute(pParentEntity); pColorAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); pColorAttribute->setBuffer(pTriangleColorBuffer); pColorAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float); pColorAttribute->setVertexSize(4);//4 means 4 float numbers, that is, R,G,B,A pColorAttribute->setByteOffset(0); pColorAttribute->setByteStride(4 * sizeof(float)); pColorAttribute->setCount(Colors.size()); pColorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName()); pTriangleGeometry->addAttribute(pColorAttribute); pTriangleMesh->setInstanceCount(1); pTriangleMesh->setIndexOffset(0); pTriangleMesh->setFirstInstance(0); pTriangleMesh->setVertexCount(Vertices.size()); pTriangleMesh->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); pTriangleMesh->setGeometry(pTriangleGeometry); return pTriangleMesh; }