Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qconvexmeshshape.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qcacheutils_p.h"
6
7#include <QFile>
8#include <QFileInfo>
9#include <QtQuick3D/QQuick3DGeometry>
10#include <extensions/PxExtensionsAPI.h>
11
12#include "foundation/PxVec3.h"
13#include "cooking/PxConvexMeshDesc.h"
14#include "extensions/PxDefaultStreams.h"
15
16#include <QtQml/qqml.h>
17#include <QtQml/QQmlFile>
18#include <QtQml/qqmlcontext.h>
19
20#include <QtQuick3DUtils/private/qssgmesh_p.h>
21#include "qphysicsworld_p.h"
23#include "qphysicsutils_p.h"
24
26
27physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMesh()
28{
29 if (m_convexMesh != nullptr)
30 return m_convexMesh;
31
32 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
33 if (thePhysics == nullptr)
34 return nullptr;
35
36 m_convexMesh = QCacheUtils::readCachedConvexMesh(m_meshPath, *thePhysics);
37 if (m_convexMesh != nullptr)
38 return m_convexMesh;
39
40 m_convexMesh = QCacheUtils::readCookedConvexMesh(m_meshPath, *thePhysics);
41 if (m_convexMesh != nullptr)
42 return m_convexMesh;
43
44 loadSsgMesh();
45
46 if (!m_ssgMesh.isValid())
47 return nullptr;
48
49 physx::PxDefaultMemoryOutputStream buf;
50 physx::PxConvexMeshCookingResult::Enum result;
51 int vStride = m_ssgMesh.vertexBuffer().stride;
52 int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride;
53 const auto *vd = m_ssgMesh.vertexBuffer().data.constData();
54
55 qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts";
56
58
59 for (int i = 0; i < vCount; ++i) {
60 auto *vp = reinterpret_cast<const QVector3D *>(vd + vStride * i + m_posOffset);
61 verts << physx::PxVec3 { vp->x(), vp->y(), vp->z() };
62 }
63
64 const auto *convexVerts = verts.constData();
65
66 physx::PxConvexMeshDesc convexDesc;
67 convexDesc.points.count = vCount;
68 convexDesc.points.stride = sizeof(physx::PxVec3);
69 convexDesc.points.data = convexVerts;
70 convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
71
72 const auto cooking = QPhysicsWorld::getCooking();
73 if (cooking && cooking->cookConvexMesh(convexDesc, buf, &result)) {
74 auto size = buf.getSize();
75 auto *data = buf.getData();
76 physx::PxDefaultMemoryInputData input(data, size);
77 m_convexMesh = thePhysics->createConvexMesh(input);
78 qCDebug(lcQuick3dPhysics) << "Created convex mesh" << m_convexMesh << "for mesh" << this;
80 } else {
81 qCWarning(lcQuick3dPhysics) << "Could not create convex mesh from" << m_meshPath;
82 }
83
84 return m_convexMesh;
85}
86
87physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMesh()
88{
89
90 if (m_triangleMesh != nullptr)
91 return m_triangleMesh;
92
93 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
94 if (thePhysics == nullptr)
95 return nullptr;
96
97 m_triangleMesh = QCacheUtils::readCachedTriangleMesh(m_meshPath, *thePhysics);
98 if (m_triangleMesh != nullptr)
99 return m_triangleMesh;
100
101 m_triangleMesh = QCacheUtils::readCookedTriangleMesh(m_meshPath, *thePhysics);
102 if (m_triangleMesh != nullptr)
103 return m_triangleMesh;
104
105 loadSsgMesh();
106 if (!m_ssgMesh.isValid())
107 return nullptr;
108
109 physx::PxDefaultMemoryOutputStream buf;
110 physx::PxTriangleMeshCookingResult::Enum result;
111 const int vStride = m_ssgMesh.vertexBuffer().stride;
112 const int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride;
113 const auto *vd = m_ssgMesh.vertexBuffer().data.constData();
114
115 const int iStride =
116 m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16
117 ? 2
118 : 4;
119 const int iCount = m_ssgMesh.indexBuffer().data.size() / iStride;
120
121 qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts" << iCount << "idxs";
122
123 physx::PxTriangleMeshDesc triangleDesc;
124 triangleDesc.points.count = vCount;
125 triangleDesc.points.stride = vStride;
126 triangleDesc.points.data = vd + m_posOffset;
127
128 triangleDesc.flags = {}; //??? physx::PxMeshFlag::eFLIPNORMALS or
129 // physx::PxMeshFlag::e16_BIT_INDICES
130 triangleDesc.triangles.count = iCount / 3;
131 triangleDesc.triangles.stride = iStride * 3;
132 triangleDesc.triangles.data = m_ssgMesh.indexBuffer().data.constData();
133
134 const auto cooking = QPhysicsWorld::getCooking();
135 if (cooking && cooking->cookTriangleMesh(triangleDesc, buf, &result)) {
136 auto size = buf.getSize();
137 auto *data = buf.getData();
138 physx::PxDefaultMemoryInputData input(data, size);
139 m_triangleMesh = thePhysics->createTriangleMesh(input);
140 qCDebug(lcQuick3dPhysics) << "Created triangle mesh" << m_triangleMesh << "for mesh"
141 << this;
143 } else {
144 qCWarning(lcQuick3dPhysics) << "Could not create triangle mesh from" << m_meshPath;
145 }
146
147 return m_triangleMesh;
148}
149
150void QQuick3DPhysicsMesh::loadSsgMesh()
151{
152 if (m_ssgMesh.isValid())
153 return;
154
155 static const char *compTypes[] = { "Null", "UnsignedInt8", "Int8", "UnsignedInt16",
156 "Int16", "UnsignedInt32", "Int32", "UnsignedInt64",
157 "Int64", "Float16", "Float32", "Float64" };
158
159 QFileInfo fileInfo = QFileInfo(m_meshPath);
160 if (fileInfo.exists()) {
161 QFile file(fileInfo.absoluteFilePath());
163 m_ssgMesh = QSSGMesh::Mesh::loadMesh(&file);
164 }
165 qCDebug(lcQuick3dPhysics) << "Loaded SSG mesh from" << m_meshPath << m_ssgMesh.isValid()
166 << "draw" << int(m_ssgMesh.drawMode()) << "wind"
167 << int(m_ssgMesh.winding()) << "subs" << m_ssgMesh.subsets().count()
168 << "attrs" << m_ssgMesh.vertexBuffer().entries.count()
169 << m_ssgMesh.vertexBuffer().data.size() << "stride"
170 << m_ssgMesh.vertexBuffer().stride << "verts"
171 << m_ssgMesh.vertexBuffer().data.size()
172 / m_ssgMesh.vertexBuffer().stride;
173
174 for (auto &v : m_ssgMesh.vertexBuffer().entries) {
175 qCDebug(lcQuick3dPhysics) << " attr" << v.name << compTypes[int(v.componentType)] << "cc"
176 << v.componentCount << "offs" << v.offset;
177 Q_ASSERT(v.componentType == QSSGMesh::Mesh::ComponentType::Float32);
178 if (v.name == "attr_pos")
179 m_posOffset = v.offset;
180 }
181
182 if (m_ssgMesh.isValid()) {
183 auto sub = m_ssgMesh.subsets().constFirst();
184 qCDebug(lcQuick3dPhysics) << "..." << sub.name << "count" << sub.count << "bounds"
185 << sub.bounds.min << sub.bounds.max << "offset" << sub.offset;
186 }
187
188#if 0 // EXTRA_DEBUG
189
190 int iStride = m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 ? 2 : 4;
191 int vStride = m_ssgMesh.vertexBuffer().stride;
192 qDebug() << "IDX" << compTypes[int(m_ssgMesh.indexBuffer().componentType)] << m_ssgMesh.indexBuffer().data.size() / iStride;
193 const auto ib = m_ssgMesh.indexBuffer().data;
194 const auto vb = m_ssgMesh.vertexBuffer().data;
195
196 auto getPoint = [&vb, vStride, this](int idx) -> QVector3D {
197 auto *vp = vb.constData() + vStride * idx + m_posOffset;
198 return *reinterpret_cast<const QVector3D *>(vp);
199 return {};
200 };
201
202 if (iStride == 2) {
203
204 } else {
205 auto *ip = reinterpret_cast<const uint32_t *>(ib.data());
206 int n = ib.size() / iStride;
207 for (int i = 0; i < qMin(50,n); i += 3) {
208
209 qDebug() << " " << ip [i] << ip[i+1] << ip[i+2] << " --- "
210 << getPoint(ip[i]) << getPoint(ip[i+1]) << getPoint(ip[i+2]);
211 }
212 }
213#endif
214 if (!m_ssgMesh.isValid())
215 qCWarning(lcQuick3dPhysics) << "Could not read mesh from" << m_meshPath;
216}
217
219 const QObject *contextObject)
220{
221 const QQmlContext *context = qmlContext(contextObject);
222 const auto resolvedUrl = context ? context->resolvedUrl(source) : source;
223 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
224 auto *mesh = meshHash.value(qmlSource);
225 if (!mesh) {
226 mesh = new QQuick3DPhysicsMesh(qmlSource);
227 meshHash[qmlSource] = mesh;
228 }
229 mesh->ref();
230 return mesh;
231}
232
234{
235 if (mesh->deref() == 0) {
236 qCDebug(lcQuick3dPhysics()) << "deleting mesh" << mesh;
237 erase_if(meshHash, [mesh](std::pair<const QString &, QQuick3DPhysicsMesh *&> h) {
238 return h.second == mesh;
239 });
240 delete mesh;
241 }
242}
243
244QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::meshHash;
245
272
274{
275 delete m_meshGeometry;
276 if (m_mesh)
278}
279
281{
282 if (m_dirtyPhysx || m_scaleDirty) {
283 updatePhysXGeometry();
284 }
285 return m_meshGeometry;
286}
287
288void QConvexMeshShape::updatePhysXGeometry()
289{
290 delete m_meshGeometry;
291 m_meshGeometry = nullptr;
292
293 auto *convexMesh = m_mesh->convexMesh();
294 if (!convexMesh)
295 return;
296
297 auto meshScale = sceneScale();
298 physx::PxMeshScale scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()),
299 physx::PxQuat(physx::PxIdentity));
300
301 m_meshGeometry = new physx::PxConvexMeshGeometry(convexMesh, scale);
302 m_dirtyPhysx = false;
303}
304
305const QUrl &QConvexMeshShape::source() const
306{
307 return m_meshSource;
308}
309
310void QConvexMeshShape::setSource(const QUrl &newSource)
311{
312 if (m_meshSource == newSource)
313 return;
314 m_meshSource = newSource;
315 m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this);
316 updatePhysXGeometry();
317
318 m_dirtyPhysx = true;
319
320 emit needsRebuild(this);
321 emit sourceChanged();
322}
323
void needsRebuild(QObject *)
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
physx::PxGeometry * getPhysXGeometry() override
QConvexMeshShape()
\qmltype ConvexMeshShape \inherits CollisionShape \inqmlmodule QtQuick3D.Physics
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
\inmodule QtCore
Definition qhash.h:818
T value(const Key &key) const noexcept
Definition qhash.h:1044
Definition qlist.h:74
const_pointer constData() const noexcept
Definition qlist.h:416
\inmodule QtCore
Definition qobject.h:90
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to QFile.
Definition qqmlfile.cpp:643
QVector3D sceneScale
QVector3D scale
static void releaseMesh(QQuick3DPhysicsMesh *mesh)
static QQuick3DPhysicsMesh * getMesh(const QUrl &source, const QObject *contextObject)
physx::PxTriangleMesh * triangleMesh()
physx::PxConvexMesh * convexMesh()
bool isValid() const
Definition qssgmesh_p.h:116
static Mesh loadMesh(QIODevice *device, quint32 id=0)
Definition qssgmesh.cpp:581
VertexBuffer vertexBuffer() const
Definition qssgmesh_p.h:97
Winding winding() const
Definition qssgmesh_p.h:119
IndexBuffer indexBuffer() const
Definition qssgmesh_p.h:98
QVector< Subset > subsets() const
Definition qssgmesh_p.h:100
DrawMode drawMode() const
Definition qssgmesh_p.h:118
\inmodule QtCore
Definition qurl.h:94
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
void writeCachedConvexMesh(const QString &filePath, physx::PxDefaultMemoryOutputStream &buf)
void writeCachedTriangleMesh(const QString &filePath, physx::PxDefaultMemoryOutputStream &buf)
physx::PxTriangleMesh * readCachedTriangleMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxConvexMesh * readCookedConvexMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxTriangleMesh * readCookedTriangleMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxConvexMesh * readCachedConvexMesh(const QString &filePath, physx::PxPhysics &physics)
Combined button and popup list for selecting options.
static void * context
qsizetype erase_if(QByteArray &ba, Predicate pred)
Definition qbytearray.h:701
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter * sub
#define qDebug
[1]
Definition qlogging.h:160
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLuint64EXT * result
[6]
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLenum input
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
QFile file
[0]
ComponentType componentType
Definition qssgmesh_p.h:66
QVector< VertexBufferEntry > entries
Definition qssgmesh_p.h:61