From 9fab556232522fbafb0935ec27c076b3e7f53ce2 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 16 Jun 2023 14:05:53 +0200
Subject: [PATCH 001/108] [SL] Add support for GPU skinning
GPU skinning can be enabled for a material, which causes the
shader generator to include code for applying the joint transforms
to the vertices. GPU skinning is currently enabled for models loaded
using assimp.
---
modules/sl/source/SLMaterial.h | 47 ++++++++++---------
modules/sl/source/gl/SLGLProgramGenerated.cpp | 45 ++++++++++++++++--
modules/sl/source/input/SLAssimpImporter.cpp | 1 +
modules/sl/source/mesh/SLMesh.cpp | 47 +++++++++++++++++--
4 files changed, 112 insertions(+), 28 deletions(-)
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index 60dbbd97..2a4d6f2f 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -198,6 +198,7 @@ class SLMaterial : public SLObject
void program(SLGLProgram* sp) { _program = sp; }
void programTF(SLGLProgram* sp) { _programTF = sp; }
void skybox(SLSkybox* sb) { _skybox = sb; }
+ void useGPUSkinning(SLbool useGPUSkinning) { _useGPUSkinning = useGPUSkinning; }
void ps(SLParticleSystem* ps) { _ps = ps; }
// Getters
@@ -220,6 +221,7 @@ class SLMaterial : public SLObject
SLGLProgram* program() { return _program; }
SLGLProgram* programTF() { return _programTF; }
SLSkybox* skybox() { return _skybox; }
+ SLbool useGPUSkinning() { return _useGPUSkinning; }
SLParticleSystem* ps() { return _ps; }
SLVNode& nodesVisible2D() { return _nodesVisible2D; }
SLVNode& nodesVisible3D() { return _nodesVisible3D; }
@@ -231,36 +233,37 @@ class SLMaterial : public SLObject
static SLfloat PERFECT; //!< PM: shininess/translucency limit
protected:
- SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
- SLReflectionModel _reflectionModel; //!< reflection model (RM_BlinnPhong or RM_CookTorrance)
- SLCol4f _ambient; //!< ambient color (RGB reflection coefficients)
- SLCol4f _diffuse; //!< diffuse color (RGB reflection coefficients)
- SLCol4f _specular; //!< specular color (RGB reflection coefficients)
- SLCol4f _emissive; //!< emissive color coefficients
- SLfloat _shininess; //!< shininess exponent in Blinn-Phong model
- SLfloat _roughness; //!< roughness property (0-1) in Cook-Torrance model
- SLfloat _metalness; //!< metallic property (0-1) in Cook-Torrance model
- SLCol4f _transmissive; //!< transmissive color (RGB reflection coefficients) for path tracing
- SLfloat _translucency; //!< translucency exponent for light refraction for path tracing
- SLfloat _kr{}; //!< reflection coefficient 0.0 - 1.0 used for ray and path tracing
- SLfloat _kt{}; //!< transmission coefficient 0.0 - 1.0 used for ray and path tracing
- SLfloat _kn{}; //!< refraction index
- SLbool _getsShadows; //!< true if shadows are visible on this material
- SLGLProgram* _program{}; //!< pointer to a GLSL shader program
- SLGLProgram* _programTF{}; //!< pointer to a GLSL shader program for transformFeedback
- SLint _numTextures; //!< number of textures in all _textures vectors array
- SLSkybox* _skybox; //!< pointer to the skybox
+ SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
+ SLReflectionModel _reflectionModel; //!< reflection model (RM_BlinnPhong or RM_CookTorrance)
+ SLCol4f _ambient; //!< ambient color (RGB reflection coefficients)
+ SLCol4f _diffuse; //!< diffuse color (RGB reflection coefficients)
+ SLCol4f _specular; //!< specular color (RGB reflection coefficients)
+ SLCol4f _emissive; //!< emissive color coefficients
+ SLfloat _shininess; //!< shininess exponent in Blinn-Phong model
+ SLfloat _roughness; //!< roughness property (0-1) in Cook-Torrance model
+ SLfloat _metalness; //!< metallic property (0-1) in Cook-Torrance model
+ SLCol4f _transmissive; //!< transmissive color (RGB reflection coefficients) for path tracing
+ SLfloat _translucency; //!< translucency exponent for light refraction for path tracing
+ SLfloat _kr{}; //!< reflection coefficient 0.0 - 1.0 used for ray and path tracing
+ SLfloat _kt{}; //!< transmission coefficient 0.0 - 1.0 used for ray and path tracing
+ SLfloat _kn{}; //!< refraction index
+ SLbool _getsShadows; //!< true if shadows are visible on this material
+ SLGLProgram* _program{}; //!< pointer to a GLSL shader program
+ SLGLProgram* _programTF{}; //!< pointer to a GLSL shader program for transformFeedback
+ SLint _numTextures; //!< number of textures in all _textures vectors array
+ SLSkybox* _skybox; //!< pointer to the skybox
+ bool _useGPUSkinning = false; //!< whether skinning is performed on the GPU or on the CPU
// For particle system
- SLParticleSystem* _ps; //!< pointer to a particle system
+ SLParticleSystem* _ps; //!< pointer to a particle system
SLVGLTexture _textures[TT_numTextureType]; //!< array of texture vectors one for each type
SLVGLTexture _textures3d; //!< texture vector for diffuse 3D textures
SLGLTexture* _errorTexture = nullptr; //!< pointer to error texture that is shown if another texture fails
SLstring _compileErrorTexFilePath; //!< path to the error texture
- SLVNode _nodesVisible2D; //!< Vector of all visible 2D nodes of with this material
- SLVNode _nodesVisible3D; //!< Vector of all visible 3D nodes of with this material
+ SLVNode _nodesVisible2D; //!< Vector of all visible 2D nodes of with this material
+ SLVNode _nodesVisible3D; //!< Vector of all visible 3D nodes of with this material
};
//-----------------------------------------------------------------------------
//! STL vector of material pointers
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index bdb9aabf..0423ee6c 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -50,6 +50,10 @@ const string vertInput_a_uv1 = R"(
layout (location = 3) in vec2 a_uv1; // Vertex tex.coord. 2 for AO)";
const string vertInput_a_tangent = R"(
layout (location = 5) in vec4 a_tangent; // Vertex tangent attribute)";
+const string vertInput_a_skinning = R"(
+
+layout (location = 6) in vec4 a_jointIds; // Vertex joint indices attributes
+layout (location = 7) in vec4 a_jointWeights; // Vertex joint weights attributes)";
//-----------------------------------------------------------------------------
const string vertInput_u_matrices_all = R"(
@@ -59,6 +63,10 @@ uniform mat4 u_pMatrix; // Projection matrix (camera to normalize device coo
const string vertInput_u_matrix_vOmv = R"(
uniform mat4 u_vOmvMatrix; // view or modelview matrix)";
//-----------------------------------------------------------------------------
+const string vertInput_u_jointMatrices = R"(
+
+uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning)";
+//-----------------------------------------------------------------------------
const string vertInput_u_lightNm = R"(
uniform vec4 u_lightPosVS[NUM_LIGHTS]; // position of light in view space
@@ -188,6 +196,20 @@ const string vertMain_v_uv0 = R"(
v_uv0 = a_uv0; // pass diffuse color tex.coord. 1 for interpolation)";
const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
+const string vertMain_skinning = R"(
+
+ vec4 totalPosition = vec4(0.0);
+ vec3 totalNormal = vec3(0.0);
+
+ for (int i = 0; i < 4; i++)
+ {
+ mat4 jointMatrix = u_jointMatrices[int(a_jointIds[i])];
+ totalPosition += a_jointWeights[i] * jointMatrix * a_position;
+ totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
+ }
+
+ v_P_VS = vec3(mvMatrix * totalPosition);
+ v_N_VS = normalize(vec3(nMatrix * totalNormal));)";
const string vertMain_TBN_Nm = R"(
// Building the matrix Eye Space -> Tangent Space
@@ -267,6 +289,14 @@ const string vertMain_EndAll = R"(
gl_Position = u_pMatrix * mvMatrix * a_position;
}
)";
+
+const string vertMain_EndSkinned = R"(
+
+ // pass the vertex w. the fix-function transform
+ gl_Position = u_pMatrix * mvMatrix * totalPosition;
+}
+)";
+
//-----------------------------------------------------------------------------
const string vertMain_PS_U_Begin = R"(
@@ -1582,7 +1612,7 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
if (light->doCascadedShadows())
programName += "C" + std::to_string(light->shadowMap()->numCascades()); // Directional light with cascaded shadowmap
else
- programName += "D"; // Directional light
+ programName += "D"; // Directional light
}
else if (light->spotCutOffDEG() < 180.0f)
programName += "S"; // Spot light
@@ -1591,6 +1621,9 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
if (light->createsShadows())
programName += "s"; // Creates shadows
}
+
+ if (mat->useGPUSkinning())
+ programName += "-S";
}
//-----------------------------------------------------------------------------
/*! See the class information for more insights of the generated name. This
@@ -1653,7 +1686,7 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
if (FlBoTex) programName += "-FB";
if (WS) programName += "-WS";
}
- else // Updating program
+ else // Updating program
{
bool counterGap = mat->ps()->doCounterGap(); // Counter gap/lag
bool acc = mat->ps()->doAcc(); // Acceleration
@@ -1889,6 +1922,9 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
bool uv0 = mat->usesUVIndex(0);
bool uv1 = mat->usesUVIndex(1);
+ // Check if we use GPU skinning
+ bool skinning = mat->useGPUSkinning();
+
// Assemble vertex shader code
string vertCode;
vertCode += shaderHeader((int)lights->size());
@@ -1898,7 +1934,9 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (uv0) vertCode += vertInput_a_uv0;
if (uv1) vertCode += vertInput_a_uv1;
if (Nm) vertCode += vertInput_a_tangent;
+ if (skinning) vertCode += vertInput_a_skinning;
vertCode += vertInput_u_matrices_all;
+ if (skinning) vertCode += vertInput_u_jointMatrices;
if (Nm) vertCode += vertInput_u_lightNm;
// Vertex shader outputs
@@ -1916,8 +1954,9 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
vertCode += vertMain_v_N_VS;
if (uv0) vertCode += vertMain_v_uv0;
if (uv1) vertCode += vertMain_v_uv1;
+ if (skinning) vertCode += vertMain_skinning;
if (Nm) vertCode += vertMain_TBN_Nm;
- vertCode += vertMain_EndAll;
+ vertCode += skinning ? vertMain_EndSkinned : vertMain_EndAll;
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
diff --git a/modules/sl/source/input/SLAssimpImporter.cpp b/modules/sl/source/input/SLAssimpImporter.cpp
index 4d89bb61..823e7bca 100644
--- a/modules/sl/source/input/SLAssimpImporter.cpp
+++ b/modules/sl/source/input/SLAssimpImporter.cpp
@@ -691,6 +691,7 @@ SLMaterial* SLAssimpImporter::loadMaterial(SLAssetManager* am,
// Create SLMaterial instance. It is also added to the SLScene::_materials vector
SLMaterial* slMat = new SLMaterial(am, name.c_str());
+ slMat->useGPUSkinning(true);
// load all the textures for this aiMat and add it to the aiMat vector
for (int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 99c21015..c46b5227 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -442,6 +442,9 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
sp->uniformMatrix4fv("u_vMatrix", 1, (SLfloat*)&stateGL->viewMatrix);
sp->uniformMatrix4fv("u_pMatrix", 1, (SLfloat*)&stateGL->projectionMatrix);
+ if (!_jointMatrices.empty())
+ sp->uniformMatrix4fv("u_jointMatrices", 100, (SLfloat*)&_jointMatrices[0]);
+
SLint locTM = sp->getUniformLocation("u_tMatrix");
if (locTM >= 0)
{
@@ -597,7 +600,7 @@ void SLMesh::handleRectangleSelection(SLSceneView* sv,
(SLfloat)vp.width,
(SLfloat)vp.height);
SLMat4f v_mvp = v * mvp;
- set tempIselected; // Temp. vector for selected vertex indices
+ set tempIselected; // Temp. vector for selected vertex indices
if (!cam->selectRect().isEmpty()) // Do rectangle Selection
{
@@ -735,8 +738,44 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
}
}
+ bool useCPUSkinning = !Ji.empty() && !_mat->useGPUSkinning();
+ bool useGPUSkinning = _mat->useGPUSkinning();
+
+ SLVVec4f gpuIndices(P.size(), SLVec4f(0, 0, 0, 0));
+ SLVVec4f gpuWeights(P.size(), SLVec4f(1.0f, 0.0f, 0.0f, 0.0f));
+
+ if (!Ji.empty())
+ {
+ for (unsigned i = 0; i < P.size(); i++)
+ {
+ const SLVuchar& indices = Ji[i];
+
+ SLint i0 = indices.size() >= 1 ? indices[0] : 0;
+ SLint i1 = indices.size() >= 2 ? indices[1] : 0;
+ SLint i2 = indices.size() >= 3 ? indices[2] : 0;
+ SLint i3 = indices.size() >= 4 ? indices[3] : 0;
+
+ gpuIndices[i] = SLVec4f((SLfloat)i0, (SLfloat)i1, (SLfloat)i2, (SLfloat)i3);
+ }
+
+ for (unsigned i = 0; i < P.size(); i++)
+ {
+ const SLVfloat& weights = Jw[i];
+
+ SLfloat w0 = weights.size() >= 1 ? weights[0] : 0.0f;
+ SLfloat w1 = weights.size() >= 2 ? weights[1] : 0.0f;
+ SLfloat w2 = weights.size() >= 3 ? weights[2] : 0.0f;
+ SLfloat w3 = weights.size() >= 4 ? weights[3] : 0.0f;
+
+ gpuWeights[i] = SLVec4f(w0, w1, w2, w3);
+ }
+ }
+
+ vao.setAttrib(AT_jointIndex, AT_jointIndex, &gpuIndices);
+ vao.setAttrib(AT_jointWeight, AT_jointWeight, &gpuWeights);
+
vao.generate((SLuint)P.size(),
- !Ji.empty() ? BU_stream : BU_static,
+ useCPUSkinning ? BU_stream : BU_static,
Ji.empty());
}
//-----------------------------------------------------------------------------
@@ -1511,7 +1550,7 @@ void SLMesh::transformSkin(const std::function& cbInformNodes)
if (_jointMatrices.empty())
{
_jointMatrices.clear();
- _jointMatrices.resize((SLuint)_skeleton->numJoints());
+ _jointMatrices.resize(100);
}
// update the joint matrix array
@@ -1527,6 +1566,8 @@ void SLMesh::transformSkin(const std::function& cbInformNodes)
// flag acceleration structure to be rebuilt
_accelStructIsOutOfDate = true;
+ if (_mat->useGPUSkinning()) return;
+
// iterate over all vertices and write to new buffers
for (SLulong i = 0; i < P.size(); ++i)
{
From 27033f672ad0ae15121b5fa34db5161be2bcfa49 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 16 Jun 2023 14:43:24 +0200
Subject: [PATCH 002/108] [SL] Use integer joint IDs for GPU skinning
The a_jointIds attribute now has the type ivec4 instead of vec4.
This removes the cost of converting the IDs to floats on the CPU
and back to int on the GPU.
---
modules/math/source/SLVec4.h | 9 +++++----
modules/sl/source/gl/SLGLEnums.h | 1 +
modules/sl/source/gl/SLGLProgramGenerated.cpp | 4 ++--
modules/sl/source/gl/SLGLVertexArray.h | 5 +++++
modules/sl/source/gl/SLGLVertexBuffer.cpp | 15 ++++++++-------
modules/sl/source/mesh/SLMesh.cpp | 4 ++--
6 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/modules/math/source/SLVec4.h b/modules/math/source/SLVec4.h
index e34b7b70..23598c31 100644
--- a/modules/math/source/SLVec4.h
+++ b/modules/math/source/SLVec4.h
@@ -232,15 +232,16 @@ template SLVec4 SLVec4::YELLOW = SLVec4(1.0f, 1.0f, 0.0f, 1.0f
template SLVec4 SLVec4::CYAN = SLVec4(0.0f, 1.0f, 1.0f, 1.0f);
template SLVec4 SLVec4::MAGENTA= SLVec4(1.0f, 0.0f, 1.0f, 1.0f);
//-----------------------------------------------------------------------------
-typedef SLVec4 SLVec4f;
-typedef SLVec4 SLVec4i;
-typedef SLVec4 SLCol4f;
+typedef SLVec4 SLVec4f;
+typedef SLVec4 SLVec4i;
+typedef SLVec4 SLCol4f;
typedef vector SLVVec4f;
+typedef vector SLVVec4i;
typedef vector SLVCol4f;
#ifdef SL_HAS_DOUBLE
-typedef SLVec4 SLVec4d;
+typedef SLVec4 SLVec4d;
typedef vector SLVVec4d;
#endif
//-----------------------------------------------------------------------------
diff --git a/modules/sl/source/gl/SLGLEnums.h b/modules/sl/source/gl/SLGLEnums.h
index b57ddf04..01c436d4 100644
--- a/modules/sl/source/gl/SLGLEnums.h
+++ b/modules/sl/source/gl/SLGLEnums.h
@@ -19,6 +19,7 @@
enum SLGLBufferType
{
BT_float = GL_FLOAT, //!< float vertex attributes
+ BT_int = GL_INT, //!< int vertex attributes
BT_ubyte = GL_UNSIGNED_BYTE, //!< vertex index type (0-2^8)
BT_ushort = GL_UNSIGNED_SHORT, //!< vertex index type (0-2^16)
BT_uint = GL_UNSIGNED_INT //!< vertex index type (0-2^32)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 0423ee6c..479a4395 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -52,7 +52,7 @@ const string vertInput_a_tangent = R"(
layout (location = 5) in vec4 a_tangent; // Vertex tangent attribute)";
const string vertInput_a_skinning = R"(
-layout (location = 6) in vec4 a_jointIds; // Vertex joint indices attributes
+layout (location = 6) in ivec4 a_jointIds; // Vertex joint indices attributes
layout (location = 7) in vec4 a_jointWeights; // Vertex joint weights attributes)";
//-----------------------------------------------------------------------------
const string vertInput_u_matrices_all = R"(
@@ -203,7 +203,7 @@ const string vertMain_skinning = R"(
for (int i = 0; i < 4; i++)
{
- mat4 jointMatrix = u_jointMatrices[int(a_jointIds[i])];
+ mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
totalPosition += a_jointWeights[i] * jointMatrix * a_position;
totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
}
diff --git a/modules/sl/source/gl/SLGLVertexArray.h b/modules/sl/source/gl/SLGLVertexArray.h
index 4b902f54..72561127 100644
--- a/modules/sl/source/gl/SLGLVertexArray.h
+++ b/modules/sl/source/gl/SLGLVertexArray.h
@@ -90,6 +90,11 @@ class SLGLVertexArray
SLint location,
SLVVec4f* data) { setAttrib(type, 4, location, &data->operator[](0)); }
+ //! Adds a vertex attribute with vector of SLVec4i
+ void setAttrib(SLGLAttributeType type,
+ SLint location,
+ SLVVec4i* data) { setAttrib(type, 4, location, &data->operator[](0), BT_int); }
+
//! Adds the index array for indexed element drawing
void setIndices(SLuint numIndicesElements,
SLGLBufferType indexDataType,
diff --git a/modules/sl/source/gl/SLGLVertexBuffer.cpp b/modules/sl/source/gl/SLGLVertexBuffer.cpp
index 935f776d..70b4c525 100644
--- a/modules/sl/source/gl/SLGLVertexBuffer.cpp
+++ b/modules/sl/source/gl/SLGLVertexBuffer.cpp
@@ -199,7 +199,7 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
{
if (a.location > -1)
{ // Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
+ if (a.dataType == BT_int || a.dataType == BT_uint)
{
glVertexAttribIPointer((SLuint)a.location,
a.elementSize,
@@ -247,7 +247,7 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
if (a.location > -1)
{ // Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
+ if (a.dataType == BT_int || a.dataType == BT_uint)
{
glVertexAttribIPointer((SLuint)a.location,
a.elementSize,
@@ -289,7 +289,7 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
a.dataPointer);
// Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
+ if (a.dataType == BT_int || a.dataType == BT_uint)
{
glVertexAttribIPointer((SLuint)a.location,
a.elementSize,
@@ -367,10 +367,11 @@ SLuint SLGLVertexBuffer::sizeOfType(SLGLBufferType type)
{
switch (type)
{
- case BT_float: return sizeof(float);
- case BT_ubyte: return sizeof(unsigned char);
- case BT_ushort: return sizeof(unsigned short);
- case BT_uint: return sizeof(unsigned int);
+ case BT_float: return sizeof(SLfloat);
+ case BT_int: return sizeof(SLint);
+ case BT_ubyte: return sizeof(SLuchar);
+ case BT_ushort: return sizeof(SLushort);
+ case BT_uint: return sizeof(SLint);
default: SL_EXIT_MSG("Invalid buffer data type");
}
return 0;
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index c46b5227..251e3d99 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -741,7 +741,7 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
bool useCPUSkinning = !Ji.empty() && !_mat->useGPUSkinning();
bool useGPUSkinning = _mat->useGPUSkinning();
- SLVVec4f gpuIndices(P.size(), SLVec4f(0, 0, 0, 0));
+ SLVVec4i gpuIndices(P.size(), SLVec4i(0, 0, 0, 0));
SLVVec4f gpuWeights(P.size(), SLVec4f(1.0f, 0.0f, 0.0f, 0.0f));
if (!Ji.empty())
@@ -755,7 +755,7 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
SLint i2 = indices.size() >= 3 ? indices[2] : 0;
SLint i3 = indices.size() >= 4 ? indices[3] : 0;
- gpuIndices[i] = SLVec4f((SLfloat)i0, (SLfloat)i1, (SLfloat)i2, (SLfloat)i3);
+ gpuIndices[i] = SLVec4i(i0, i1, i2, i3);
}
for (unsigned i = 0; i < P.size(); i++)
From 6d8dc1ab3aec7bef22b945d306fbc28404595c8d Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 14:03:13 +0200
Subject: [PATCH 003/108] [SL] Force CPU skinning when required
---
modules/sl/source/SLScene.cpp | 8 +-
modules/sl/source/SLScene.h | 3 +-
modules/sl/source/SLSceneView.cpp | 3 +-
modules/sl/source/gl/SLGLProgramGenerated.cpp | 33 ++++---
modules/sl/source/mesh/SLMesh.cpp | 88 +++++++++++++------
modules/sl/source/mesh/SLMesh.h | 10 ++-
modules/sl/source/node/SLNode.cpp | 10 ++-
modules/sl/source/node/SLNode.h | 11 +--
8 files changed, 113 insertions(+), 53 deletions(-)
diff --git a/modules/sl/source/SLScene.cpp b/modules/sl/source/SLScene.cpp
index 89c239e7..53f5354b 100644
--- a/modules/sl/source/SLScene.cpp
+++ b/modules/sl/source/SLScene.cpp
@@ -134,7 +134,8 @@ void SLScene::unInit()
@return true if really something got updated
*/
bool SLScene::onUpdate(bool renderTypeIsRT,
- bool voxelsAreShown)
+ bool voxelsAreShown,
+ bool forceCPUSkinning)
{
PROFILE_FUNCTION();
@@ -176,8 +177,11 @@ bool SLScene::onUpdate(bool renderTypeIsRT,
// Do software skinning on all changed skeletons. Update any out of date acceleration structure for RT or if they're being rendered.
if (_root3D)
{
+ if (renderTypeIsRT || voxelsAreShown)
+ forceCPUSkinning = true;
+
// we use a lambda to inform nodes that share a mesh that the mesh got updated (so we don't have to transfer the root node)
- sceneHasChanged |= _root3D->updateMeshSkins([&](SLMesh* mesh)
+ sceneHasChanged |= _root3D->updateMeshSkins(forceCPUSkinning, [&](SLMesh* mesh)
{
SLVNode nodes = _root3D->findChildren(mesh, true);
for (auto* node : nodes)
diff --git a/modules/sl/source/SLScene.h b/modules/sl/source/SLScene.h
index f4981adf..8a09a6c4 100644
--- a/modules/sl/source/SLScene.h
+++ b/modules/sl/source/SLScene.h
@@ -114,7 +114,8 @@ class SLScene : public SLObject
// Misc.
bool onUpdate(bool renderTypeIsRT,
- bool voxelsAreShown);
+ bool voxelsAreShown,
+ bool forceCPUSkinning);
void init(SLAssetManager* am);
virtual void unInit();
void selectNodeMesh(SLNode* nodeToSelect, SLMesh* meshToSelect);
diff --git a/modules/sl/source/SLSceneView.cpp b/modules/sl/source/SLSceneView.cpp
index 57f5290a..fdf264b6 100644
--- a/modules/sl/source/SLSceneView.cpp
+++ b/modules/sl/source/SLSceneView.cpp
@@ -513,7 +513,8 @@ SLbool SLSceneView::onPaint()
// update current scene
sceneHasChanged = _s->onUpdate((_renderType == RT_rt),
- drawBit(SL_DB_VOXELS));
+ drawBit(SL_DB_VOXELS),
+ drawBit(SL_DB_WITHEDGES));
}
SLbool camUpdated = false;
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 479a4395..6142ffc2 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -65,7 +65,9 @@ uniform mat4 u_vOmvMatrix; // view or modelview matrix)";
//-----------------------------------------------------------------------------
const string vertInput_u_jointMatrices = R"(
-uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning)";
+uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning
+uniform bool u_skinningEnabled; // Flag if the shader should perform skinning
+)";
//-----------------------------------------------------------------------------
const string vertInput_u_lightNm = R"(
@@ -198,18 +200,29 @@ const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
const string vertMain_skinning = R"(
- vec4 totalPosition = vec4(0.0);
- vec3 totalNormal = vec3(0.0);
+ vec4 totalPosition;
+ vec3 totalNormal;
- for (int i = 0; i < 4; i++)
+ if (u_skinningEnabled)
{
- mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
- totalPosition += a_jointWeights[i] * jointMatrix * a_position;
- totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
- }
+ totalPosition = vec4(0.0);
+ totalNormal = vec3(0.0);
+
+ for (int i = 0; i < 4; i++)
+ {
+ mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
+ totalPosition += a_jointWeights[i] * jointMatrix * a_position;
+ totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
+ }
- v_P_VS = vec3(mvMatrix * totalPosition);
- v_N_VS = normalize(vec3(nMatrix * totalNormal));)";
+ v_P_VS = vec3(mvMatrix * totalPosition);
+ v_N_VS = normalize(vec3(nMatrix * totalNormal));
+ }
+ else
+ {
+ totalPosition = a_position;
+ totalNormal = a_normal;
+ })";
const string vertMain_TBN_Nm = R"(
// Building the matrix Eye Space -> Tangent Space
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 251e3d99..6bc4d7d4 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -442,8 +442,16 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
sp->uniformMatrix4fv("u_vMatrix", 1, (SLfloat*)&stateGL->viewMatrix);
sp->uniformMatrix4fv("u_pMatrix", 1, (SLfloat*)&stateGL->projectionMatrix);
- if (!_jointMatrices.empty())
- sp->uniformMatrix4fv("u_jointMatrices", 100, (SLfloat*)&_jointMatrices[0]);
+ // Pass skeleton joint matrices to the shader program
+ if (_mat->useGPUSkinning())
+ {
+ // Only perform skinning in the shader if we haven't performed CPU skinning and if there are joint IDs
+ SLbool skinningEnabled = !_isCPUSkinned && !Ji.empty();
+ sp->uniform1i("u_skinningEnabled", skinningEnabled);
+
+ if (skinningEnabled)
+ sp->uniformMatrix4fv("u_jointMatrices", 100, (SLfloat*)&_jointMatrices[0]);
+ }
SLint locTM = sp->getUniformLocation("u_tMatrix");
if (locTM >= 0)
@@ -890,8 +898,18 @@ SLbool SLMesh::hit(SLRay* ray, SLNode* node)
return true;
}
+ // Force the mesh to be skinned in software even if it would be normally skinned on the GPU.
+ // We need the results from the skinning on the CPU to perform the ray-triangle intersection.
+ if (_skeleton && _mat && _mat->useGPUSkinning() && !_isCPUSkinned)
+ transformSkin(true, [](SLMesh*) {});
+
if (_accelStruct)
+ {
+ if (_accelStructIsOutOfDate)
+ updateAccelStruct();
+
return _accelStruct->intersect(ray, node);
+ }
else
{ // intersect against all faces
SLbool wasHit = false;
@@ -1092,6 +1110,8 @@ flag is set. This can happen for mesh animations.
*/
void SLMesh::updateAccelStruct()
{
+ SL_LOG(".");
+
calcMinMax();
// Add half a percent in each direction to avoid zero size dimensions
@@ -1530,8 +1550,12 @@ a weight and an index. After the transform the VBO have to be updated.
This skinning process can also be done (a lot faster) on the GPU.
This software skinning is also needed for ray or path tracing.
*/
-void SLMesh::transformSkin(const std::function& cbInformNodes)
+void SLMesh::transformSkin(bool forceCPUSkinning,
+ const std::function& cbInformNodes)
{
+ if (_isSelected)
+ forceCPUSkinning = true;
+
// create the secondary buffers for P and N once
if (skinnedP.empty())
{
@@ -1556,44 +1580,54 @@ void SLMesh::transformSkin(const std::function& cbInformNodes)
// update the joint matrix array
_skeleton->getJointMatrices(_jointMatrices);
- // notify Parent Nodes to update AABB
+ // notify parent nodes to update AABB
cbInformNodes(this);
- // temporarily set finalP and finalN
- _finalP = &skinnedP;
- _finalN = &skinnedN;
-
// flag acceleration structure to be rebuilt
_accelStructIsOutOfDate = true;
- if (_mat->useGPUSkinning()) return;
+ // remember if this node has been skinned on the CPU
+ _isCPUSkinned = forceCPUSkinning;
- // iterate over all vertices and write to new buffers
- for (SLulong i = 0; i < P.size(); ++i)
+ // Perform software skinning if the material doesn't support CPU skinning or
+ // if the results of the skinning process are required somewehere else.
+ if (!_mat->useGPUSkinning() || forceCPUSkinning)
{
- skinnedP[i] = SLVec3f::ZERO;
- if (!N.empty()) skinnedN[i] = SLVec3f::ZERO;
+ _finalP = &skinnedP;
+ _finalN = &skinnedN;
- // accumulate final normal and positions
- for (SLulong j = 0; j < Ji[i].size(); ++j)
+ // iterate over all vertices and write to new buffers
+ for (SLulong i = 0; i < P.size(); ++i)
{
- const SLMat4f& jm = _jointMatrices[Ji[i][j]];
- SLVec4f tempPos = SLVec4f(jm * P[i]);
- skinnedP[i].x += tempPos.x * Jw[i][j];
- skinnedP[i].y += tempPos.y * Jw[i][j];
- skinnedP[i].z += tempPos.z * Jw[i][j];
+ skinnedP[i] = SLVec3f::ZERO;
+ if (!N.empty()) skinnedN[i] = SLVec3f::ZERO;
- if (!N.empty())
+ // accumulate final normal and positions
+ for (SLulong j = 0; j < Ji[i].size(); ++j)
{
- // Build the 3x3 submatrix in GLSL 110 (= mat3 jt3 = mat3(jt))
- // for the normal transform that is the normally the inverse transpose.
- // The inverse transpose can be ignored as long as we only have
- // rotation and uniform scaling in the 3x3 submatrix.
- SLMat3f jnm = jm.mat3();
- skinnedN[i] += jnm * N[i] * Jw[i][j];
+ const SLMat4f& jm = _jointMatrices[Ji[i][j]];
+ SLVec4f tempPos = SLVec4f(jm * P[i]);
+ skinnedP[i].x += tempPos.x * Jw[i][j];
+ skinnedP[i].y += tempPos.y * Jw[i][j];
+ skinnedP[i].z += tempPos.z * Jw[i][j];
+
+ if (!N.empty())
+ {
+ // Build the 3x3 submatrix in GLSL 110 (= mat3 jt3 = mat3(jt))
+ // for the normal transform that is the normally the inverse transpose.
+ // The inverse transpose can be ignored as long as we only have
+ // rotation and uniform scaling in the 3x3 submatrix.
+ SLMat3f jnm = jm.mat3();
+ skinnedN[i] += jnm * N[i] * Jw[i][j];
+ }
}
}
}
+ else
+ {
+ _finalP = &P;
+ _finalN = &N;
+ }
// update or create buffers
if (_vao.vaoID())
diff --git a/modules/sl/source/mesh/SLMesh.h b/modules/sl/source/mesh/SLMesh.h
index ff475e3f..6873db2a 100644
--- a/modules/sl/source/mesh/SLMesh.h
+++ b/modules/sl/source/mesh/SLMesh.h
@@ -151,7 +151,8 @@ class SLMesh : public SLObject
SLbool hitTriangleOS(SLRay* ray, SLNode* node, SLuint iT);
virtual void generateVAO(SLGLVertexArray& vao);
void computeHardEdgesIndices(float angleRAD, float epsilon);
- void transformSkin(const std::function& cbInformNodes);
+ void transformSkin(bool forceCPUSkinning,
+ const std::function& cbInformNodes);
void deselectPartialSelection();
#ifdef SL_HAS_OPTIX
@@ -208,8 +209,8 @@ class SLMesh : public SLObject
SLVushort IE16; //!< Vector of hard edges vertex indices 16 bit (see computeHardEdgesIndices)
SLVuint IE32; //!< Vector of hard edges vertex indices 32 bit (see computeHardEdgesIndices)
- SLVec3f minP; //!< min. vertex in OS
- SLVec3f maxP; //!< max. vertex in OS
+ SLVec3f minP; //!< min. vertex in OS
+ SLVec3f maxP; //!< max. vertex in OS
private:
void calcTangents();
@@ -243,9 +244,10 @@ class SLMesh : public SLObject
SLbool _isVolume; //!< Flag for RT if mesh is a closed volume
SLAccelStruct* _accelStruct; //!< KD-tree or uniform grid
- SLbool _accelStructIsOutOfDate; //!< Flag id accel.struct needs update
+ SLbool _accelStructIsOutOfDate; //!< Flag if accel. struct needs update
SLAnimSkeleton* _skeleton; //!< The skeleton this mesh is bound to
SLVMat4f _jointMatrices; //!< Joint matrix vector for this mesh
+ SLbool _isCPUSkinned; //!< Flag if mesh has been skinned on CPU during update
SLVVec3f* _finalP; //!< Pointer to final vertex position vector
SLVVec3f* _finalN; //!< pointer to final vertex normal vector
};
diff --git a/modules/sl/source/node/SLNode.cpp b/modules/sl/source/node/SLNode.cpp
index ee1e83a0..cee233cf 100644
--- a/modules/sl/source/node/SLNode.cpp
+++ b/modules/sl/source/node/SLNode.cpp
@@ -1106,19 +1106,23 @@ void SLNode::updateRec()
/*! Do software skinning on all changed skeletons && updateRec any out of date
acceleration structure for RT or if they're being rendered.
*/
-bool SLNode::updateMeshSkins(const std::function& cbInformNodes)
+bool SLNode::updateMeshSkins(bool forceCPUSkinning,
+ const std::function& cbInformNodes)
{
+ if (drawBit(SL_DB_WITHEDGES) || drawBit(SL_DB_ONLYEDGES) || drawBit(SL_DB_VOXELS))
+ forceCPUSkinning = true;
+
bool hasChanges = false;
// Do software skinning on changed skeleton
if (_mesh && _mesh->skeleton() && _mesh->skeleton()->changed())
{
- _mesh->transformSkin(cbInformNodes);
+ _mesh->transformSkin(forceCPUSkinning, cbInformNodes);
hasChanges = true;
}
for (auto* child : _children)
- hasChanges |= child->updateMeshSkins(cbInformNodes);
+ hasChanges |= child->updateMeshSkins(forceCPUSkinning, cbInformNodes);
return hasChanges;
}
diff --git a/modules/sl/source/node/SLNode.h b/modules/sl/source/node/SLNode.h
index 74e12451..c4e6ac1f 100644
--- a/modules/sl/source/node/SLNode.h
+++ b/modules/sl/source/node/SLNode.h
@@ -301,7 +301,8 @@ class SLNode
const SLAnimSkeleton* skeleton();
void updateRec();
virtual void doUpdate() {}
- bool updateMeshSkins(const std::function& cbInformNodes);
+ bool updateMeshSkins(bool forceCPUSkinning,
+ const std::function& cbInformNodes);
void updateMeshAccelStructs();
void updateMeshMat(std::function setMat,
bool recursive);
@@ -310,7 +311,7 @@ class SLNode
SLfloat minLodCoverage() { return _minLodCoverage; }
SLubyte levelForSM() { return _levelForSM; }
- static SLuint numWMUpdates; //!< NO. of calls to updateWMRec per frame
+ static SLuint numWMUpdates; //!< NO. of calls to updateWMRec per frame
static unsigned int instanceIndex; //!< ???
@@ -335,9 +336,9 @@ class SLNode
SLbool findRecursive);
protected:
- SLNode* _parent; //!< pointer to the parent node
- SLVNode _children; //!< vector of children nodes
- SLMesh* _mesh; //!< pointer to a single mesh
+ SLNode* _parent; //!< pointer to the parent node
+ SLVNode _children; //!< vector of children nodes
+ SLMesh* _mesh; //!< pointer to a single mesh
SLint _depth; //!< depth of the node in a scene tree
SLint _entityID; //!< ID in the SLVEntity graph for Data Oriented Design
From 7427bcc31ed6c3ea75b28675be2b820d37bbe01d Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 15:03:11 +0200
Subject: [PATCH 004/108] [SL] Add draw bit for GPU skinning
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 4 +++
.../app_demo_slproject/source/AppDemoLoad.cpp | 4 +++
modules/sl/source/SLDrawBits.h | 27 ++++++++++---------
modules/sl/source/SLSceneView.cpp | 2 +-
4 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index e4d20e0d..20459536 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -2393,6 +2393,9 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
if (ImGui::MenuItem("Skeleton", "K", sv->drawBits()->get(SL_DB_SKELETON)))
sv->drawBits()->toggle(SL_DB_SKELETON);
+ if (ImGui::MenuItem("GPU Skinning", "G", sv->drawBits()->get(SL_DB_GPU_SKINNING)))
+ sv->drawBits()->toggle(SL_DB_GPU_SKINNING);
+
if (ImGui::MenuItem("All off"))
sv->drawBits()->allOff();
@@ -2407,6 +2410,7 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
sv->drawBits()->on(SL_DB_BBOX);
sv->drawBits()->on(SL_DB_SKELETON);
sv->drawBits()->on(SL_DB_CULLOFF);
+ sv->drawBits()->on(SL_DB_GPU_SKINNING);
}
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
diff --git a/apps/app_demo_slproject/source/AppDemoLoad.cpp b/apps/app_demo_slproject/source/AppDemoLoad.cpp
index d8f0a7ec..66184142 100644
--- a/apps/app_demo_slproject/source/AppDemoLoad.cpp
+++ b/apps/app_demo_slproject/source/AppDemoLoad.cpp
@@ -3594,6 +3594,9 @@ resolution shadows near the camera and lower resolution shadows further away.");
scene->addChild(center);
scene->addChild(cam1);
+ std::uniform_real_distribution dist(0.0f, 1.0f);
+ std::default_random_engine randEngine;
+
// create astroboys around the center astroboy
SLint size = 4;
for (SLint iZ = -size; iZ <= size; ++iZ)
@@ -3607,6 +3610,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
float zt = float(iZ) * 1.0f + ((shift) ? 0.5f : 0.0f);
SLNode* n = center->copyRec();
n->translate(xt, 0, zt, TS_object);
+ n->scale(0.75f + 0.5f * dist(randEngine));
scene->addChild(n);
}
}
diff --git a/modules/sl/source/SLDrawBits.h b/modules/sl/source/SLDrawBits.h
index 9bdf55eb..c6dbef7e 100644
--- a/modules/sl/source/SLDrawBits.h
+++ b/modules/sl/source/SLDrawBits.h
@@ -17,19 +17,20 @@
Drawing Bits control some visual states of the scene and are applied per scene
view or per single node object. Not all are used from the beginning
*/
-#define SL_DB_HIDDEN 1 //!< Flags an object as hidden
-#define SL_DB_NOTSELECTABLE 2 //!< Flags an object as selected
-#define SL_DB_MESHWIRED 4 //!< Draw polygons as wired mesh
-#define SL_DB_NORMALS 8 //!< Draw the vertex normals
-#define SL_DB_BBOX 16 //!< Draw the bounding boxes of a node
-#define SL_DB_AXIS 32 //!< Draw the coordinate axis of a node
-#define SL_DB_VOXELS 64 //!< Draw the voxels of the uniform grid
-#define SL_DB_SKELETON 128 //!< Draw the skeletons joints
-#define SL_DB_CULLOFF 256 //!< Turn off face culling
-#define SL_DB_OVERDRAW 512 //!< Draw node over all other nodes
-#define SL_DB_WITHEDGES 1024 //!< Draw faces with hard edges
-#define SL_DB_ONLYEDGES 2048 //!< Draw only hard edges
-#define SL_DB_BRECT 4096 //!< Draw the bounding rectangle of a node
+#define SL_DB_HIDDEN 1 //!< Flags an object as hidden
+#define SL_DB_NOTSELECTABLE 2 //!< Flags an object as selected
+#define SL_DB_MESHWIRED 4 //!< Draw polygons as wired mesh
+#define SL_DB_NORMALS 8 //!< Draw the vertex normals
+#define SL_DB_BBOX 16 //!< Draw the bounding boxes of a node
+#define SL_DB_AXIS 32 //!< Draw the coordinate axis of a node
+#define SL_DB_VOXELS 64 //!< Draw the voxels of the uniform grid
+#define SL_DB_SKELETON 128 //!< Draw the skeletons joints
+#define SL_DB_CULLOFF 256 //!< Turn off face culling
+#define SL_DB_OVERDRAW 512 //!< Draw node over all other nodes
+#define SL_DB_WITHEDGES 1024 //!< Draw faces with hard edges
+#define SL_DB_ONLYEDGES 2048 //!< Draw only hard edges
+#define SL_DB_BRECT 4096 //!< Draw the bounding rectangle of a node
+#define SL_DB_GPU_SKINNING 8192 //!< Perform skinning on the GPU
//-----------------------------------------------------------------------------
//! Drawing states stored in the bits of an unsigned int
diff --git a/modules/sl/source/SLSceneView.cpp b/modules/sl/source/SLSceneView.cpp
index fdf264b6..d58af6cf 100644
--- a/modules/sl/source/SLSceneView.cpp
+++ b/modules/sl/source/SLSceneView.cpp
@@ -514,7 +514,7 @@ SLbool SLSceneView::onPaint()
// update current scene
sceneHasChanged = _s->onUpdate((_renderType == RT_rt),
drawBit(SL_DB_VOXELS),
- drawBit(SL_DB_WITHEDGES));
+ !drawBit(SL_DB_GPU_SKINNING) || drawBit(SL_DB_WITHEDGES));
}
SLbool camUpdated = false;
From e2731d738ce0a82c5df10153e5fd5e1266e761c9 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 15:06:23 +0200
Subject: [PATCH 005/108] [SL] Remove updateAccelStruct debug printing
---
modules/sl/source/mesh/SLMesh.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 6bc4d7d4..bc64ad6a 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -1110,8 +1110,6 @@ flag is set. This can happen for mesh animations.
*/
void SLMesh::updateAccelStruct()
{
- SL_LOG(".");
-
calcMinMax();
// Add half a percent in each direction to avoid zero size dimensions
From 3575143985d5707ad10bdafd1e3689f19d5a15bb Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 19 Jun 2023 16:36:58 +0200
Subject: [PATCH 006/108] Update SLMesh.cpp
---
modules/sl/source/mesh/SLMesh.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index bc64ad6a..48ebb2aa 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -449,7 +449,7 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
SLbool skinningEnabled = !_isCPUSkinned && !Ji.empty();
sp->uniform1i("u_skinningEnabled", skinningEnabled);
- if (skinningEnabled)
+ if (skinningEnabled && !_jointMatrices.empty())
sp->uniformMatrix4fv("u_jointMatrices", 100, (SLfloat*)&_jointMatrices[0]);
}
From 851d931476d2c5e9b08b27e94d0fc1e7faa050ba Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 16:43:02 +0200
Subject: [PATCH 007/108] [SL] Rename useGPUSkinning to supportsGPUSkinning
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 2 +-
modules/sl/source/SLMaterial.h | 44 +++++++++----------
modules/sl/source/gl/SLGLProgramGenerated.cpp | 4 +-
modules/sl/source/input/SLAssimpImporter.cpp | 2 +-
modules/sl/source/mesh/SLMesh.cpp | 23 +++++-----
5 files changed, 36 insertions(+), 39 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 20459536..30b69b5b 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -2393,7 +2393,7 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
if (ImGui::MenuItem("Skeleton", "K", sv->drawBits()->get(SL_DB_SKELETON)))
sv->drawBits()->toggle(SL_DB_SKELETON);
- if (ImGui::MenuItem("GPU Skinning", "G", sv->drawBits()->get(SL_DB_GPU_SKINNING)))
+ if (ImGui::MenuItem("GPU Skinning", nullptr, sv->drawBits()->get(SL_DB_GPU_SKINNING)))
sv->drawBits()->toggle(SL_DB_GPU_SKINNING);
if (ImGui::MenuItem("All off"))
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index 2a4d6f2f..e1ea9bde 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -198,7 +198,7 @@ class SLMaterial : public SLObject
void program(SLGLProgram* sp) { _program = sp; }
void programTF(SLGLProgram* sp) { _programTF = sp; }
void skybox(SLSkybox* sb) { _skybox = sb; }
- void useGPUSkinning(SLbool useGPUSkinning) { _useGPUSkinning = useGPUSkinning; }
+ void supportsGPUSkinning(SLbool supportsGPUSkinning) { _supportsGPUSkinning = supportsGPUSkinning; }
void ps(SLParticleSystem* ps) { _ps = ps; }
// Getters
@@ -221,7 +221,7 @@ class SLMaterial : public SLObject
SLGLProgram* program() { return _program; }
SLGLProgram* programTF() { return _programTF; }
SLSkybox* skybox() { return _skybox; }
- SLbool useGPUSkinning() { return _useGPUSkinning; }
+ SLbool supportsGPUSkinning() { return _supportsGPUSkinning; }
SLParticleSystem* ps() { return _ps; }
SLVNode& nodesVisible2D() { return _nodesVisible2D; }
SLVNode& nodesVisible3D() { return _nodesVisible3D; }
@@ -233,26 +233,26 @@ class SLMaterial : public SLObject
static SLfloat PERFECT; //!< PM: shininess/translucency limit
protected:
- SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
- SLReflectionModel _reflectionModel; //!< reflection model (RM_BlinnPhong or RM_CookTorrance)
- SLCol4f _ambient; //!< ambient color (RGB reflection coefficients)
- SLCol4f _diffuse; //!< diffuse color (RGB reflection coefficients)
- SLCol4f _specular; //!< specular color (RGB reflection coefficients)
- SLCol4f _emissive; //!< emissive color coefficients
- SLfloat _shininess; //!< shininess exponent in Blinn-Phong model
- SLfloat _roughness; //!< roughness property (0-1) in Cook-Torrance model
- SLfloat _metalness; //!< metallic property (0-1) in Cook-Torrance model
- SLCol4f _transmissive; //!< transmissive color (RGB reflection coefficients) for path tracing
- SLfloat _translucency; //!< translucency exponent for light refraction for path tracing
- SLfloat _kr{}; //!< reflection coefficient 0.0 - 1.0 used for ray and path tracing
- SLfloat _kt{}; //!< transmission coefficient 0.0 - 1.0 used for ray and path tracing
- SLfloat _kn{}; //!< refraction index
- SLbool _getsShadows; //!< true if shadows are visible on this material
- SLGLProgram* _program{}; //!< pointer to a GLSL shader program
- SLGLProgram* _programTF{}; //!< pointer to a GLSL shader program for transformFeedback
- SLint _numTextures; //!< number of textures in all _textures vectors array
- SLSkybox* _skybox; //!< pointer to the skybox
- bool _useGPUSkinning = false; //!< whether skinning is performed on the GPU or on the CPU
+ SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
+ SLReflectionModel _reflectionModel; //!< reflection model (RM_BlinnPhong or RM_CookTorrance)
+ SLCol4f _ambient; //!< ambient color (RGB reflection coefficients)
+ SLCol4f _diffuse; //!< diffuse color (RGB reflection coefficients)
+ SLCol4f _specular; //!< specular color (RGB reflection coefficients)
+ SLCol4f _emissive; //!< emissive color coefficients
+ SLfloat _shininess; //!< shininess exponent in Blinn-Phong model
+ SLfloat _roughness; //!< roughness property (0-1) in Cook-Torrance model
+ SLfloat _metalness; //!< metallic property (0-1) in Cook-Torrance model
+ SLCol4f _transmissive; //!< transmissive color (RGB reflection coefficients) for path tracing
+ SLfloat _translucency; //!< translucency exponent for light refraction for path tracing
+ SLfloat _kr{}; //!< reflection coefficient 0.0 - 1.0 used for ray and path tracing
+ SLfloat _kt{}; //!< transmission coefficient 0.0 - 1.0 used for ray and path tracing
+ SLfloat _kn{}; //!< refraction index
+ SLbool _getsShadows; //!< true if shadows are visible on this material
+ SLGLProgram* _program{}; //!< pointer to a GLSL shader program
+ SLGLProgram* _programTF{}; //!< pointer to a GLSL shader program for transformFeedback
+ SLint _numTextures; //!< number of textures in all _textures vectors array
+ SLSkybox* _skybox; //!< pointer to the skybox
+ bool _supportsGPUSkinning = false; //!< whether skinning is performed on the GPU or on the CPU
// For particle system
SLParticleSystem* _ps; //!< pointer to a particle system
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 6142ffc2..465c9670 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -1635,7 +1635,7 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
programName += "s"; // Creates shadows
}
- if (mat->useGPUSkinning())
+ if (mat->supportsGPUSkinning())
programName += "-S";
}
//-----------------------------------------------------------------------------
@@ -1936,7 +1936,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
bool uv1 = mat->usesUVIndex(1);
// Check if we use GPU skinning
- bool skinning = mat->useGPUSkinning();
+ bool skinning = mat->supportsGPUSkinning();
// Assemble vertex shader code
string vertCode;
diff --git a/modules/sl/source/input/SLAssimpImporter.cpp b/modules/sl/source/input/SLAssimpImporter.cpp
index 823e7bca..12930a22 100644
--- a/modules/sl/source/input/SLAssimpImporter.cpp
+++ b/modules/sl/source/input/SLAssimpImporter.cpp
@@ -691,7 +691,7 @@ SLMaterial* SLAssimpImporter::loadMaterial(SLAssetManager* am,
// Create SLMaterial instance. It is also added to the SLScene::_materials vector
SLMaterial* slMat = new SLMaterial(am, name.c_str());
- slMat->useGPUSkinning(true);
+ slMat->supportsGPUSkinning(true);
// load all the textures for this aiMat and add it to the aiMat vector
for (int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 48ebb2aa..8de969d2 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -443,7 +443,7 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
sp->uniformMatrix4fv("u_pMatrix", 1, (SLfloat*)&stateGL->projectionMatrix);
// Pass skeleton joint matrices to the shader program
- if (_mat->useGPUSkinning())
+ if (_mat->supportsGPUSkinning())
{
// Only perform skinning in the shader if we haven't performed CPU skinning and if there are joint IDs
SLbool skinningEnabled = !_isCPUSkinned && !Ji.empty();
@@ -746,14 +746,11 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
}
}
- bool useCPUSkinning = !Ji.empty() && !_mat->useGPUSkinning();
- bool useGPUSkinning = _mat->useGPUSkinning();
-
- SLVVec4i gpuIndices(P.size(), SLVec4i(0, 0, 0, 0));
- SLVVec4f gpuWeights(P.size(), SLVec4f(1.0f, 0.0f, 0.0f, 0.0f));
-
if (!Ji.empty())
{
+ SLVVec4i gpuIndices(P.size(), SLVec4i(0, 0, 0, 0));
+ SLVVec4f gpuWeights(P.size(), SLVec4f(1.0f, 0.0f, 0.0f, 0.0f));
+
for (unsigned i = 0; i < P.size(); i++)
{
const SLVuchar& indices = Ji[i];
@@ -777,13 +774,13 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
gpuWeights[i] = SLVec4f(w0, w1, w2, w3);
}
- }
- vao.setAttrib(AT_jointIndex, AT_jointIndex, &gpuIndices);
- vao.setAttrib(AT_jointWeight, AT_jointWeight, &gpuWeights);
+ vao.setAttrib(AT_jointIndex, AT_jointIndex, &gpuIndices);
+ vao.setAttrib(AT_jointWeight, AT_jointWeight, &gpuWeights);
+ }
vao.generate((SLuint)P.size(),
- useCPUSkinning ? BU_stream : BU_static,
+ !Ji.empty() && !_mat->supportsGPUSkinning() ? BU_stream : BU_static,
Ji.empty());
}
//-----------------------------------------------------------------------------
@@ -900,7 +897,7 @@ SLbool SLMesh::hit(SLRay* ray, SLNode* node)
// Force the mesh to be skinned in software even if it would be normally skinned on the GPU.
// We need the results from the skinning on the CPU to perform the ray-triangle intersection.
- if (_skeleton && _mat && _mat->useGPUSkinning() && !_isCPUSkinned)
+ if (_skeleton && _mat && _mat->supportsGPUSkinning() && !_isCPUSkinned)
transformSkin(true, [](SLMesh*) {});
if (_accelStruct)
@@ -1589,7 +1586,7 @@ void SLMesh::transformSkin(bool forceCPUSkinning,
// Perform software skinning if the material doesn't support CPU skinning or
// if the results of the skinning process are required somewehere else.
- if (!_mat->useGPUSkinning() || forceCPUSkinning)
+ if (!_mat->supportsGPUSkinning() || forceCPUSkinning)
{
_finalP = &skinnedP;
_finalN = &skinnedN;
From d518217916d6eb67d4464204b7107367c510ab6c Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 16:56:14 +0200
Subject: [PATCH 008/108] [SL] Add GUI text for GPU skinning
The text shows whether a material shader has support
for GPU skinning.
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 4 ++++
modules/sl/source/mesh/SLMesh.cpp | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 30b69b5b..d2724752 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -4337,6 +4337,7 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
ImGui::TreePop();
}
+
if (m->program() != nullptr)
{
for (auto* shd : m->program()->shaders())
@@ -4371,6 +4372,9 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
}
}
}
+
+ ImGui::Text("Supports GPU skinning: %s", m->supportsGPUSkinning() ? "Yes" : "No");
+
ImGui::TreePop();
}
}
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 8de969d2..2ecef129 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -749,7 +749,7 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
if (!Ji.empty())
{
SLVVec4i gpuIndices(P.size(), SLVec4i(0, 0, 0, 0));
- SLVVec4f gpuWeights(P.size(), SLVec4f(1.0f, 0.0f, 0.0f, 0.0f));
+ SLVVec4f gpuWeights(P.size(), SLVec4f(0.0f, 0.0f, 0.0f, 0.0f));
for (unsigned i = 0; i < P.size(); i++)
{
From 5291a44a50978879eecc1031fa99d8e900374850 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 19 Jun 2023 17:08:15 +0200
Subject: [PATCH 009/108] [SL] Only create as many joint matrices as required
---
modules/sl/source/mesh/SLMesh.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 2ecef129..6791934e 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -450,7 +450,7 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
sp->uniform1i("u_skinningEnabled", skinningEnabled);
if (skinningEnabled && !_jointMatrices.empty())
- sp->uniformMatrix4fv("u_jointMatrices", 100, (SLfloat*)&_jointMatrices[0]);
+ sp->uniformMatrix4fv("u_jointMatrices", _jointMatrices.size(), (SLfloat*)&_jointMatrices[0]);
}
SLint locTM = sp->getUniformLocation("u_tMatrix");
@@ -1569,7 +1569,7 @@ void SLMesh::transformSkin(bool forceCPUSkinning,
if (_jointMatrices.empty())
{
_jointMatrices.clear();
- _jointMatrices.resize(100);
+ _jointMatrices.resize((SLuint)_skeleton->numJoints());
}
// update the joint matrix array
From 29adf5b785386ea306b9b6fbd2279b6ec292cf8a Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Wed, 21 Jun 2023 09:04:26 +0200
Subject: [PATCH 010/108] [SL] Add some comments for GPU skinning
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 10 +++++
modules/sl/source/mesh/SLMesh.cpp | 39 ++++++++++---------
2 files changed, 30 insertions(+), 19 deletions(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 465c9670..43185814 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -205,12 +205,22 @@ const string vertMain_skinning = R"(
if (u_skinningEnabled)
{
+ // In skinned skeleton animation, every vertex of a mesh is transformed by
+ // max. four joints (bones) of a skeleton identified by indices. The
+ // joint matrices represent this transformation and can change per frame
+ // to animate the mesh. The effect that a joint has on a vertex is
+ // specified by the four weights passed along with the joint indices.
+
totalPosition = vec4(0.0);
totalNormal = vec3(0.0);
+ // iterate over all joints that are transforming this vertex.
for (int i = 0; i < 4; i++)
{
+ // get the transformation of this joint.
mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
+
+ // apply the weighted transformation to the position and normal of the vertex.
totalPosition += a_jointWeights[i] * jointMatrix * a_position;
totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
}
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 6791934e..16d193a3 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -748,35 +748,36 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
if (!Ji.empty())
{
- SLVVec4i gpuIndices(P.size(), SLVec4i(0, 0, 0, 0));
- SLVVec4f gpuWeights(P.size(), SLVec4f(0.0f, 0.0f, 0.0f, 0.0f));
+ // indices are passed to the shader as ivec4s
+ SLVVec4i indicesData(P.size(), SLVec4i(0, 0, 0, 0));
+ // weights are passed to the shader as vec4s
+ SLVVec4f indicesWeights(P.size(), SLVec4f(0.0f, 0.0f, 0.0f, 0.0f));
+
+ // create the vec4 of indices for all points
for (unsigned i = 0; i < P.size(); i++)
{
- const SLVuchar& indices = Ji[i];
-
- SLint i0 = indices.size() >= 1 ? indices[0] : 0;
- SLint i1 = indices.size() >= 2 ? indices[1] : 0;
- SLint i2 = indices.size() >= 3 ? indices[2] : 0;
- SLint i3 = indices.size() >= 4 ? indices[3] : 0;
+ const SLVuchar& curIndices = Ji[i];
- gpuIndices[i] = SLVec4i(i0, i1, i2, i3);
+ indicesData[i] = SLVec4i(curIndices.size() >= 1 ? curIndices[0] : 0,
+ curIndices.size() >= 2 ? curIndices[1] : 0,
+ curIndices.size() >= 3 ? curIndices[2] : 0,
+ curIndices.size() >= 4 ? curIndices[3] : 0);
}
+ // create the vec4 of weights for all points
for (unsigned i = 0; i < P.size(); i++)
{
- const SLVfloat& weights = Jw[i];
-
- SLfloat w0 = weights.size() >= 1 ? weights[0] : 0.0f;
- SLfloat w1 = weights.size() >= 2 ? weights[1] : 0.0f;
- SLfloat w2 = weights.size() >= 3 ? weights[2] : 0.0f;
- SLfloat w3 = weights.size() >= 4 ? weights[3] : 0.0f;
+ const SLVfloat& curWeights = Jw[i];
- gpuWeights[i] = SLVec4f(w0, w1, w2, w3);
+ indicesWeights[i] = SLVec4f(curWeights.size() >= 1 ? curWeights[0] : 0.0f,
+ curWeights.size() >= 2 ? curWeights[1] : 0.0f,
+ curWeights.size() >= 3 ? curWeights[2] : 0.0f,
+ curWeights.size() >= 4 ? curWeights[3] : 0.0f);
}
- vao.setAttrib(AT_jointIndex, AT_jointIndex, &gpuIndices);
- vao.setAttrib(AT_jointWeight, AT_jointWeight, &gpuWeights);
+ vao.setAttrib(AT_jointIndex, AT_jointIndex, &indicesData);
+ vao.setAttrib(AT_jointWeight, AT_jointWeight, &indicesWeights);
}
vao.generate((SLuint)P.size(),
@@ -1621,7 +1622,7 @@ void SLMesh::transformSkin(bool forceCPUSkinning,
else
{
_finalP = &P;
- _finalN = &N;
+ _finalN = &N;
}
// update or create buffers
From 8cf8955579a9c08b6d7380d1dd455ae937a88703 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Wed, 21 Jun 2023 15:24:03 +0200
Subject: [PATCH 011/108] [SL] Fix GPU skinning UB in generateVAO
---
modules/sl/source/mesh/SLMesh.cpp | 32 +++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 16d193a3..d3398093 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -746,20 +746,24 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
}
}
- if (!Ji.empty())
+ SLVVec4i jointIndicesData; // indices are passed to the shader as ivec4s
+ SLVVec4f jointWeightsData; // weights are passed to the shader as vec4s
+
+ if (!Ji.empty() && _mat->supportsGPUSkinning())
{
- // indices are passed to the shader as ivec4s
- SLVVec4i indicesData(P.size(), SLVec4i(0, 0, 0, 0));
+ assert(Ji.size() == P.size());
+ assert(Jw.size() == P.size());
- // weights are passed to the shader as vec4s
- SLVVec4f indicesWeights(P.size(), SLVec4f(0.0f, 0.0f, 0.0f, 0.0f));
+ jointIndicesData = SLVVec4i(P.size(), SLVec4i(0, 0, 0, 0));
+ jointWeightsData = SLVVec4f(P.size(), SLVec4f(0.0f, 0.0f, 0.0f, 0.0f));
// create the vec4 of indices for all points
for (unsigned i = 0; i < P.size(); i++)
{
const SLVuchar& curIndices = Ji[i];
+ assert(!curIndices.empty());
- indicesData[i] = SLVec4i(curIndices.size() >= 1 ? curIndices[0] : 0,
+ jointIndicesData[i] = SLVec4i(curIndices.size() >= 1 ? curIndices[0] : 0,
curIndices.size() >= 2 ? curIndices[1] : 0,
curIndices.size() >= 3 ? curIndices[2] : 0,
curIndices.size() >= 4 ? curIndices[3] : 0);
@@ -769,19 +773,19 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
for (unsigned i = 0; i < P.size(); i++)
{
const SLVfloat& curWeights = Jw[i];
+ assert(curWeights.size() == Ji[i].size());
- indicesWeights[i] = SLVec4f(curWeights.size() >= 1 ? curWeights[0] : 0.0f,
- curWeights.size() >= 2 ? curWeights[1] : 0.0f,
- curWeights.size() >= 3 ? curWeights[2] : 0.0f,
- curWeights.size() >= 4 ? curWeights[3] : 0.0f);
+ jointWeightsData[i] = SLVec4f(curWeights.size() >= 1 ? curWeights[0] : 0.0f,
+ curWeights.size() >= 2 ? curWeights[1] : 0.0f,
+ curWeights.size() >= 3 ? curWeights[2] : 0.0f,
+ curWeights.size() >= 4 ? curWeights[3] : 0.0f);
}
-
- vao.setAttrib(AT_jointIndex, AT_jointIndex, &indicesData);
- vao.setAttrib(AT_jointWeight, AT_jointWeight, &indicesWeights);
+ vao.setAttrib(AT_jointIndex, AT_jointIndex, &jointIndicesData);
+ vao.setAttrib(AT_jointWeight, AT_jointWeight, &jointWeightsData);
}
vao.generate((SLuint)P.size(),
- !Ji.empty() && !_mat->supportsGPUSkinning() ? BU_stream : BU_static,
+ !Ji.empty() ? BU_stream : BU_static,
Ji.empty());
}
//-----------------------------------------------------------------------------
From a49729fa5db46de3dd0529c43d3bb193588c81b8 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Wed, 28 Jun 2023 10:17:55 +0200
Subject: [PATCH 012/108] [SL] Add support for variables to shader generator
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 59 ++++++++++++-------
modules/sl/source/gl/SLGLProgramGenerated.h | 4 ++
2 files changed, 43 insertions(+), 20 deletions(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 43185814..6d630fe4 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -200,8 +200,8 @@ const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
const string vertMain_skinning = R"(
- vec4 totalPosition;
- vec3 totalNormal;
+ vec4 skinnedPosition;
+ vec3 skinnedNormal;
if (u_skinningEnabled)
{
@@ -211,8 +211,8 @@ const string vertMain_skinning = R"(
// to animate the mesh. The effect that a joint has on a vertex is
// specified by the four weights passed along with the joint indices.
- totalPosition = vec4(0.0);
- totalNormal = vec3(0.0);
+ skinnedPosition = vec4(0.0);
+ skinnedNormal = vec3(0.0);
// iterate over all joints that are transforming this vertex.
for (int i = 0; i < 4; i++)
@@ -221,17 +221,17 @@ const string vertMain_skinning = R"(
mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
// apply the weighted transformation to the position and normal of the vertex.
- totalPosition += a_jointWeights[i] * jointMatrix * a_position;
- totalNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
+ skinnedPosition += a_jointWeights[i] * jointMatrix * a_position;
+ skinnedNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
}
- v_P_VS = vec3(mvMatrix * totalPosition);
- v_N_VS = normalize(vec3(nMatrix * totalNormal));
+ v_P_VS = vec3(mvMatrix * skinnedPosition);
+ v_N_VS = normalize(vec3(nMatrix * skinnedNormal));
}
else
{
- totalPosition = a_position;
- totalNormal = a_normal;
+ skinnedPosition = a_position;
+ skinnedNormal = a_normal;
})";
const string vertMain_TBN_Nm = R"(
@@ -309,17 +309,9 @@ const string vertMain_PS_EndAll_VertBillboard = R"(
const string vertMain_EndAll = R"(
// pass the vertex w. the fix-function transform
- gl_Position = u_pMatrix * mvMatrix * a_position;
+ gl_Position = u_pMatrix * mvMatrix * ${localPosition};
}
)";
-
-const string vertMain_EndSkinned = R"(
-
- // pass the vertex w. the fix-function transform
- gl_Position = u_pMatrix * mvMatrix * totalPosition;
-}
-)";
-
//-----------------------------------------------------------------------------
const string vertMain_PS_U_Begin = R"(
@@ -1861,6 +1853,9 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
if (Nm) vertCode += vertMain_TBN_Nm;
vertCode += vertMain_EndAll;
+ // Vertex shader variables
+ setVariable(vertCode, "localPosition", "a_position");
+
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
// Assemble fragment shader code
@@ -1979,7 +1974,10 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (uv1) vertCode += vertMain_v_uv1;
if (skinning) vertCode += vertMain_skinning;
if (Nm) vertCode += vertMain_TBN_Nm;
- vertCode += skinning ? vertMain_EndSkinned : vertMain_EndAll;
+ vertCode += vertMain_EndAll;
+
+ // Vertex shader variables
+ setVariable(vertCode, "localPosition", skinning ? "skinnedPosition" : "a_position");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
@@ -2291,6 +2289,10 @@ void SLGLProgramGenerated::buildPerPixVideoBkgdSm(SLVLight* lights)
vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
vertCode += vertMain_EndAll;
+
+ // Vertex shader variables
+ setVariable(vertCode, "localPosition", "a_position");
+
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
// Assemble fragment shader code
@@ -2680,6 +2682,23 @@ void SLGLProgramGenerated::addCodeToShader(SLGLShader* shader,
shader->file(generatedShaderPath + name);
}
//-----------------------------------------------------------------------------
+//! Builds unique program name that identifies shader program
+/*! A variable is specified in templates like this: ${variableName}.
+ */
+void SLGLProgramGenerated::setVariable(std::string& code,
+ const std::string& name,
+ const std::string& value)
+{
+ std::string placeholder = "${" + name + "}";
+
+ std::string::size_type pos = 0;
+ while ((pos = code.find(placeholder)) != std::string::npos)
+ {
+ code.replace(pos, placeholder.size(), value);
+ pos += value.size();
+ }
+}
+//-----------------------------------------------------------------------------
//! Adds shader header code
string SLGLProgramGenerated::shaderHeader(int numLights)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index 93ebc1da..3ce56bd1 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -118,6 +118,10 @@ class SLGLProgramGenerated : public SLGLProgram
static void addCodeToShader(SLGLShader* shader,
const string& code,
const string& name);
+ static void setVariable(std::string& code,
+ const std::string& name,
+ const std::string& value);
+
static string generatedShaderPath; //! Path to write out generated shaders
};
//-----------------------------------------------------------------------------
From d4854bedac88a2279a64540952aaa0055da4dabc Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Wed, 28 Jun 2023 11:26:26 +0200
Subject: [PATCH 013/108] [SL] GPU skinning in more complex shaders
GPU skinning should now work with the Cook-Torrance
reflection model and with normal mapping.
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 100 +++++++++++-------
1 file changed, 64 insertions(+), 36 deletions(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 6d630fe4..ae0cafed 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -63,7 +63,7 @@ uniform mat4 u_pMatrix; // Projection matrix (camera to normalize device coo
const string vertInput_u_matrix_vOmv = R"(
uniform mat4 u_vOmvMatrix; // view or modelview matrix)";
//-----------------------------------------------------------------------------
-const string vertInput_u_jointMatrices = R"(
+const string vertInput_u_skinning = R"(
uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning
uniform bool u_skinningEnabled; // Flag if the shader should perform skinning
@@ -182,13 +182,13 @@ void main()
{)";
const string vertMain_v_P_VS = R"(
mat4 mvMatrix = u_vMatrix * u_mMatrix;
- v_P_VS = vec3(mvMatrix * a_position); // vertex position in view space)";
+ v_P_VS = vec3(mvMatrix * ${localPosition}); // vertex position in view space)";
const string vertMain_v_P_WS_Sm = R"(
- v_P_WS = vec3(u_mMatrix * a_position); // vertex position in world space)";
+ v_P_WS = vec3(u_mMatrix * ${localPosition}); // vertex position in world space)";
const string vertMain_v_N_VS = R"(
mat3 invMvMatrix = mat3(inverse(mvMatrix));
mat3 nMatrix = transpose(invMvMatrix);
- v_N_VS = vec3(nMatrix * a_normal); // vertex normal in view space)";
+ v_N_VS = vec3(nMatrix * ${localNormal}); // vertex normal in view space)";
const string vertMain_v_R_OS = R"(
vec3 I = normalize(v_P_VS);
vec3 N = normalize(v_N_VS);
@@ -199,47 +199,63 @@ const string vertMain_v_uv0 = R"(
const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
const string vertMain_skinning = R"(
-
vec4 skinnedPosition;
vec3 skinnedNormal;
if (u_skinningEnabled)
{
// In skinned skeleton animation, every vertex of a mesh is transformed by
- // max. four joints (bones) of a skeleton identified by indices. The
- // joint matrices represent this transformation and can change per frame
- // to animate the mesh. The effect that a joint has on a vertex is
- // specified by the four weights passed along with the joint indices.
-
- skinnedPosition = vec4(0.0);
- skinnedNormal = vec3(0.0);
-
- // iterate over all joints that are transforming this vertex.
- for (int i = 0; i < 4; i++)
- {
- // get the transformation of this joint.
- mat4 jointMatrix = u_jointMatrices[a_jointIds[i]];
-
- // apply the weighted transformation to the position and normal of the vertex.
- skinnedPosition += a_jointWeights[i] * jointMatrix * a_position;
- skinnedNormal += a_jointWeights[i] * mat3(jointMatrix) * a_normal;
- }
+ // max. four joints (bones) of a skeleton identified by indices. The joint
+ // matrix is a weighted sum of four joint matrices and can change per frame
+ // to animate the mesh.
+ mat4 jm = u_jointMatrices[int(a_jointIds.x)] * a_jointWeights.x
+ + u_jointMatrices[int(a_jointIds.y)] * a_jointWeights.y
+ + u_jointMatrices[int(a_jointIds.z)] * a_jointWeights.z
+ + u_jointMatrices[int(a_jointIds.w)] * a_jointWeights.w;
+
+ skinnedPosition = jm * a_position;
+ skinnedNormal = mat3(jm) * a_normal;
+ }
+ else
+ {
+ skinnedPosition = a_position;
+ skinnedNormal = a_normal;
+ }
+)";
+const string vertMain_skinning_Nm = R"(
+ vec4 skinnedPosition;
+ vec3 skinnedNormal;
+ vec4 skinnedTangent;
- v_P_VS = vec3(mvMatrix * skinnedPosition);
- v_N_VS = normalize(vec3(nMatrix * skinnedNormal));
+ if (u_skinningEnabled)
+ {
+ // In skinned skeleton animation, every vertex of a mesh is transformed by
+ // max. four joints (bones) of a skeleton identified by indices. The joint
+ // matrix is a weighted sum of four joint matrices and can change per frame
+ // to animate the mesh.
+ mat4 jm = u_jointMatrices[int(a_jointIds.x)] * a_jointWeights.x
+ + u_jointMatrices[int(a_jointIds.y)] * a_jointWeights.y
+ + u_jointMatrices[int(a_jointIds.z)] * a_jointWeights.z
+ + u_jointMatrices[int(a_jointIds.w)] * a_jointWeights.w;
+
+ skinnedPosition = jm * a_position;
+ skinnedNormal = mat3(jm) * a_normal;
+ skinnedTangent = vec4(mat3(jm) * a_tangent.xyz, a_tangent.w);
}
else
{
skinnedPosition = a_position;
skinnedNormal = a_normal;
- })";
+ skinnedTangent = a_tangent;
+ }
+)";
const string vertMain_TBN_Nm = R"(
// Building the matrix Eye Space -> Tangent Space
// See the math behind at: http://www.terathon.com/code/tangent.html
- vec3 n = normalize(nMatrix * a_normal);
- vec3 t = normalize(nMatrix * a_tangent.xyz);
- vec3 b = cross(n, t) * a_tangent.w; // bitangent w. corrected handedness
+ vec3 n = normalize(nMatrix * ${localNormal});
+ vec3 t = normalize(nMatrix * ${localTangent}.xyz);
+ vec3 b = cross(n, t) * ${localTangent}.w; // bitangent w. corrected handedness
mat3 TBN = mat3(t,b,n);
// Transform vector to the eye into tangent space
@@ -1587,8 +1603,9 @@ void main()
The shader program gets a unique name with the following pattern:
- genCook-D00-N00-E00-O01-RM00-Sky-C4s
- | | | | | | | |
+ genCook-D00-N00-E00-O01-RM00-Sky-C4s-S
+ | | | | | | | | |
+ | | | | | | | | + Support for GPU skinning
| | | | | | | + Directional light w. 4 shadow cascades
| | | | | | + Ambient light from skybox
| | | | | + Roughness-metallic map with index 0 and uv 0
@@ -1823,6 +1840,9 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
bool uv1 = mat->usesUVIndex(1);
bool sky = mat->skybox() != nullptr;
+ // Check if the shader has to support skinning
+ bool skinning = mat->supportsGPUSkinning();
+
// Assemble vertex shader code
string vertCode;
vertCode += shaderHeader((int)lights->size());
@@ -1831,9 +1851,11 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
vertCode += vertInput_a_pn;
if (uv0) vertCode += vertInput_a_uv0;
if (Nm) vertCode += vertInput_a_tangent;
+ if (skinning) vertCode += vertInput_a_skinning;
vertCode += vertInput_u_matrices_all;
// if (sky) vertCode += vertInput_u_matrix_invMv;
if (Nm) vertCode += vertInput_u_lightNm;
+ if (skinning) vertCode += vertInput_u_skinning;
// Vertex shader outputs
vertCode += vertOutput_v_P_VS;
@@ -1845,6 +1867,7 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
// Vertex shader main loop
vertCode += vertMain_Begin;
+ if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
@@ -1854,7 +1877,9 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
vertCode += vertMain_EndAll;
// Vertex shader variables
- setVariable(vertCode, "localPosition", "a_position");
+ setVariable(vertCode, "localPosition", skinning ? "skinnedPosition" : "a_position");
+ setVariable(vertCode, "localNormal", skinning ? "skinnedNormal" : "a_normal");
+ if (Nm) setVariable(vertCode, "localTangent", skinning ? "skinnedTangent" : "a_tangent");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
@@ -1940,7 +1965,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
bool uv0 = mat->usesUVIndex(0);
bool uv1 = mat->usesUVIndex(1);
- // Check if we use GPU skinning
+ // Check if the shader has to support skinning
bool skinning = mat->supportsGPUSkinning();
// Assemble vertex shader code
@@ -1954,8 +1979,8 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (Nm) vertCode += vertInput_a_tangent;
if (skinning) vertCode += vertInput_a_skinning;
vertCode += vertInput_u_matrices_all;
- if (skinning) vertCode += vertInput_u_jointMatrices;
if (Nm) vertCode += vertInput_u_lightNm;
+ if (skinning) vertCode += vertInput_u_skinning;
// Vertex shader outputs
vertCode += vertOutput_v_P_VS;
@@ -1967,17 +1992,19 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
// Vertex shader main loop
vertCode += vertMain_Begin;
+ if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
if (uv0) vertCode += vertMain_v_uv0;
if (uv1) vertCode += vertMain_v_uv1;
- if (skinning) vertCode += vertMain_skinning;
if (Nm) vertCode += vertMain_TBN_Nm;
vertCode += vertMain_EndAll;
// Vertex shader variables
setVariable(vertCode, "localPosition", skinning ? "skinnedPosition" : "a_position");
+ setVariable(vertCode, "localNormal", skinning ? "skinnedNormal" : "a_normal");
+ if (Nm) setVariable(vertCode, "localTangent", skinning ? "skinnedTangent" : "a_tangent");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
@@ -2292,6 +2319,7 @@ void SLGLProgramGenerated::buildPerPixVideoBkgdSm(SLVLight* lights)
// Vertex shader variables
setVariable(vertCode, "localPosition", "a_position");
+ setVariable(vertCode, "localNormal", "a_normal");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
@@ -2682,7 +2710,7 @@ void SLGLProgramGenerated::addCodeToShader(SLGLShader* shader,
shader->file(generatedShaderPath + name);
}
//-----------------------------------------------------------------------------
-//! Builds unique program name that identifies shader program
+//! Sets a variable in the shader code.
/*! A variable is specified in templates like this: ${variableName}.
*/
void SLGLProgramGenerated::setVariable(std::string& code,
From d890b770445be6892d9a045a9ff77ebbfe0740bc Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Tue, 11 Jul 2023 14:42:35 +0200
Subject: [PATCH 014/108] Silenced some Warnings and typos
---
.../ch00_new_cpp_features/ch00_NewCppFeatures.cpp | 2 +-
modules/cv/source/CVTrackedFeatures.cpp | 2 +-
modules/math/CMakeLists.txt | 7 ++-----
modules/math/externals/Shoemake/EulerAngles.cpp | 6 ------
modules/sl/source/gl/SLGLTexture.h | 4 ++--
modules/sl/source/input/SLAssimpImporter.cpp | 4 ++--
6 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/apps/exercises/ch00_new_cpp_features/ch00_NewCppFeatures.cpp b/apps/exercises/ch00_new_cpp_features/ch00_NewCppFeatures.cpp
index d5d0cfd2..db3bf7d8 100644
--- a/apps/exercises/ch00_new_cpp_features/ch00_NewCppFeatures.cpp
+++ b/apps/exercises/ch00_new_cpp_features/ch00_NewCppFeatures.cpp
@@ -293,7 +293,7 @@ void new_rvalue_references()
const char* pb1 = b.c_str();
cout << "a before the move: " << std::hex << pa1 << ", " << pa1 << endl;
cout << "b before the move: " << std::hex << pb1 << ", " << pb1 << endl;
- b = move(a);
+ //b = move(a);
const char* pa2 = a.c_str();
const char* pb2 = b.c_str();
cout << "a after the move: " << std::hex << pa2 << ", " << pa2 << endl;
diff --git a/modules/cv/source/CVTrackedFeatures.cpp b/modules/cv/source/CVTrackedFeatures.cpp
index 329a9de1..6fb7ab1c 100644
--- a/modules/cv/source/CVTrackedFeatures.cpp
+++ b/modules/cv/source/CVTrackedFeatures.cpp
@@ -792,9 +792,9 @@ void CVTrackedFeatures::optimizeMatches()
#endif
}
-#if DO_FEATURE_BENCHMARKING
sum_reprojection_error += reprojectionError / _marker.keypoints3D.size();
+#if DO_FEATURE_BENCHMARKING
CVMat prevRmat, currRmat;
if (_prevFrame.foundPose)
{
diff --git a/modules/math/CMakeLists.txt b/modules/math/CMakeLists.txt
index 0bcf811c..168fbe0e 100644
--- a/modules/math/CMakeLists.txt
+++ b/modules/math/CMakeLists.txt
@@ -39,6 +39,8 @@ add_library(${target}
${headers}
${sources})
+add_definitions(-w)
+
add_library(${META_PROJECT_NAME}::${target}
ALIAS
${target}
@@ -46,11 +48,6 @@ add_library(${META_PROJECT_NAME}::${target}
enable_warnings(${target})
-set_target_properties(${target}
- PROPERTIES
- ${DEFAULT_PROJECT_OPTIONS}
- )
-
target_include_directories(${target}
PRIVATE
diff --git a/modules/math/externals/Shoemake/EulerAngles.cpp b/modules/math/externals/Shoemake/EulerAngles.cpp
index bde45d00..7ef1f215 100644
--- a/modules/math/externals/Shoemake/EulerAngles.cpp
+++ b/modules/math/externals/Shoemake/EulerAngles.cpp
@@ -12,8 +12,6 @@ EulerAngles Eul_(float ai, float aj, float ah, int order)
return (ea);
}
/* Construct quaternion from Euler angles (in radians). */
-#pragma warning(disable:4552)
-#pragma warning(disable:4244)
Quat Eul_ToQuat(EulerAngles ea)
{
Quat qu;
@@ -43,8 +41,6 @@ Quat Eul_ToQuat(EulerAngles ea)
}
/* Construct matrix from Euler angles (in radians). */
-#pragma warning(disable:4552)
-#pragma warning( disable:4244)
void Eul_ToHMatrix(EulerAngles ea, HMatrix M)
{ double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
int i,j,k,h,n,s,f;
@@ -68,8 +64,6 @@ void Eul_ToHMatrix(EulerAngles ea, HMatrix M)
}
/* Convert matrix to Euler angles (in radians). */
-#pragma warning(disable:4552)
-#pragma warning( disable:4244)
EulerAngles Eul_FromHMatrix(HMatrix M, int order)
{
EulerAngles ea;
diff --git a/modules/sl/source/gl/SLGLTexture.h b/modules/sl/source/gl/SLGLTexture.h
index a9542069..546af1e6 100644
--- a/modules/sl/source/gl/SLGLTexture.h
+++ b/modules/sl/source/gl/SLGLTexture.h
@@ -220,8 +220,8 @@ class SLGLTexture : public SLObject
SLuint depth() { return _depth; }
SLbyte uvIndex() { return _uvIndex; }
SLint bytesPerPixel() { return _bytesPerPixel; }
- SLint bytesOnGPU() { return _bytesOnGPU; }
- SLint bytesInFile() { return _bytesInFile; }
+ SLint bytesOnGPU() { return (SLint)_bytesOnGPU; }
+ SLint bytesInFile() { return (SLint)_bytesInFile; }
CVVImage& images() { return _images; }
SLenum target() const { return _target; }
SLuint texID() const { return _texID; }
diff --git a/modules/sl/source/input/SLAssimpImporter.cpp b/modules/sl/source/input/SLAssimpImporter.cpp
index a031840e..a05de729 100644
--- a/modules/sl/source/input/SLAssimpImporter.cpp
+++ b/modules/sl/source/input/SLAssimpImporter.cpp
@@ -917,7 +917,7 @@ SLGLTexture* SLAssimpImporter::loadTexture(SLAssetManager* assetMgr,
minificationFilter,
GL_LINEAR,
texType);
- texture->uvIndex(uvIndex);
+ texture->uvIndex((SLbyte)uvIndex);
// if texture images get deleted after build you can't do ray tracing
if (deleteTexImgAfterBuild)
@@ -1274,7 +1274,7 @@ SLAnimation* SLAssimpImporter::loadAnimation(SLAnimManager& animManager, aiAnima
// exit if we didn't load a skeleton but have animations for one
if (!_skinnedMeshes.empty())
- assert(_skeleton != nullptr && "The skeleton wasn't impoted correctly.");
+ assert(_skeleton != nullptr && "The skeleton wasn't imported correctly.");
// create the animation
SLAnimation* result;
From be175660b2261a281d0ee3f5452df5fd3cdd756f Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Wed, 20 Sep 2023 08:16:32 +0200
Subject: [PATCH 015/108] Update README.md
---
README.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 1bbb2f7c..8ceebd4e 100644
--- a/README.md
+++ b/README.md
@@ -3,12 +3,13 @@
[![Build Windows](https://github.com/cpvrlab/SLProject4/actions/workflows/build-x86_64-windows.yml/badge.svg)](https://github.com/cpvrlab/SLProject4/actions/workflows/build-x86_64-windows.yml)
[![Build macOS](https://github.com/cpvrlab/SLProject4/actions/workflows/build-x86_64-macos.yml/badge.svg)](https://github.com/cpvrlab/SLProject4/actions/workflows/build-x86_64-macos.yml)
[![Build Emscripten](https://github.com/cpvrlab/SLProject4/actions/workflows/build-wasm-emscripten.yml/badge.svg)](https://github.com/cpvrlab/SLProject4/actions/workflows/build-wasm-emscripten.yml)
+[![Build Online Docs](https://github.com/cpvrlab/SLProject4/actions/workflows/build-docs.yml/badge.svg)](https://github.com/cpvrlab/SLProject4/actions/workflows/build-docs.yml)
-SL stands for Scene Library. It is developed at the Berne University of Applied Sciences (BFH) in Switzerland and is used for student projects in the cpvrLab. The various applications show what you can learn in three semesters about 3D computer graphics in real time rendering and ray tracing. The framework is built in C++ and OpenGL ES and can be built for Windows, Linux, macOS (Intel & arm64), Android, Apple iOS and for WebAssembly enabled browsers. The framework can render alternatively with Ray Tracing and Path Tracing which provides in addition high quality transparencies, reflections and soft shadows. For a complete feature list see the [SLProject4 wiki](https://github.com/cpvrlab/SLProject4/wiki).
+SL stands for Scene Library. It is developed at the Berne University of Applied Sciences (BFH) in Switzerland and is used for student projects in the cpvrLab. The various applications show what you can learn in three semesters about 3D computer graphics in real-time rendering and ray tracing. The framework is built in C++ and OpenGL ES and can be built for Windows, Linux, macOS (Intel & arm64), Android, Apple iOS, and WebAssembly-enabled browsers. The framework can render alternatively with Ray Tracing and Path Tracing, which provides high-quality transparencies, reflections, and soft shadows. For a complete feature list see the [SLProject4 wiki](https://github.com/cpvrlab/SLProject4/wiki).
## How to get the SLProject4
-The SLProject4 is hosted at GitHub as a GIT repository.
+The SLProject4 is hosted on GitHub as a GIT repository.
[GIT](http://git-scm.com/) is a distributed versioning control system.
To clone SLProject4, use the following command:
@@ -18,7 +19,7 @@ cd
git clone https://github.com/cpvrlab/SLProject4.git
```
-For people with an aversion to the command line, a GIT GUI tool, such as the [GitHub Desktop Client](https://desktop.github.com), can be used. To get the latest additions to SLProject4, please checkout the develop branch:
+For people with an aversion to the command line, a GIT GUI tool, such as the [GitHub Desktop Client](https://desktop.github.com), can be used. To get the latest additions to SLProject4, please check the develop branch:
```
git checkout develop
From af8fd9293c218e4b13cd65a05010b0c9b454319c Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Fri, 29 Sep 2023 12:44:09 +0200
Subject: [PATCH 016/108] Update ch08_BlinnPhongLighting.frag
---
data/shaders/ch08_BlinnPhongLighting.frag | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/data/shaders/ch08_BlinnPhongLighting.frag b/data/shaders/ch08_BlinnPhongLighting.frag
index adf344ee..4cc50e5e 100644
--- a/data/shaders/ch08_BlinnPhongLighting.frag
+++ b/data/shaders/ch08_BlinnPhongLighting.frag
@@ -27,7 +27,7 @@ uniform vec4 u_globalAmbi; // Global ambient scene color
uniform vec4 u_matAmbi; // ambient color reflection coefficient (ka)
uniform vec4 u_matDiff; // diffuse color reflection coefficient (kd)
uniform vec4 u_matSpec; // specular color reflection coefficient (ks)
-uniform vec4 u_matEmis; // emissive color for self-shining materials
+uniform vec4 u_matEmis; // emissive color for self-shining materials (ke)
uniform float u_matShin; // shininess exponent
out vec4 o_fragColor; // output fragment color
From 406e36972ce0a6b2011b91df8f86bfac1c1e91aa Mon Sep 17 00:00:00 2001
From: luc
Date: Thu, 26 Oct 2023 18:29:01 +0200
Subject: [PATCH 017/108] Add support for draw instanced and use of a shared
VBO in multiples VAO
---
modules/sl/source/gl/SLGLVertexArray.cpp | 78 +++++++++++-
modules/sl/source/gl/SLGLVertexArray.h | 39 ++++--
modules/sl/source/gl/SLGLVertexBuffer.cpp | 141 +++++++++-------------
modules/sl/source/gl/SLGLVertexBuffer.h | 2 +-
modules/sl/source/mesh/SLMesh.cpp | 7 +-
modules/sl/source/mesh/SLMesh.h | 2 +-
6 files changed, 169 insertions(+), 100 deletions(-)
diff --git a/modules/sl/source/gl/SLGLVertexArray.cpp b/modules/sl/source/gl/SLGLVertexArray.cpp
index 9738308f..79e4d8c2 100644
--- a/modules/sl/source/gl/SLGLVertexArray.cpp
+++ b/modules/sl/source/gl/SLGLVertexArray.cpp
@@ -29,6 +29,7 @@ SLGLVertexArray::SLGLVertexArray()
_numVertices = 0;
_indexDataElements = nullptr;
_indexDataEdges = nullptr;
+ _externalVBOf = nullptr;
}
//-----------------------------------------------------------------------------
/*! Deletes the OpenGL objects for the vertex array and the vertex buffer.
@@ -86,6 +87,14 @@ void SLGLVertexArray::setAttrib(SLGLAttributeType type,
_VBOf.attribs().push_back(va);
}
+
+//-----------------------------------------------------------------------------
+ void SLGLVertexArray::setExternalVBO(SLGLVertexBuffer* vbo, SLuint divisor)
+ {
+ _externalVBOf = vbo;
+ _externalDivisor = divisor;
+ }
+
//-----------------------------------------------------------------------------
/*! Defines the vertex indices for the element drawing. Without indices vertex
array can only be drawn with SLGLVertexArray::drawArrayAs.
@@ -140,6 +149,7 @@ void SLGLVertexArray::updateAttrib(SLGLAttributeType type,
glBindVertexArray(0);
GET_GL_ERROR;
}
+
//-----------------------------------------------------------------------------
/*! Generates the OpenGL objects for the vertex array and the vertex buffer
object. If the input data is an interleaved array (all attribute data pointer
@@ -174,7 +184,8 @@ void SLGLVertexArray::updateAttrib(SLGLAttributeType type,
*/
void SLGLVertexArray::generate(SLuint numVertices,
SLGLBufferUsage usage,
- SLbool outputInterleaved)
+ SLbool outputInterleaved,
+ SLuint divisor)
{
assert(numVertices);
@@ -193,7 +204,15 @@ void SLGLVertexArray::generate(SLuint numVertices,
// Generate the vertex buffer object for float attributes
if (_VBOf.attribs().size())
+ {
_VBOf.generate(numVertices, usage, outputInterleaved);
+ _VBOf.bindAndEnableAttrib(divisor);
+ }
+
+ if (_externalVBOf != nullptr)
+ {
+ _externalVBOf->bindAndEnableAttrib(_externalDivisor);
+ }
/////////////////////////////////////////////////////////////////
// Create Element Array Buffer for Indices for elements and edges
@@ -240,7 +259,8 @@ void SLGLVertexArray::generate(SLuint numVertices,
/*! Same as generate but with transform feedback */
void SLGLVertexArray::generateTF(SLuint numVertices,
SLGLBufferUsage usage,
- SLbool outputInterleaved)
+ SLbool outputInterleaved,
+ SLuint divisor)
{
assert(numVertices);
@@ -262,7 +282,15 @@ void SLGLVertexArray::generateTF(SLuint numVertices,
// Generate the vertex buffer object for float attributes
if (_VBOf.attribs().size())
+ {
_VBOf.generate(numVertices, usage, outputInterleaved);
+ _VBOf.bindAndEnableAttrib(divisor);
+ }
+
+ if (_externalVBOf != nullptr)
+ {
+ _externalVBOf->bindAndEnableAttrib(_externalDivisor);
+ }
///////////////////////////////
// Bind transform feedback
@@ -430,6 +458,52 @@ void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
GET_GL_ERROR;
}
+
+void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
+ SLsizei countInstance,
+ SLuint numIndexes,
+ SLuint indexOffset
+ )
+{
+ assert(_numIndicesElements && _idVBOIndices && "No index VBO generated for VAO");
+
+ // From OpenGL 3.0 on we have the OpenGL Vertex Arrays
+ // Binding the VAO saves all the commands after the else (per draw call!)
+ glBindVertexArray(_vaoID);
+ GET_GL_ERROR;
+
+ // Do the draw call with indices
+ if (numIndexes == 0)
+ numIndexes = _numIndicesElements;
+
+ SLuint indexTypeSize = SLGLVertexBuffer::sizeOfType(_indexDataType);
+
+ ////////////////////////////////////////////////////////
+ glDrawElementsInstanced(primitiveType, (SLsizei)numIndexes ,_indexDataType, (void*)(size_t)(indexOffset * (SLuint)indexTypeSize), countInstance);
+ //glDrawElements(primitiveType, (SLsizei)numIndexes ,_indexDataType, (void*)(size_t)(indexOffset * (SLuint)indexTypeSize));
+ ////////////////////////////////////////////////////////
+
+ GET_GL_ERROR;
+ // Update statistics
+ totalDrawCalls++;
+ switch (primitiveType)
+ {
+ case PT_triangles:
+ totalPrimitivesRendered += (numIndexes / 3);
+ break;
+ case PT_lines:
+ totalPrimitivesRendered += (numIndexes / 2);
+ break;
+ case PT_points:
+ totalPrimitivesRendered += numIndexes;
+ break;
+ default: break;
+ }
+ glBindVertexArray(0);
+
+ GET_GL_ERROR;
+}
+
//-----------------------------------------------------------------------------
/*! Draws the hard edges with the specified color.
The VAO has no or one active index buffer. For drawArrayAs no indices are needed.
diff --git a/modules/sl/source/gl/SLGLVertexArray.h b/modules/sl/source/gl/SLGLVertexArray.h
index 4b902f54..b0c0459d 100644
--- a/modules/sl/source/gl/SLGLVertexArray.h
+++ b/modules/sl/source/gl/SLGLVertexArray.h
@@ -130,6 +130,9 @@ class SLGLVertexArray
indicesEdges && indicesEdges->size() ? (void*)&indicesEdges->operator[](0) : nullptr);
}
+ //! Attach a VBO that has been created outside of this VAO
+ void setExternalVBO(SLGLVertexBuffer *vbo, SLuint divisor = 0);
+
//! Updates a specific vertex attribute in the VBO
void updateAttrib(SLGLAttributeType type,
SLint elementSize,
@@ -158,12 +161,14 @@ class SLGLVertexArray
//! Generates the VA & VB objects for a NO. of vertices
void generate(SLuint numVertices,
SLGLBufferUsage usage = BU_static,
- SLbool outputInterleaved = true);
+ SLbool outputInterleaved = true,
+ SLuint divisor = 0);
//! Generates the VA & VB & TF objects
void generateTF(SLuint numVertices,
SLGLBufferUsage usage = BU_static,
- SLbool outputInterleaved = true);
+ SLbool outputInterleaved = true,
+ SLuint divisor = 0);
//! Begin transform feedback
void beginTF(SLuint tfoID);
@@ -181,6 +186,12 @@ class SLGLVertexArray
SLint firstVertex = 0,
SLsizei countVertices = 0);
+ //! Draws the VAO as an array with instance primitive type
+ void drawElementsInstanced(SLGLPrimitiveType primitiveType,
+ SLsizei countInstance = 0,
+ SLuint numIndexes = 0,
+ SLuint indexOffset = 0);
+
//! Draws the hard edges of the VAO with the edge indices
void drawEdges(SLCol4f color, SLfloat lineWidth = 1.0f);
@@ -188,22 +199,26 @@ class SLGLVertexArray
SLuint numVertices() const { return _numVertices; }
SLuint numIndicesElements() const { return _numIndicesElements; }
SLuint numIndicesEdges() const { return _numIndicesEdges; }
+ SLGLVertexBuffer* vbo() { return &_VBOf; }
// Some statistics
static SLuint totalDrawCalls; //! static total no. of draw calls
static SLuint totalPrimitivesRendered; //! static total no. of primitives rendered
protected:
- SLuint _vaoID; //! OpenGL id of vertex array object
- SLuint _tfoID; //! OpenGL id of transform feedback object
- SLuint _numVertices; //! NO. of vertices in array
- SLGLVertexBuffer _VBOf; //! Vertex buffer object for float attributes
- SLuint _idVBOIndices; //! OpenGL id of index vbo
- SLuint _numIndicesElements; //! NO. of vertex indices in array for triangles, lines or points
- void* _indexDataElements; //! Pointer to index data for elements
- SLuint _numIndicesEdges; //! NO. of vertex indices in array for hard edges
- void* _indexDataEdges; //! Pointer to index data for hard edges
- SLGLBufferType _indexDataType; //! index data type (ubyte, ushort, uint)
+ SLuint _instances; //! Number of instances of drawing
+ SLuint _vaoID; //! OpenGL id of vertex array object
+ SLuint _tfoID; //! OpenGL id of transform feedback object
+ SLuint _numVertices; //! NO. of vertices in array
+ SLGLVertexBuffer _VBOf; //! Vertex buffer object for float attributes
+ SLGLVertexBuffer* _externalVBOf; //! Vertex buffer object that has beed created outside of this VAO
+ SLuint _externalDivisor; //! VBO attrib divisor for the external VBO
+ SLuint _idVBOIndices; //! OpenGL id of index vbo
+ SLuint _numIndicesElements; //! NO. of vertex indices in array for triangles, lines or points
+ void* _indexDataElements; //! Pointer to index data for elements
+ SLuint _numIndicesEdges; //! NO. of vertex indices in array for hard edges
+ void* _indexDataEdges; //! Pointer to index data for hard edges
+ SLGLBufferType _indexDataType; //! index data type (ubyte, ushort, uint)
};
//-----------------------------------------------------------------------------
diff --git a/modules/sl/source/gl/SLGLVertexBuffer.cpp b/modules/sl/source/gl/SLGLVertexBuffer.cpp
index 935f776d..d5bae373 100644
--- a/modules/sl/source/gl/SLGLVertexBuffer.cpp
+++ b/modules/sl/source/gl/SLGLVertexBuffer.cpp
@@ -195,33 +195,6 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
if (inputIsInterleaved)
{
- for (auto a : _attribs)
- {
- if (a.location > -1)
- { // Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
- {
- glVertexAttribIPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- (SLint)_strideBytes,
- (void*)(size_t)a.offsetBytes);
- }
- else
- {
- glVertexAttribPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- GL_FALSE,
- (SLint)_strideBytes,
- (void*)(size_t)a.offsetBytes);
- }
-
- // Tell the attribute to be an array attribute instead of a state variable
- glEnableVertexAttribArray((SLuint)a.location);
- }
- }
-
// generate the interleaved VBO buffer on the GPU
glBufferData(GL_ARRAY_BUFFER, _sizeBytes, _attribs[0].dataPointer, _usage);
}
@@ -244,30 +217,6 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
for (SLuint b = 0; b < elementSizeBytes; ++b)
data[iDst + b] = ((SLuchar*)a.dataPointer)[iSrc + b];
}
-
- if (a.location > -1)
- { // Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
- {
- glVertexAttribIPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- (SLint)_strideBytes,
- (void*)(size_t)a.offsetBytes);
- }
- else
- {
- glVertexAttribPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- GL_FALSE,
- (SLint)_strideBytes,
- (void*)(size_t)a.offsetBytes);
- }
-
- // Tell the attribute to be an array attribute instead of a state variable
- glEnableVertexAttribArray((SLuint)a.location);
- }
}
// generate the interleaved VBO buffer on the GPU
@@ -287,28 +236,6 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
a.offsetBytes,
a.bufferSizeBytes,
a.dataPointer);
-
- // Sets the vertex attribute data pointer to its corresponding GLSL variable
- if (a.dataType == BT_uint)
- {
- glVertexAttribIPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- 0,
- (void*)(size_t)a.offsetBytes);
- }
- else
- {
- glVertexAttribPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- GL_FALSE,
- 0,
- (void*)(size_t)a.offsetBytes);
- }
-
- // Tell the attribute to be an array attribute instead of a state variable
- glEnableVertexAttribArray((SLuint)a.location);
}
}
}
@@ -318,34 +245,84 @@ void SLGLVertexBuffer::generate(SLuint numVertices,
totalBufferSize += _sizeBytes;
GET_GL_ERROR;
}
+
//-----------------------------------------------------------------------------
/*! This method is only used by SLGLVertexArray drawing methods for OpenGL
contexts prior to 3.0 where vertex array objects did not exist. This is the
additional overhead that had to be done per draw call.
*/
-void SLGLVertexBuffer::bindAndEnableAttrib()
+void SLGLVertexBuffer::bindAndEnableAttrib(SLuint divisor) const
{
- if (_attribs.size())
+ //////////////////////////////////////
+ // Associate VBO to Attribute location
+ //////////////////////////////////////
+
+ glBindBuffer(GL_ARRAY_BUFFER, _id);
+
+ if (_outputInterleaved) // Copy attribute data interleaved
{
- glBindBuffer(GL_ARRAY_BUFFER, _id);
+ for (auto a : _attribs)
+ {
+ if (a.location > -1)
+ { // Sets the vertex attribute data pointer to its corresponding GLSL variable
+ if (a.dataType == BT_uint)
+ {
+ glVertexAttribIPointer((SLuint)a.location,
+ a.elementSize,
+ a.dataType,
+ (SLint)_strideBytes,
+ (void*)(size_t)a.offsetBytes);
+ }
+ else
+ {
+ glVertexAttribPointer((SLuint)a.location,
+ a.elementSize,
+ a.dataType,
+ GL_FALSE,
+ (SLint)_strideBytes,
+ (void*)(size_t)a.offsetBytes);
+ }
+ // Tell the attribute to be an array attribute instead of a state variable
+ glEnableVertexAttribArray((SLuint)a.location);
+ if (divisor > 0)
+ glVertexAttribDivisor((SLuint)a.location, divisor);
+ }
+ }
+ }
+ else // copy attributes buffers sequentially
+ {
for (auto a : _attribs)
{
if (a.location > -1)
{
// Sets the vertex attribute data pointer to its corresponding GLSL variable
- glVertexAttribPointer((SLuint)a.location,
- a.elementSize,
- a.dataType,
- GL_FALSE,
- (SLsizei)_strideBytes,
- (void*)(size_t)a.offsetBytes);
+ if (a.dataType == BT_uint)
+ {
+ glVertexAttribIPointer((SLuint)a.location,
+ a.elementSize,
+ a.dataType,
+ 0,
+ (void*)(size_t)a.offsetBytes);
+ }
+ else
+ {
+ glVertexAttribPointer((SLuint)a.location,
+ a.elementSize,
+ a.dataType,
+ GL_FALSE,
+ 0,
+ (void*)(size_t)a.offsetBytes);
+ }
// Tell the attribute to be an array attribute instead of a state variable
glEnableVertexAttribArray((SLuint)a.location);
+ if (divisor > 0)
+ glVertexAttribDivisor((SLuint)a.location, divisor);
}
}
}
+ GET_GL_ERROR;
}
//-----------------------------------------------------------------------------
/*! This method is only used by SLGLVertexArray drawing methods for OpenGL
diff --git a/modules/sl/source/gl/SLGLVertexBuffer.h b/modules/sl/source/gl/SLGLVertexBuffer.h
index 7d6ec776..b6425fa3 100644
--- a/modules/sl/source/gl/SLGLVertexBuffer.h
+++ b/modules/sl/source/gl/SLGLVertexBuffer.h
@@ -87,7 +87,7 @@ class SLGLVertexBuffer
SLbool outputInterleaved = true);
//! Binds & enables the vertex attribute for OpenGL < 3.0
- void bindAndEnableAttrib();
+ void bindAndEnableAttrib(SLuint divisor = 0) const;
//! disables the vertex attribute for OpenGL < 3.0
void disableAttrib();
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index e2d0be05..c9c0b0ce 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -379,7 +379,7 @@ Optionally you can draw the normals and/or the uniform grid voxels.
Please view also the full process of rendering one frame
*/
-void SLMesh::draw(SLSceneView* sv, SLNode* node)
+void SLMesh::draw(SLSceneView* sv, SLNode* node, SLuint instances)
{
SLGLState* stateGL = SLGLState::instance();
@@ -469,7 +469,10 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node)
_vao.drawArrayAs(PT_points);
else
{
- _vao.drawElementsAs(primitiveType);
+ if (instances > 1)
+ _vao.drawElementsInstanced(primitiveType, instances);
+ else
+ _vao.drawElementsAs(primitiveType);
if ((sv->drawBit(SL_DB_WITHEDGES) || node->drawBit(SL_DB_WITHEDGES)) &&
(!IE32.empty() || !IE16.empty()))
diff --git a/modules/sl/source/mesh/SLMesh.h b/modules/sl/source/mesh/SLMesh.h
index ff475e3f..957f2ad4 100644
--- a/modules/sl/source/mesh/SLMesh.h
+++ b/modules/sl/source/mesh/SLMesh.h
@@ -130,7 +130,7 @@ class SLMesh : public SLObject
~SLMesh() override;
virtual void init(SLNode* node);
- virtual void draw(SLSceneView* sv, SLNode* node);
+ virtual void draw(SLSceneView* sv, SLNode* node, SLuint intances = 0);
void drawIntoDepthBuffer(SLSceneView* sv,
SLNode* node,
SLMaterial* depthMat);
From dd1e89b441b6ec9863c6c85306302d47e38aba22 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 30 Oct 2023 16:51:39 +0100
Subject: [PATCH 018/108] [WebGPU] Set up CMake to download wgpu
---
apps/CMakeLists.txt | 6 ++++-
apps/webgpu/CMakeLists.txt | 50 ++++++++++++++++++++++++++++++++++++++
apps/webgpu/main.cpp | 18 ++++++++++++++
3 files changed, 73 insertions(+), 1 deletion(-)
create mode 100644 apps/webgpu/CMakeLists.txt
create mode 100644 apps/webgpu/main.cpp
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 73765b36..d4889f7a 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -9,4 +9,8 @@ else()
add_subdirectory(app_demo_imgui)
add_subdirectory(app_demo_node)
add_subdirectory(app_demo_slproject)
-endif()
+
+ if (SL_BUILD_WEBGPU_DEMO)
+ add_subdirectory(webgpu)
+ endif ()
+endif()
\ No newline at end of file
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
new file mode 100644
index 00000000..9b74fd34
--- /dev/null
+++ b/apps/webgpu/CMakeLists.txt
@@ -0,0 +1,50 @@
+if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
+ set(WGPU_OS "windows")
+elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
+ set(WGPU_OS "macos")
+elseif (SYSTEM_NAME_UPPER MATCHES "LINUX")
+ set(WGPU_OS "linux")
+else ()
+ message(FATAL_ERROR "[WebGPU] System '${SYSTEM_NAME_UPPER}' is not supported")
+endif ()
+
+if (CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
+ set(WGPU_ARCH "x86_64")
+elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
+ set(WGPU_ARCH "arm64")
+else ()
+ message(FATAL_ERROR "[WebGPU] Architecture '${CMAKE_SYSTEM_PROCESSOR}' is not supported")
+endif ()
+
+set(WGPU_VERSION "v0.18.0.1")
+set(WGPU_DIR "${SL_PROJECT_ROOT}/externals/prebuilt/wgpu_${WGPU_VERSION}")
+set(WGPU_ZIP "wgpu-${WGPU_OS}-${WGPU_ARCH}-release.zip")
+
+if (NOT EXISTS "${WGPU_DIR}")
+ set(BASE_URL "https://github.com/gfx-rs/wgpu-native/releases/download")
+ set(DOWNLOAD_URL "${BASE_URL}/${WGPU_VERSION}/${WGPU_ZIP}")
+
+ message(STATUS "[WebGPU] Downloading ${WGPU_ZIP}...")
+ file(DOWNLOAD "${DOWNLOAD_URL}" "${WGPU_DIR}/${WGPU_ZIP}")
+ message(STATUS "[WebGPU] Download complete")
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf "${WGPU_ZIP}" WORKING_DIRECTORY "${WGPU_DIR}")
+ message(STATUS "[WebGPU] Files extracted")
+
+ file(REMOVE "${WGPU_DIR}/commit-sha" "${WGPU_DIR}/${WGPU_ZIP}")
+ message(STATUS "[WebGPU] Directory cleaned up")
+else ()
+ message(STATUS "[WebGPU] Directory existing")
+endif ()
+
+add_library(wgpu STATIC IMPORTED)
+set_target_properties(wgpu PROPERTIES
+ IMPORTED_LOCATION "${WGPU_DIR}/wgpu_native.lib"
+ INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
+
+if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
+ target_link_libraries(wgpu INTERFACE "ws2_32" "userenv" "advapi32" "bcrypt" "d3dcompiler" "ntdll" "opengl32")
+endif ()
+
+add_executable(webgpu-demo main.cpp)
+target_link_libraries(webgpu-demo wgpu)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
new file mode 100644
index 00000000..c014c1dc
--- /dev/null
+++ b/apps/webgpu/main.cpp
@@ -0,0 +1,18 @@
+#include
+
+#include
+
+int main(int argc, const char* argv[]) {
+ WGPUInstance instance = wgpuCreateInstance(nullptr);
+ if (instance) {
+ std::cout << "[WebGPU] Instance created" << std::endl;
+ } else {
+ std::cerr << "[WebGPU] Failed to create instance" << std::endl;
+ return 1;
+ }
+
+ wgpuInstanceRelease(instance);
+ std::cerr << "[WebGPU] Resources released" << std::endl;
+
+ return 0;
+}
\ No newline at end of file
From 50b2f28340db2020c6cb1013132a817bb0d6f6f3 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 2 Nov 2023 17:16:02 +0100
Subject: [PATCH 019/108] [WebGPU] Add triangle demo for Windows
---
CMakeLists.txt | 2 +
apps/webgpu/CMakeLists.txt | 2 +-
apps/webgpu/main.cpp | 318 ++++++++++++++++++++++++++++++++++++-
3 files changed, 314 insertions(+), 8 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2018324f..f03e78da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,7 @@ option(SL_BUILD_WAI "Specifies if the WAI library should be built" ON)
option(SL_BUILD_APPS "Specifies if sample apps should be built" ON)
option(SL_BUILD_EXERCISES "Specifies if exercise apps should be built" ON)
option(SL_BUILD_VULKAN_APPS "Specifies if vulkan apps should be built" OFF)
+option(SL_BUILD_WEBGPU_DEMO "Specifies if WebGPU demo should be built" ON)
option(SL_BUILD_WITH_OPTIX "Specifies if Optix renderer should be built" OFF)
option(SL_BUILD_WITH_KTX "Specifies if Kronos Texture library (ktx) should be used" ON)
option(SL_BUILD_WITH_OPENSSL "Specifies if OpenSSL should be used" ON)
@@ -71,6 +72,7 @@ message(STATUS "SL_BUILD_WAI: ${SL_BUILD_WAI}")
message(STATUS "SL_BUILD_APPS: ${SL_BUILD_APPS}")
message(STATUS "SL_BUILD_EXERCISES: ${SL_BUILD_EXERCISES}")
message(STATUS "SL_BUILD_VULKAN_APPS: ${SL_BUILD_VULKAN_APPS}")
+message(STATUS "SL_BUILD_WEBGPU_DEMO: ${SL_BUILD_WEBGPU_DEMO}")
message(STATUS "SL_BUILD_WITH_OPTIX: ${SL_BUILD_WITH_OPTIX}")
message(STATUS "SL_BUILD_WITH_KTX: ${SL_BUILD_WITH_KTX}")
message(STATUS "SL_BUILD_WITH_OPENSSL: ${SL_BUILD_WITH_OPENSSL}")
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 9b74fd34..97bfde63 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -47,4 +47,4 @@ if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
endif ()
add_executable(webgpu-demo main.cpp)
-target_link_libraries(webgpu-demo wgpu)
+target_link_libraries(webgpu-demo PRIVATE wgpu glfw3dll)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index c014c1dc..b23d48cb 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -1,18 +1,322 @@
+#if defined(_WIN32)
+# define SYSTEM_WINDOWS
+# define GLFW_EXPOSE_NATIVE_WIN32
+# define WIN32_LEAN_AND_MEAN
+# include
+#elif defined(__linux__)
+# define SYSTEM_LINUX
+# define GLFW_EXPOSE_NATIVE_X11
+#elif defined(__APPLE__)
+# define SYSTEM_DARWIN
+# define GLFW_EXPOSE_NATIVE_COCOA
+#endif
+
#include
+#include
+#include
#include
+#include
+
+#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
+
+#define WEBGPU_DEMO_CHECK(condition, errorMsg) \
+ if (!(condition)) \
+ { \
+ std::cerr << (errorMsg) << std::endl; \
+ std::exit(1); \
+ }
+
+void handleAdapterRequest(WGPURequestAdapterStatus status,
+ WGPUAdapter adapter,
+ char const* message,
+ void* userdata)
+{
+ WEBGPU_DEMO_CHECK(status == WGPURequestAdapterStatus_Success,
+ "[WebGPU] Failed to acquire adapter: " + std::string(message));
+ WEBGPU_DEMO_LOG("[WebGPU] Adapter acquired");
+
+ WGPUAdapter* outAdapter = (WGPUAdapter*)userdata;
+ *outAdapter = adapter;
+}
+
+void handleDeviceRequest(WGPURequestDeviceStatus status,
+ WGPUDevice device,
+ char const* message,
+ void* userdata)
+{
+ WEBGPU_DEMO_CHECK(status == WGPURequestDeviceStatus_Success,
+ "[WebGPU] Failed to acquire device: " + std::string(message));
+ WEBGPU_DEMO_LOG("[WebGPU] Device acquired");
+
+ WGPUDevice* outDevice = (WGPUDevice*)userdata;
+ *outDevice = device;
+}
+
+int main(int argc, const char* argv[])
+{
+ // === Initialize GLFW ===
+
+ WEBGPU_DEMO_CHECK(glfwInit(), "[GLFW] Failed to initialize");
+ WEBGPU_DEMO_LOG("[GLFW] Initialized");
+
+ // === Create the GLFW window ===
+
+ // Prevent GLFW from creating an OpenGL context as the underlying graphics API probably won't be OpenGL.
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+
+ // Create a non-resizable window as we currently don't recreate surfaces when the window size changes.
+ glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+
+ GLFWwindow* window = glfwCreateWindow(1280, 720, "WebGPU Demo", nullptr, nullptr);
+ WEBGPU_DEMO_CHECK(window, "[GLFW] Window created");
+
+ // === Create a WebGPU instance ===
+ // The instance is the root interface to WebGPU through which we create all other WebGPU resources.
-int main(int argc, const char* argv[]) {
WGPUInstance instance = wgpuCreateInstance(nullptr);
- if (instance) {
- std::cout << "[WebGPU] Instance created" << std::endl;
- } else {
- std::cerr << "[WebGPU] Failed to create instance" << std::endl;
- return 1;
+ WEBGPU_DEMO_CHECK(instance, "[WebGPU] Failed to create instance");
+ WEBGPU_DEMO_LOG("[WebGPU] Instance created");
+
+ // === Acquire a WebGPU adapter ===
+ // An adapter provides information about the capabilities of the GPU.
+
+ WGPURequestAdapterOptions adapterOptions = {};
+
+ WGPUAdapter adapter;
+ wgpuInstanceRequestAdapter(instance, &adapterOptions, handleAdapterRequest, &adapter);
+
+ // === Acquire a WebGPU device ===
+ // A device provides access to a GPU and is created from an adapter.
+
+ WGPUDeviceDescriptor deviceDesc = {};
+ deviceDesc.label = "Demo Device";
+ deviceDesc.defaultQueue.label = "Demo Queue";
+
+ WGPUDevice device;
+ wgpuAdapterRequestDevice(adapter, &deviceDesc, handleDeviceRequest, &device);
+
+ // === Acquire a WebGPU queue ===
+ // The queue is where the commands for the GPU are submitted to.
+
+ WGPUQueue queue = wgpuDeviceGetQueue(device);
+ WEBGPU_DEMO_CHECK(queue, "[WebGPU] Failed to acquire queue");
+ WEBGPU_DEMO_LOG("[WebGPU] Queue acquired");
+
+ // === Create a WebGPU surface ===
+ // The surface is where our rendered images will be presented to.
+ // It is created from window handles on most platforms and from a canvas in the browser.
+
+#ifdef SYSTEM_WINDOWS
+ WGPUSurfaceDescriptorFromWindowsHWND nativeSurfaceDesc = {};
+ nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
+ nativeSurfaceDesc.hinstance = GetModuleHandle(nullptr);
+ nativeSurfaceDesc.hwnd = glfwGetWin32Window(window);
+#endif
+
+ WGPUSurfaceDescriptor surfaceDesc = {};
+ surfaceDesc.label = "Demo Surface";
+ surfaceDesc.nextInChain = (const WGPUChainedStruct*)&nativeSurfaceDesc;
+
+ WGPUSurface surface = wgpuInstanceCreateSurface(instance, &surfaceDesc);
+ WEBGPU_DEMO_CHECK(surface, "[WebGPU] Failed to create surface");
+ WEBGPU_DEMO_LOG("[WebGPU] Surface created");
+
+ // === Configure the surface ===
+ // The surface needs to be configured before images can be presented.
+
+ // Query the surface capabilities from the adapter.
+ WGPUSurfaceCapabilities surfaceCapabilities;
+ wgpuSurfaceGetCapabilities(surface, adapter, &surfaceCapabilities);
+
+ // Get the window size from the GLFW window.
+ int surfaceWidth;
+ int surfaceHeight;
+ glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
+
+ WGPUSurfaceConfiguration surfaceConfig = {};
+ surfaceConfig.device = device;
+ surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
+ surfaceConfig.format = surfaceCapabilities.formats[0];
+ surfaceConfig.presentMode = WGPUPresentMode_Fifo;
+ surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
+ surfaceConfig.width = surfaceWidth;
+ surfaceConfig.height = surfaceHeight;
+ wgpuSurfaceConfigure(surface, &surfaceConfig);
+ WEBGPU_DEMO_LOG("[WebGPU] Surface configured");
+
+ // === Create the shader module ===
+ // Create a shader module for use in our render pipeline.
+ // Shaders are written in a WebGPU-specific language called WGSL (WebGPU shader language).
+ // Shader modules can be used in multiple pipeline stages by specifying different entry points.
+
+ const char* shaderSource = R"(
+ @vertex
+ fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f {
+ if (in_vertex_index == 0u) {
+ return vec4f(-0.5, -0.5, 0.0, 1.0);
+ } else if (in_vertex_index == 1u) {
+ return vec4f(0.5, -0.5, 0.0, 1.0);
+ } else {
+ return vec4f(0.0, 0.5, 0.0, 1.0);
+ }
+ }
+
+ @fragment
+ fn fs_main() -> @location(0) vec4f {
+ return vec4f(0.2, 0.2, 1.0, 1.0);
+ }
+ )";
+
+ WGPUShaderModuleWGSLDescriptor shaderModuleWGSLDesc = {};
+ shaderModuleWGSLDesc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor;
+ shaderModuleWGSLDesc.code = shaderSource;
+
+ WGPUShaderModuleDescriptor shaderModuleDesc = {};
+ shaderModuleDesc.label = "Hello Triangle Shader";
+ shaderModuleDesc.nextInChain = (const WGPUChainedStruct*)&shaderModuleWGSLDesc;
+
+ WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
+ WEBGPU_DEMO_CHECK(shaderModule, "[WebGPU] Failed to create shader module");
+ WEBGPU_DEMO_LOG("[WebGPU] Shader module created");
+
+ // === Create the WebGPU render pipeline ===
+ // The render pipeline specifies the configuration for the fixed-function stages as well as
+ // the shaders for the programmable stages of the hardware pipeline.
+
+ // Configuration for the vertex shader stage
+ WGPUVertexState vertexState = {};
+ vertexState.module = shaderModule;
+ vertexState.entryPoint = "vs_main";
+
+ // Configuration for the primitive assembly and rasterization stages
+ WGPUPrimitiveState primitiveState = {};
+ primitiveState.topology = WGPUPrimitiveTopology_TriangleList;
+ primitiveState.stripIndexFormat = WGPUIndexFormat_Undefined;
+ primitiveState.frontFace = WGPUFrontFace_CCW;
+ primitiveState.cullMode = WGPUCullMode_None;
+
+ // Configuration for multisampling
+ WGPUMultisampleState multisampleState = {};
+ multisampleState.count = 1;
+ multisampleState.mask = WGPUColorWriteMask_All;
+
+ // Configuration for the fragment shader stage
+ WGPUColorTargetState colorTargetState = {};
+ colorTargetState.format = surfaceCapabilities.formats[0];
+ colorTargetState.writeMask = WGPUColorWriteMask_All;
+ WGPUFragmentState fragmentState = {};
+ fragmentState.module = shaderModule;
+ fragmentState.entryPoint = "fs_main";
+ fragmentState.targetCount = 1;
+ fragmentState.targets = &colorTargetState;
+
+ // Configuration for the entire pipeline
+ WGPURenderPipelineDescriptor pipelineDesc = {};
+ pipelineDesc.label = "Hello Triangle Pipeline";
+ pipelineDesc.vertex = vertexState;
+ pipelineDesc.primitive = primitiveState;
+ pipelineDesc.multisample = multisampleState;
+ pipelineDesc.fragment = &fragmentState;
+
+ WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device, &pipelineDesc);
+ WEBGPU_DEMO_CHECK(pipeline, "[WebGPU] Failed to create render pipeline");
+ WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
+
+ // === Render loop ===
+
+ while (!glfwWindowShouldClose(window))
+ {
+ // === Create a WebGPU texture view ===
+ // The texture view is where we render our image into.
+
+ // Get a texture from the surface to render into.
+ WGPUSurfaceTexture surfaceTexture;
+ wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
+ WEBGPU_DEMO_CHECK(surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_Success, "[WebGPU] Failed to acquire current surface texture");
+
+ // Create a view into the texture to specify where and how to modify the texture.
+ WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
+
+ // === Create a WebGPU command encoder ===
+ // The encoder encodes the commands for the GPU into a command buffer.
+
+ WGPUCommandEncoderDescriptor cmdEncoderDesc = {};
+ cmdEncoderDesc.label = " Hello Triangle Command Encoder";
+
+ WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(device, &cmdEncoderDesc);
+ WEBGPU_DEMO_CHECK(cmdEncoder, "[WebGPU] Failed to create command encoder");
+
+ // === Create a WebGPU render pass ===
+ // The render pass specifies what attachments to use while rendering.
+ // A color attachment specifies what view to render into and what to do with the texture before and after
+ // rendering. We clear the texture before rendering and store the results after rendering.
+
+ WGPURenderPassColorAttachment colorAttachment = {};
+ colorAttachment.view = view;
+ colorAttachment.loadOp = WGPULoadOp_Clear;
+ colorAttachment.storeOp = WGPUStoreOp_Store;
+ colorAttachment.clearValue.r = 0.3;
+ colorAttachment.clearValue.g = 0.0;
+ colorAttachment.clearValue.b = 0.2;
+ colorAttachment.clearValue.a = 1.0;
+
+ WGPURenderPassDescriptor renderPassDesc = {};
+ renderPassDesc.label = "Hello Triangle Render Pass";
+ renderPassDesc.colorAttachmentCount = 1;
+ renderPassDesc.colorAttachments = &colorAttachment;
+
+ // === Encode the commands ===
+ // The commands to begin a render pass, bind a pipeline, draw the triangle and end the render pass
+ // are encoded into a buffer.
+
+ WGPURenderPassEncoder renderPassEncoder = wgpuCommandEncoderBeginRenderPass(cmdEncoder, &renderPassDesc);
+ wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipeline);
+ wgpuRenderPassEncoderDraw(renderPassEncoder, 3, 1, 0, 0);
+ wgpuRenderPassEncoderEnd(renderPassEncoder);
+
+ // === Get the command buffer ===
+ // The command encoder is finished to get the commands for the GPU to execute in a command buffer.
+
+ WGPUCommandBufferDescriptor cmdBufferDesc = {};
+ cmdBufferDesc.label = "Hello Triangle Command Buffer";
+
+ WGPUCommandBuffer cmdBuffer = wgpuCommandEncoderFinish(cmdEncoder, &cmdBufferDesc);
+
+ // === Submit the command buffer to the GPU ===
+ // The work for the GPU is submitted through the queue and executed.
+ wgpuQueueSubmit(queue, 1, &cmdBuffer);
+
+ // === Present the surface ===
+ // This presents our rendered texture to the screen.
+ wgpuSurfacePresent(surface);
+
+ // === Clean up resources ===
+ wgpuCommandBufferRelease(cmdBuffer);
+ wgpuRenderPassEncoderRelease(renderPassEncoder);
+ wgpuCommandEncoderRelease(cmdEncoder);
+ wgpuTextureViewRelease(view);
+ wgpuTextureRelease(surfaceTexture.texture);
+
+ glfwPollEvents();
}
+ // === Release all WebGPU resources ===
+
+ wgpuRenderPipelineRelease(pipeline);
+ wgpuShaderModuleRelease(shaderModule);
+ wgpuSurfaceRelease(surface);
+ wgpuQueueRelease(queue);
+ wgpuDeviceRelease(device);
+ wgpuAdapterRelease(adapter);
wgpuInstanceRelease(instance);
- std::cerr << "[WebGPU] Resources released" << std::endl;
+ WEBGPU_DEMO_LOG("[WebGPU] Resources released");
+
+ // === Destroy the window and terminate GLFW ===
+
+ glfwDestroyWindow(window);
+ glfwTerminate();
+ WEBGPU_DEMO_LOG("[GLFW] Window closed and terminated");
return 0;
}
\ No newline at end of file
From 7618a51eb6b31906f245bb98927900eef2414be6 Mon Sep 17 00:00:00 2001
From: luc
Date: Thu, 2 Nov 2023 17:22:42 +0100
Subject: [PATCH 020/108] working version without finition
---
modules/sl/source/SLMaterial.cpp | 8 +-
modules/sl/source/SLMaterial.h | 2 +-
modules/sl/source/gl/SLGLProgramGenerated.cpp | 285 ++++++++++++++++--
modules/sl/source/gl/SLGLProgramGenerated.h | 13 +-
modules/sl/source/mesh/SLParticleSystem.cpp | 80 ++++-
modules/sl/source/mesh/SLParticleSystem.h | 6 +-
6 files changed, 360 insertions(+), 34 deletions(-)
diff --git a/modules/sl/source/SLMaterial.cpp b/modules/sl/source/SLMaterial.cpp
index 25719855..d26365a3 100644
--- a/modules/sl/source/SLMaterial.cpp
+++ b/modules/sl/source/SLMaterial.cpp
@@ -377,7 +377,7 @@ SLMaterial::~SLMaterial()
If this material has not yet a shader program assigned (SLMaterial::_program)
a suitable program will be generated with an instance of SLGLProgramGenerated.
*/
-void SLMaterial::generateProgramPS()
+void SLMaterial::generateProgramPS(bool renderInstanced)
{
// If no shader program is attached add a generated shader program
// A 3D object can be stored without material or shader program information.
@@ -395,11 +395,15 @@ void SLMaterial::generateProgramPS()
// If the program was not found by name generate a new one
if (!_program)
{
+ std::string geom = "";
+ if (!renderInstanced)
+ geom = "Geom";
+
_program = new SLGLProgramGenerated(_assetManager,
programNameDraw,
this,
true,
- "Geom");
+ geom);
}
}
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index 60dbbd97..983f2ff5 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -108,7 +108,7 @@ class SLMaterial : public SLObject
SLGLProgram* program);
~SLMaterial() override;
- void generateProgramPS();
+ void generateProgramPS(bool renderInstanced = false);
void activate(SLCamera* cam,
SLVLight* lights,
SLSkybox* skybox = nullptr);
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index bdb9aabf..9aee3ca3 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -44,6 +44,8 @@ const string vertInput_PS_a_texNum = R"(
layout (location = 6) in uint a_texNum; // Particle rotation attribute)";
const string vertInput_PS_a_initP = R"(
layout (location = 7) in vec3 a_initialPosition;// Particle initial position attribute)";
+const string vertInput_PS_a_positionP = R"(
+layout (location = 8) in vec3 a_positionP; // Particle position attribute)";
const string vertInput_a_uv0 = R"(
layout (location = 2) in vec2 a_uv0; // Vertex tex.coord. 1 for diffuse color)";
const string vertInput_a_uv1 = R"(
@@ -103,7 +105,6 @@ uniform int u_condFB; // Condition to update texNum)";
//-----------------------------------------------------------------------------
const string vertOutput_v_P_VS = R"(
-
out vec3 v_P_VS; // Point of illumination in view space (VS))";
const string vertOutput_v_P_WS = R"(
out vec3 v_P_WS; // Point of illumination in world space (WS))";
@@ -146,6 +147,46 @@ const string vertOutput_PS_struct_texNum = R"(
uint texNum; // Num of texture in flipbook)";
const string vertOutput_PS_struct_End = R"(
} vert; )";
+
+const string vertOutput_PS_instanced_texNum = R"(
+out uint texNum; // Num of texture in flipbook)";
+const string vertOutput_PS_instanced_transparency = R"(
+out float transparency; // transparency of a particle )";
+
+const string fragInput_PS_instanced_transparency = R"(
+in float transparency; // transparency of a particle )";
+const string fragInput_PS_instanced_texNum = R"(
+in uint texNum; // Num of texture in flipbook)";
+
+const string fragMain_PS_v_c = R"(
+ vec4 color = u_color; // Particle color)";
+const string fragMain_PS_v_doColorOverLT = R"(
+ vec4 color = vec4(vert[0].color, 1.0); // Particle color)";
+const string fragMain_PS_v_withoutColor = R"(
+ vec4 color = vec4( 0.0, 0.0, 0.0, 1.0); // Particle color)";
+const string fragMain_PS_instanced_c = R"(
+ vec4 color = u_color; // Particle color
+ color.w *= transparency; // Apply transparency
+ )";
+
+const string vertInput_u_matrix_p = R"(
+uniform mat4 u_pMatrix; // Projection matrix)";
+const string vertInput_u_matrix_vertBillboard = R"(
+uniform mat4 u_vYawPMatrix; // Projection matrix)";
+const string fragInput_PS_u_c = R"(
+uniform vec4 u_color; // Particle color)";
+const string vertInput_PS_u_ScaRa = R"(
+uniform float u_scale; // Particle scale
+uniform float u_radiusW; // Particle width radius)
+uniform float u_radiusH; // Particle height radius)";
+//-----------------------------------------------------------------------------
+
+const string vertOutput_PS_color = R"(
+out vec4 v_particleColor; // Size of a particle )";
+
+const string vertOutput_PS_texCoord = R"(
+out vec2 v_texCoord; // interpolated texture coordinateA)";
+
//-----------------------------------------------------------------------------
const string vertOutput_PS_tf_p = R"(
@@ -167,9 +208,15 @@ out vec3 tf_initialPosition; // To transform feedback)";
//-----------------------------------------------------------------------------
const string vertMain_Begin = R"(
-
void main()
{)";
+
+const string vertMain_instanced_Begin = R"(
+void main()
+{
+ vec3 position = a_positionP;
+)";
+
const string vertMain_v_P_VS = R"(
mat4 mvMatrix = u_vMatrix * u_mMatrix;
v_P_VS = vec3(mvMatrix * a_position); // vertex position in view space)";
@@ -213,8 +260,9 @@ const string vertMain_TBN_Nm = R"(
v_lightDirTS[i] *= TBN;
}
)";
-const string vertMain_PS_v_a = R"(
- float age = u_time - a_startTime; // Get the age of the particle)";
+
+//-----------------------------------------------------------------------------
+// Things that goes directly to geometry shader
const string vertMain_PS_v_t_default = R"(
if(age < 0.0)
vert.transparency = 0.0; // To be discard, because the particle is to be born
@@ -244,10 +292,82 @@ const string vertMain_PS_v_s_curve = R"(
pow(vert.size,2.0) * u_si_bernstein.y +
vert.size * u_si_bernstein.z +
u_si_bernstein.w; // Get transparency by bezier curve)";
+
+const string vertMain_PS_instanced_v_r = R"(
+ float rotation = a_rotation;)";
+
+const string vertMain_PS_instanced_v_s = R"(
+ float size = age / u_tTL;)";
+const string vertMain_PS_instanced_v_s_curve = R"(
+ size = pow(size,3.0) * u_si_bernstein.x +
+ pow(size,2.0) * u_si_bernstein.y +
+ size * u_si_bernstein.z +
+ u_si_bernstein.w; // Get transparency by bezier curve)";
+
+const string vertMain_PS_instanced_v_sS = R"(
+ position = size * position;
+ )";
+
const string vertMain_PS_v_doColorOverLT = R"(
vert.color = colorByAge(age/u_tTL);)";
+const string vertMain_PS_v_color = R"(
+ vert.color = u_color.rgb;)";
+
const string vertMain_PS_v_texNum = R"(
vert.texNum = a_texNum;)";
+
+const string vertMain_PS_v_a = R"(
+ float age = u_time - a_startTime; // Get the age of the particle)";
+
+const string vertMain_PS_v_tC = R"(
+ v_texCoord = 0.5 * (a_positionP.xy + vec2(1.0));)";
+
+const string vertMain_PS_instanced_v_t_default = R"(
+ if(age < 0.0)
+ transparency = 0.0; // To be discard, because the particle is to be born
+ else
+ transparency = 1.0;)";
+const string vertMain_PS_instanced_v_t_begin = R"(
+ if(age < 0.0)
+ transparency = 0.0; // To be discard, because the particle is to be born
+ else
+ {
+ transparency = age / u_tTL; // Get by the ratio age:lifetime)";
+const string vertMain_PS_instanced_v_t_linear = R"(
+ transparency = 1.0 - transparency; // Linear)";
+const string vertMain_PS_instanced_v_t_curve = R"(
+ transparency = pow(transparency,3.0) * u_al_bernstein.x +
+ pow(transparency,2.0) * u_al_bernstein.y +
+ transparency * u_al_bernstein.z +
+ u_al_bernstein.w; // Get transparency by bezier curve)";
+
+
+const string vertMain_PS_instanced_scale = R"(
+ position = vec3(u_radiusW * position.x, u_radiusH * position.y, position.z);
+ position = u_scale * position;
+ )";
+
+const string vertMain_PS_instanced_rotate = R"(
+ mat2 rot = mat2(cos(a_rotation),-sin(a_rotation),
+ sin(a_rotation), cos(a_rotation)); // Matrix of rotation
+ position = vec3(rot * position.xy, position.z);
+ )";
+
+const string vertMain_PS_instanced_EndAll = R"(
+
+ // Modelview matrix multiplication with (particle position + particle generator position)
+ // Calculate position in view space
+ gl_Position = u_pMatrix * (u_vOmvMatrix * vec4(a_position, 1) + vec4(position, 0.0));
+}
+)";
+
+const string vertMain_PS_instanced_EndAll_VertBillboard = R"(
+ gl_Position = vec4(position + a_positionP, 1);
+}
+)";
+
+
+
const string vertMain_PS_EndAll = R"(
// Modelview matrix multiplication with (particle position + particle generator position)
@@ -265,8 +385,7 @@ const string vertMain_EndAll = R"(
// pass the vertex w. the fix-function transform
gl_Position = u_pMatrix * mvMatrix * a_position;
-}
-)";
+})";
//-----------------------------------------------------------------------------
const string vertMain_PS_U_Begin = R"(
@@ -336,6 +455,9 @@ const string vertMain_PS_U_EndAll = R"(
}
}
})";
+
+
+
//-----------------------------------------------------------------------------
const string geomConfig_PS = R"(
layout (points) in; // Primitives that we received from vertex shader
@@ -361,7 +483,6 @@ uniform mat4 u_pMatrix; // Projection matrix)";
const string geomInput_u_matrix_vertBillboard = R"(
uniform mat4 u_vYawPMatrix; // Projection matrix)";
const string geomInput_PS_u_ScaRa = R"(
-
uniform float u_scale; // Particle scale
uniform float u_radiusW; // Particle width radius)
uniform float u_radiusH; // Particle height radius)";
@@ -373,10 +494,12 @@ const string geomInput_PS_u_row = R"(
uniform int u_row; // Number of row of flipbook texture)";
//-----------------------------------------------------------------------------
const string geomOutput_PS_v_pC = R"(
-
out vec4 v_particleColor; // The resulting color per vertex)";
const string geomOutput_PS_v_tC = R"(
out vec2 v_texCoord; // Texture coordinate at vertex)";
+
+const string vertOutput_PS_v_tC = R"(
+out vec2 v_texCoord; // Texture coordinate at vertex)";
//-----------------------------------------------------------------------------
const string geomMain_PS_Begin = R"(
@@ -633,7 +756,6 @@ const string fragInput_PS_u_wireFrame = R"(
uniform bool u_doWireFrame; // Boolean for wireFrame)";
//-----------------------------------------------------------------------------
const string fragMain_PS_TF = R"(
-
out vec4 o_fragColor; // output fragment color
void main()
@@ -643,7 +765,6 @@ void main()
)";
//-----------------------------------------------------------------------------
const string fragMain_PS = R"(
-
void main()
{
// Just set the interpolated color from the vertex shader
@@ -657,21 +778,36 @@ void main()
discard;
)";
-const string fragMain_PS_withoutColor = R"(
+
+const string fragMain_instanced_PS_begin = R"(
void main()
-{
+{
+)";
+
+const string fragMain_PS_withoutColor = R"(
// componentwise multiply w. texture color
if(!u_doWireFrame)
o_fragColor = texture(u_matTextureDiffuse0, v_texCoord);
else
o_fragColor = vec4(0,0,0,1.0);
- o_fragColor.a *= v_particleColor.a;
+ o_fragColor.a *= transparency;
if(o_fragColor.a < 0.001)
discard;
+)";
+
+const string fragMain_instanced_PS_end = R"(
+ // Just set the interpolated color from the vertex shader
+ o_fragColor = color;
+ // componentwise multiply w. texture color
+ if(!u_doWireFrame)
+ o_fragColor *= texture(u_matTextureDiffuse0, v_texCoord);
+ if(o_fragColor.a < 0.001)
+ discard;
)";
+
const string fragMain_PS_endAll = R"(
//Same color for each wireframe
if(u_doWireFrame)
@@ -1444,7 +1580,6 @@ const string fragMainCook_2_LightLoopNmSm = R"(
}
)";
const string fragMainCook_3_FragColor = R"(
-
// ambient lighting (note that the next IBL tutorial will replace
// this ambient lighting with environment lighting).
vec3 ambient = vec3(0.03) * matDiff.rgb * matOccl;
@@ -1459,7 +1594,6 @@ const string fragMainCook_3_FragColor = R"(
o_fragColor.a = matDiff.a;
)";
const string fragMainCook_3_FragColorSky = R"(
-
// Build diffuse reflection from environment light map
vec3 F = fresnelSchlickRoughness(max(dot(N, E), 0.0), F0, matRough);
vec3 kS = F;
@@ -1643,7 +1777,6 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
bool rot = mat->ps()->doRotation(); // Rotation
programName += "-B" + std::to_string(billboardType);
if (rot) programName += "-RT";
-
if (AlOvLi) programName += "-AL";
if (AlOvLi && AlOvLiCu) programName += "cu";
if (SiOvLi) programName += "-SL";
@@ -1733,7 +1866,7 @@ void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
* @param mat Parent material pointer
* @param isDrawProg Flag if program is for drawing instead of update
*/
-void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg)
+void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool isRenderInstanced)
{
if (mat->name() == "IBLMat")
{
@@ -1745,7 +1878,12 @@ void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg)
_shaders[1]->type() == ST_fragment);
if (isDrawProg)
- buildPerPixParticle(mat);
+ {
+ if (isRenderInstanced)
+ buildPerPixParticleInstanced(mat);
+ else
+ buildPerPixParticle(mat);
+ }
else
buildPerPixParticleUpdate(mat);
}
@@ -1974,6 +2112,117 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
}
//-----------------------------------------------------------------------------
+void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
+{
+ assert(_shaders.size() > 2 &&
+ _shaders[0]->type() == ST_vertex &&
+ _shaders[1]->type() == ST_fragment);
+
+ // Check what textures the material has
+ bool Dm = mat->hasTextureType(TT_diffuse);
+ GLint billboardType = mat->ps()->billboardType(); // Billboard type (0 -> default; 1 -> vertical billboard, 2 -> horizontal billboard)
+ bool rot = mat->ps()->doRotation(); // Rotation
+ bool AlOvLi = mat->ps()->doAlphaOverLT(); // Alpha over life
+ bool Co = mat->ps()->doColor(); // Color over life
+ bool CoOvLi = mat->ps()->doColorOverLT(); // Color over life
+ bool AlOvLiCu = mat->ps()->doAlphaOverLTCurve(); // Alpha over life curve
+ bool SiOvLi = mat->ps()->doSizeOverLT(); // Size over life
+ bool SiOvLiCu = mat->ps()->doSizeOverLTCurve(); // Size over life curve
+ bool FlBoTex = mat->ps()->doFlipBookTexture(); // Flipbook texture
+
+ //////////////////////////////
+ // Assemble vertex shader code
+ //////////////////////////////
+
+ string vertCode;
+ vertCode += shaderHeader();
+
+ // Vertex shader inputs
+ vertCode += vertInput_PS_a_positionP;
+ vertCode += vertInput_PS_a_p; //position
+ vertCode += vertInput_PS_a_st; // start time
+ if (rot) vertCode += vertInput_PS_a_r; //rotation as float
+ if (FlBoTex) vertCode += vertInput_PS_a_texNum; // per particle texture number
+
+ // Vertex shader uniforms
+ vertCode += vertInput_PS_u_ScaRa;
+ vertCode += vertInput_u_matrix_p;
+ vertCode += vertInput_PS_u_time;
+ vertCode += vertInput_u_matrix_vOmv;
+ if (AlOvLi && AlOvLiCu) vertCode += vertInput_PS_u_al_bernstein_alpha;
+ if (SiOvLi && SiOvLiCu) vertCode += vertInput_PS_u_al_bernstein_size;
+ if (Co && CoOvLi) vertCode += vertInput_PS_u_colorOvLF;
+
+ // Vertex shader outputs
+ if (FlBoTex) vertCode += vertOutput_PS_instanced_texNum;
+ vertCode += vertOutput_PS_instanced_transparency;
+ vertCode += vertOutput_PS_v_tC;
+
+ // Vertex shader functions
+ if (Co && CoOvLi) vertCode += vertFunction_PS_ColorOverLT;
+
+ // Vertex shader main loop
+ vertCode += vertMain_instanced_Begin;
+ vertCode += vertMain_PS_v_a;
+ vertCode += vertMain_PS_v_tC;
+ if (AlOvLi)
+ vertCode += vertMain_PS_instanced_v_t_begin;
+ else
+ vertCode += vertMain_PS_instanced_v_t_default;
+ if (AlOvLi) vertCode += AlOvLiCu ? vertMain_PS_instanced_v_t_curve : vertMain_PS_instanced_v_t_linear;
+ if (AlOvLi) vertCode += vertMain_PS_v_t_end;
+ //if (rot) vertCode += vertMain_PS_v_r;
+ vertCode += vertMain_PS_instanced_scale;
+ if (SiOvLi) vertCode += vertMain_PS_instanced_v_s;
+ if (SiOvLi && SiOvLiCu) vertCode += vertMain_PS_instanced_v_s_curve;
+ if (SiOvLi) vertCode += vertMain_PS_instanced_v_sS;
+ if (rot) vertCode += vertMain_PS_instanced_rotate;
+ if (Co && CoOvLi) vertCode += vertMain_PS_v_doColorOverLT;
+ if (FlBoTex) vertCode += vertMain_PS_v_texNum;
+ if (billboardType == BT_Vertical || billboardType == BT_Horizontal)
+ vertCode += vertMain_PS_EndAll_VertBillboard;
+ else
+ vertCode += vertMain_PS_instanced_EndAll;
+
+ addCodeToShader(_shaders[0], vertCode, _name + ".vert");
+
+ ////////////////////////////////
+ // Assemble fragment shader code
+ ////////////////////////////////
+
+ string fragCode;
+ fragCode += shaderHeader();
+
+ if (Co && !CoOvLi) vertCode += fragInput_PS_u_c;
+ // Fragment shader inputs
+ if (FlBoTex) fragCode += fragInput_PS_instanced_texNum;
+ fragCode += fragInput_PS_v_tC;
+ if (Co && !CoOvLi) fragCode += fragInput_PS_u_c;
+ fragCode += fragInput_PS_instanced_transparency;
+
+ // Fragment shader uniforms
+ if (Dm) fragCode += fragInput_u_matTexDm;
+ fragCode += fragInput_PS_u_overG;
+ fragCode += fragInput_PS_u_wireFrame;
+
+ // Fragment shader outputs
+ fragCode += fragOutputs_o_fragColor;
+
+ // Fragment shader main loop
+ fragCode += fragMain_instanced_PS_begin;
+ if (Co || CoOvLi)
+ {
+ fragCode += fragMain_PS_instanced_c;
+ fragCode += fragMain_instanced_PS_end;
+ }
+ else
+ fragCode += fragMain_PS_withoutColor;
+
+ fragCode += fragMain_PS_endAll;
+
+ addCodeToShader(_shaders[1], fragCode, _name + ".frag");
+}
+//-----------------------------------------------------------------------------
void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
{
assert(_shaders.size() > 2 &&
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index 93ebc1da..22865155 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -81,7 +81,15 @@ class SLGLProgramGenerated : public SLGLProgram
geomShader,
programName)
{
- buildProgramCodePS(mat, isDrawProg);
+
+ if (geomShader != "")
+ {
+ buildProgramCodePS(mat, isDrawProg, false);
+ }
+ else
+ {
+ buildProgramCodePS(mat, isDrawProg, true);
+ }
}
static bool lightsDoShadowMapping(SLVLight* lights);
@@ -92,7 +100,7 @@ class SLGLProgramGenerated : public SLGLProgram
string& programName,
bool isDrawProg);
- void buildProgramCodePS(SLMaterial* mat, bool isDrawProg);
+ void buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool isRenderInstanced = false);
void buildProgramCode(SLMaterial* mat,
SLVLight* lights);
void beginShader(SLCamera* cam,
@@ -104,6 +112,7 @@ class SLGLProgramGenerated : public SLGLProgram
void buildPerPixCook(SLMaterial* mat, SLVLight* lights);
void buildPerPixBlinn(SLMaterial* mat, SLVLight* lights);
void buildPerPixParticle(SLMaterial* mat);
+ void buildPerPixParticleInstanced(SLMaterial* mat);
void buildPerPixParticleUpdate(SLMaterial* mat);
// Video background shader builder functions
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index c69dcefe..c5751e4c 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -33,7 +33,13 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
{
assert(!name.empty());
- _primitive = PT_points;
+ // To be added to constructor
+ _renderInstanced = true;
+
+ if (_renderInstanced)
+ _primitive = PT_triangles;
+ else
+ _primitive = PT_points;
if (amount > UINT_MAX) // Need to change for number of floats
SL_EXIT_MSG("SLParticleSystem supports max. 2^32 vertices.");
@@ -43,8 +49,6 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
_velocityRndMin = velocityRandomStart;
_velocityRndMax = velocityRandomEnd;
- P.resize(1); // To trick parent class
-
_textureFirst = texC;
_textureFlipbook = texFlipbook;
@@ -447,6 +451,39 @@ void SLParticleSystem::generate()
_vao2.setAttrib(AT_initialPosition, AT_initialPosition, &tempInitP);
_vao2.generateTF((SLuint)tempP.size());
+ if (_renderInstanced)
+ {
+ /* Generate for billboard (for drawing without geometry shader)*/
+ P.push_back(SLVec3f(-1, -1, 0));
+ P.push_back(SLVec3f(1, -1, 0));
+ P.push_back(SLVec3f(1, 1, 0));
+ P.push_back(SLVec3f(-1, 1, 0));
+
+ I32.push_back(0);
+ I32.push_back(1);
+ I32.push_back(2);
+ I32.push_back(2);
+ I32.push_back(3);
+ I32.push_back(0);
+
+ /* Generate vao for rendering with draw instanced */
+ _renderVao1.setAttrib(AT_custom0, AT_custom0, &P);
+ _renderVao1.setIndices(&I32);
+ _renderVao1.setExternalVBO(_vao1.vbo(), 2);
+
+ _renderVao2.setAttrib(AT_custom0, AT_custom0, &P);
+ _renderVao2.setIndices(&I32);
+ _renderVao2.setExternalVBO(_vao2.vbo(), 2);
+
+ _renderVao1.generate((SLuint)P.size());
+ _renderVao2.generate((SLuint)P.size());
+ }
+ else
+ {
+ P.push_back(SLVec3f(1, 1, 0));
+ I32.push_back(0);
+ }
+
_isGenerated = true;
}
//-----------------------------------------------------------------------------
@@ -542,7 +579,7 @@ void SLParticleSystem::pauseOrResume()
* user. After I update the particle in the update pass, then and finally I
* draw them.
*/
-void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
+void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
{
/////////////////////////////////////
// Init particles vector and init VAO
@@ -556,7 +593,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
////////////////////
if (!_mat->program() || !_mat->programTF())
- _mat->generateProgramPS();
+ _mat->generateProgramPS(_renderInstanced);
////////////////////////////////////////////////
// Calculate time and paused and frustum culling
@@ -680,14 +717,20 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
_vao1.beginTF(_vao2.tfoID());
_vao1.drawArrayAs(PT_points);
_vao1.endTF();
- _vao = _vao2;
+ if (_renderInstanced)
+ _vao = _renderVao2;
+ else
+ _vao = _vao2;
}
else
{
_vao2.beginTF(_vao1.tfoID());
_vao2.drawArrayAs(PT_points);
_vao2.endTF();
- _vao = _vao1;
+ if (_renderInstanced)
+ _vao = _renderVao2;
+ else
+ _vao = _vao1;
}
_updateTime.set(GlobalTimer::timeMS() - _startUpdateTimeMS);
}
@@ -709,7 +752,6 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
// World space
if (_doWorldSpace)
{
-
if (_billboardType == BT_Vertical)
{
SLMat4f vMat = stateGL->viewMatrix; // Just view matrix because world space is enabled
@@ -728,7 +770,22 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
}
else
{
- spD->uniformMatrix4fv("u_vOmvMatrix", 1, (SLfloat*)&stateGL->viewMatrix);
+
+ SLMat4f vMat = stateGL->viewMatrix; // Just view matrix because world space is enabled
+ std::cout << "vMat" << std::endl;
+ vMat.m(0, 1.0f);
+ vMat.m(1, 0.0f);
+ vMat.m(2, 0.0f);
+
+ vMat.m(3, 1.0f);
+ vMat.m(4, 0.0f);
+ vMat.m(5, 0.0f);
+
+ vMat.m(6, 0.0f);
+ vMat.m(7, 0.0f);
+ vMat.m(8, 1.0f);
+ spD->uniformMatrix4fv("u_vOmvMatrix", 1, (SLfloat*)&vMat);
+ //spD->uniformMatrix4fv("u_vOmvMatrix", 1, (SLfloat*)&stateGL->viewMatrix);
}
}
else
@@ -822,7 +879,10 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node)
stateGL->blendFunc(GL_SRC_ALPHA, GL_ONE);
///////////////////////
- SLMesh::draw(sv, node);
+ if (_renderInstanced)
+ SLMesh::draw(sv, node, _amount*2);
+ else
+ SLMesh::draw(sv, node);
///////////////////////
if (_doColor && _doBlendBrightness)
diff --git a/modules/sl/source/mesh/SLParticleSystem.h b/modules/sl/source/mesh/SLParticleSystem.h
index fd1b5b9d..c3c1ec62 100644
--- a/modules/sl/source/mesh/SLParticleSystem.h
+++ b/modules/sl/source/mesh/SLParticleSystem.h
@@ -42,7 +42,7 @@ class SLParticleSystem : public SLMesh
const SLstring& name = "Particle system",
SLGLTexture* texFlipbook = nullptr);
- void draw(SLSceneView* sv, SLNode* node);
+ void draw(SLSceneView* sv, SLNode* node, SLuint instances = 1);
void deleteData();
void deleteDataGpu();
void buildAABB(SLAABBox& aabb, const SLMat4f& wmNode);
@@ -350,6 +350,9 @@ class SLParticleSystem : public SLMesh
SLGLVertexArray _vao1; //!< First OpenGL Vertex Array Object for swapping between updating/drawing
SLGLVertexArray _vao2; //!< Second OpenGL Vertex Array Object for swapping between updating/drawing
+ SLGLVertexArray _renderVao1; //!< First OpenGL Vertex Array Object for swapping between updating/drawing
+ SLGLVertexArray _renderVao2; //!< Second OpenGL Vertex Array Object for swapping between updating/drawing
+
// Boolean for generation/resume
SLbool _isVisibleInFrustum = true; //!< Boolean to set time since node not visible
SLbool _isPaused = false; //!< Boolean to stop updating
@@ -377,6 +380,7 @@ class SLParticleSystem : public SLMesh
SLbool _doSizeOverLT = true; //!< Boolean for size over life time
SLbool _doSizeOverLTCurve = false; //!< Boolean for size over life time curve
SLbool _doFlipBookTexture = false; //!< Boolean for flipbook texture
+ SLbool _renderInstanced = false; //!< Boolean for instanced rendering
};
//-----------------------------------------------------------------------------
#endif
From 0f20c06451244c5d5c5f1bcd4084370cb5e57204 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 10:40:30 +0100
Subject: [PATCH 021/108] [Externals] Add Python build script for GLFW
---
externals/prebuild_scripts/build_glfw.py | 112 +++++++++++++++++++++++
1 file changed, 112 insertions(+)
create mode 100644 externals/prebuild_scripts/build_glfw.py
diff --git a/externals/prebuild_scripts/build_glfw.py b/externals/prebuild_scripts/build_glfw.py
new file mode 100644
index 00000000..4ec469f4
--- /dev/null
+++ b/externals/prebuild_scripts/build_glfw.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python3
+
+import platform
+import subprocess
+import os
+import multiprocessing
+import shutil
+from pathlib import Path
+
+
+BUILD_DIR = Path("build")
+INSTALL_DIR = Path("install")
+
+SYSTEM_WIN64 = "win64"
+SYSTEM_LINUX = "linux"
+SYSTEM_MAC64 = "mac64"
+SYSTEM_MACARM64 = "macArm64"
+
+
+is_windows = platform.system() == "Windows"
+is_linux = platform.system() == "Linux"
+is_darwin = platform.system() == "Darwin"
+
+
+def build(build_type):
+ build_dir = BUILD_DIR / build_type
+ install_dir = INSTALL_DIR / build_type
+
+ # Convert the first letter to uppercase for CMake.
+ cmake_build_type = build_type[0].upper() + build_type[1:]
+
+ config_command = [
+ "cmake",
+ "-B" + str(build_dir),
+ "-DCMAKE_INSTALL_PREFIX=" + str(install_dir),
+ "-DGLFW_BUILD_EXAMPLES=OFF",
+ "-DGLFW_BUILD_TESTS=OFF",
+ "-DGLFW_BUILD_DOCS=OFF"
+ ]
+
+ if not is_windows:
+ config_command.append("-DCMAKE_BUILD_TYPE=" + cmake_build_type)
+
+ build_command = [
+ "cmake",
+ "--build", build_dir,
+ "--target", "install",
+ "-j" + str(multiprocessing.cpu_count())
+ ]
+
+ if is_windows:
+ build_command.extend(["--config", cmake_build_type])
+
+ subprocess.run(config_command)
+ subprocess.run(build_command)
+
+ destination = output_dir / build_type
+ destination.mkdir()
+
+ if is_windows:
+ shutil.copy(install_dir / "lib" / "glfw3.lib", destination)
+ else:
+ shutil.copy(install_dir / "lib" / "libglfw3.a", destination)
+
+
+print(f"\n=== Building GLFW ===\n")
+version = input("Version: ")
+
+if is_windows:
+ system = SYSTEM_WIN64
+ print("System: " + system)
+elif is_linux:
+ system = SYSTEM_LINUX
+ print("System: " + system)
+elif is_darwin:
+ system = input(f"System ({SYSTEM_MAC64}/{SYSTEM_MACARM64}): ")
+ assert system in (SYSTEM_MAC64, SYSTEM_MACARM64)
+
+name = system + "_glfw_" + version
+
+prebuilt_dir = Path(os.curdir).absolute().parent / "prebuilt"
+output_dir = Path(prebuilt_dir, name)
+print("Output directory: " + str(output_dir))
+
+zip_filename = name + ".zip"
+print("Zip file: " + zip_filename)
+
+if not os.path.isdir("glfw"):
+ print("\n=== Cloning GLFW ===\n")
+ subprocess.run(["git", "clone", "https://github.com/glfw/glfw.git"])
+
+os.chdir("glfw")
+
+print(f"\n=== Checking out version {version} ===\n")
+subprocess.run(["git", "checkout", version])
+subprocess.run(["git", "pull", "origin", version])
+
+print(f"\n=== Preparing output directory ===\n")
+
+shutil.rmtree(output_dir, ignore_errors=True)
+output_dir.mkdir()
+
+print("Directory created")
+
+print(f"\n=== Building debug version ===\n")
+build("debug")
+print(f"\n=== Building release version ===\n")
+build("release")
+
+shutil.copytree(INSTALL_DIR / "debug" / "include", output_dir / "include")
+shutil.copy("LICENSE.md", output_dir)
+shutil.copy("README.md", output_dir)
\ No newline at end of file
From 3b5ec616362aff4e71444d9c20ce3e260284aa0d Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 10:53:37 +0100
Subject: [PATCH 022/108] [Externals] Add Windows support for build_glfw.py
---
externals/prebuild_scripts/build_glfw.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/externals/prebuild_scripts/build_glfw.py b/externals/prebuild_scripts/build_glfw.py
index 4ec469f4..e3036d0e 100644
--- a/externals/prebuild_scripts/build_glfw.py
+++ b/externals/prebuild_scripts/build_glfw.py
@@ -82,9 +82,6 @@ def build(build_type):
output_dir = Path(prebuilt_dir, name)
print("Output directory: " + str(output_dir))
-zip_filename = name + ".zip"
-print("Zip file: " + zip_filename)
-
if not os.path.isdir("glfw"):
print("\n=== Cloning GLFW ===\n")
subprocess.run(["git", "clone", "https://github.com/glfw/glfw.git"])
@@ -109,4 +106,13 @@ def build(build_type):
shutil.copytree(INSTALL_DIR / "debug" / "include", output_dir / "include")
shutil.copy("LICENSE.md", output_dir)
-shutil.copy("README.md", output_dir)
\ No newline at end of file
+shutil.copy("README.md", output_dir)
+
+print("\n=== Creating archive === \n")
+
+os.chdir(os.pardir)
+shutil.make_archive(name, "zip", output_dir.parent, output_dir.name)
+print("Archive created")
+print("Path: " + str(Path(name + ".zip").absolute()))
+
+print("\n")
\ No newline at end of file
From 03c0999ba27b285ed6da91f17fc843e73b5fa43e Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 10:59:37 +0100
Subject: [PATCH 023/108] [CMake] Upgrade GLFW to 3.3.8 on Windows and macOS
---
cmake/DownloadPrebuilts.cmake | 47 ++++++++++++++++-------------------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/cmake/DownloadPrebuilts.cmake b/cmake/DownloadPrebuilts.cmake
index 8858fcb8..9e8d3dfc 100644
--- a/cmake/DownloadPrebuilts.cmake
+++ b/cmake/DownloadPrebuilts.cmake
@@ -446,22 +446,19 @@ elseif ("${SYSTEM_NAME_UPPER}" STREQUAL "WINDOWS") #----------------------------
# GLFW for Windows #
####################
- set(glfw_VERSION "3.3.2")
+ set(glfw_VERSION "3.3.8")
set(glfw_PREBUILT_DIR "win64_glfw_${glfw_VERSION}")
set(glfw_DIR "${PREBUILT_PATH}/${glfw_PREBUILT_DIR}")
- set(glfw_INCLUDE_DIR "${glfw_DIR}/include")
- set(glfw_LINK_DIR "${glfw_DIR}/lib-vc2019")
- add_library(glfw3dll SHARED IMPORTED)
- set_target_properties(glfw3dll PROPERTIES
- IMPORTED_IMPLIB "${glfw_LINK_DIR}/glfw3dll.lib"
- IMPORTED_LOCATION "${glfw_LINK_DIR}/glfw3.dll"
- INTERFACE_INCLUDE_DIRECTORIES "${glfw_INCLUDE_DIR}"
+ add_library(glfw3 STATIC IMPORTED)
+ set_target_properties(glfw3 PROPERTIES
+ IMPORTED_LOCATION "${glfw_DIR}/release/glfw3.lib"
+ IMPORTED_LOCATION_DEBUG "${glfw_DIR}/debug/glfw3.lib"
+ INTERFACE_INCLUDE_DIRECTORIES "${glfw_DIR}/include"
)
- set(glfw_LIBS glfw3dll)
+ set(glfw_LIBS glfw3)
download_lib("${glfw_PREBUILT_DIR}")
- copy_dlls("${glfw_LIBS}")
###################
# KTX for Windows #
@@ -643,19 +640,18 @@ elseif ("${SYSTEM_NAME_UPPER}" STREQUAL "DARWIN" AND
# GLFW for MacOS-x86_64 #
#########################
- set(glfw_VERSION "3.3.2")
+ set(glfw_VERSION "3.3.8")
set(glfw_PREBUILT_DIR "mac64_glfw_${glfw_VERSION}")
set(glfw_DIR "${PREBUILT_PATH}/${glfw_PREBUILT_DIR}")
- set(glfw_INCLUDE_DIR "${glfw_DIR}/include")
- add_library(glfw SHARED IMPORTED)
- set_target_properties(glfw PROPERTIES
- IMPORTED_LOCATION "${glfw_DIR}/Release/libglfw.3.dylib"
- INTERFACE_INCLUDE_DIRECTORIES "${glfw_INCLUDE_DIR}")
- set(glfw_LIBS glfw)
+ add_library(glfw3 STATIC IMPORTED)
+ set_target_properties(glfw3 PROPERTIES
+ IMPORTED_LOCATION "${glfw_DIR}/release/libglfw3.a"
+ IMPORTED_LOCATION_DEBUG "${glfw_DIR}/debug/libglfw3.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${glfw_DIR}/include")
+ set(glfw_LIBS glfw3)
download_lib("${glfw_PREBUILT_DIR}")
- copy_dylibs("${glfw_LIBS}")
########################
# KTX for MacOS-x86_64 #
@@ -824,19 +820,18 @@ elseif ("${SYSTEM_NAME_UPPER}" STREQUAL "DARWIN" AND
# GLFW for MacOS-arm64 #
########################
- set(glfw_VERSION "3.3.2")
+ set(glfw_VERSION "3.3.8")
set(glfw_PREBUILT_DIR "macArm64_glfw_${glfw_VERSION}")
set(glfw_DIR "${PREBUILT_PATH}/${glfw_PREBUILT_DIR}")
- set(glfw_INCLUDE_DIR "${glfw_DIR}/include")
- add_library(glfw SHARED IMPORTED)
- set_target_properties(glfw PROPERTIES
- IMPORTED_LOCATION "${glfw_DIR}/Release/libglfw.3.3.dylib"
- INTERFACE_INCLUDE_DIRECTORIES "${glfw_INCLUDE_DIR}")
- set(glfw_LIBS glfw)
+ add_library(glfw3 STATIC IMPORTED)
+ set_target_properties(glfw3 PROPERTIES
+ IMPORTED_LOCATION "${glfw_DIR}/release/libglfw3.a"
+ IMPORTED_LOCATION_DEBUG "${glfw_DIR}/debug/libglfw3.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${glfw_DIR}/include")
+ set(glfw_LIBS glfw3)
download_lib("${glfw_PREBUILT_DIR}")
- copy_dylibs("${glfw_LIBS}")
#######################
# KTX for MacOS-arm64 #
From ba333c3da4a0bda9f772f6f3b730ca8a4d7265bd Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:00:53 +0100
Subject: [PATCH 024/108] [WebGPU] Fix GLFW linking
---
apps/webgpu/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 97bfde63..40b48567 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -47,4 +47,4 @@ if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
endif ()
add_executable(webgpu-demo main.cpp)
-target_link_libraries(webgpu-demo PRIVATE wgpu glfw3dll)
+target_link_libraries(webgpu-demo PRIVATE wgpu ${glfw_LIBS})
From 3e91462dad04e440f38159b7e8e97c83bdd67196 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:04:19 +0100
Subject: [PATCH 025/108] [Externals] Add support for macOS cross-compilation
to build_glfw.py
---
externals/prebuild_scripts/build_glfw.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/externals/prebuild_scripts/build_glfw.py b/externals/prebuild_scripts/build_glfw.py
index e3036d0e..1f66519a 100644
--- a/externals/prebuild_scripts/build_glfw.py
+++ b/externals/prebuild_scripts/build_glfw.py
@@ -40,6 +40,11 @@ def build(build_type):
if not is_windows:
config_command.append("-DCMAKE_BUILD_TYPE=" + cmake_build_type)
+
+ if system == SYSTEM_MAC64:
+ config_command.append("-DCMAKE_OSX_ARCHITECTURES=x86_64")
+ elif system == SYSTEM_MACARM64:
+ config_command.append("-DCMAKE_OSX_ARCHITECTURES=arm64")
build_command = [
"cmake",
From 29c1a76bd393901c0b6b16bf46e38c1a0759df79 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:12:21 +0100
Subject: [PATCH 026/108] [WebGPU] Add support for Metal surfaces
---
apps/webgpu/CMakeLists.txt | 17 +++++++++++++----
apps/webgpu/main.cpp | 24 ++++++++++++++++++++++--
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 40b48567..7eb61dd6 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -38,13 +38,22 @@ else ()
endif ()
add_library(wgpu STATIC IMPORTED)
-set_target_properties(wgpu PROPERTIES
- IMPORTED_LOCATION "${WGPU_DIR}/wgpu_native.lib"
- INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
- target_link_libraries(wgpu INTERFACE "ws2_32" "userenv" "advapi32" "bcrypt" "d3dcompiler" "ntdll" "opengl32")
+ target_link_libraries(wgpu INTERFACE "ws2_32" "userenv" "bcrypt" "d3dcompiler" "ntdll" "opengl32")
+ set_target_properties(wgpu PROPERTIES
+ IMPORTED_LOCATION "${WGPU_DIR}/libwgpu_native.lib"
+ INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
+elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
+ target_link_libraries(wgpu INTERFACE "-framework CoreFoundation" "-framework QuartzCore" "-framework Metal")
+ set_target_properties(wgpu PROPERTIES
+ IMPORTED_LOCATION "${WGPU_DIR}/libwgpu_native.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
endif ()
add_executable(webgpu-demo main.cpp)
target_link_libraries(webgpu-demo PRIVATE wgpu ${glfw_LIBS})
+
+if (SYSTEM_NAME_UPPER MATCHES "DARWIN")
+ target_link_libraries(webgpu-demo PRIVATE "-framework Cocoa" "-framework IOKit")
+endif ()
\ No newline at end of file
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index b23d48cb..b835cf79 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -9,10 +9,17 @@
#elif defined(__APPLE__)
# define SYSTEM_DARWIN
# define GLFW_EXPOSE_NATIVE_COCOA
+# define OBJC_OLD_DISPATCH_PROTOTYPES 1
+# include
+# include
+# include
+# include
#endif
#include
+
#include
+#define GLFW_NATIVE_INCLUDE_NONE
#include
#include
@@ -107,11 +114,24 @@ int main(int argc, const char* argv[])
// The surface is where our rendered images will be presented to.
// It is created from window handles on most platforms and from a canvas in the browser.
-#ifdef SYSTEM_WINDOWS
+#if defined(SYSTEM_WINDOWS)
WGPUSurfaceDescriptorFromWindowsHWND nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
nativeSurfaceDesc.hinstance = GetModuleHandle(nullptr);
nativeSurfaceDesc.hwnd = glfwGetWin32Window(window);
+#elif defined(SYSTEM_DARWIN)
+ id cocoaWindow = glfwGetCocoaWindow(window);
+
+ id contentView = objc_msgSend(cocoaWindow, sel_registerName("contentView"));
+ objc_msgSend(contentView, sel_getUid("setWantsLayer:"), 1);
+
+ objc_class *metalLayerClass = objc_getClass("CAMetalLayer");
+ id metalLayer = objc_msgSend((id)metalLayerClass, sel_getUid("layer"));
+ objc_msgSend(contentView, sel_registerName("setLayer:"), metalLayer);
+
+ WGPUSurfaceDescriptorFromMetalLayer nativeSurfaceDesc = {};
+ nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
+ nativeSurfaceDesc.layer = metalLayer;
#endif
WGPUSurfaceDescriptor surfaceDesc = {};
@@ -286,7 +306,7 @@ int main(int argc, const char* argv[])
// === Submit the command buffer to the GPU ===
// The work for the GPU is submitted through the queue and executed.
wgpuQueueSubmit(queue, 1, &cmdBuffer);
-
+
// === Present the surface ===
// This presents our rendered texture to the screen.
wgpuSurfacePresent(surface);
From a81d07795739a7d28f8bada8af21290e03ff7c6f Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:17:03 +0100
Subject: [PATCH 027/108] [WebGPU] Add support for Xlib surfaces
---
apps/webgpu/main.cpp | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index b835cf79..7d48d42e 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -9,6 +9,8 @@
#elif defined(__APPLE__)
# define SYSTEM_DARWIN
# define GLFW_EXPOSE_NATIVE_COCOA
+# define GLFW_NATIVE_INCLUDE_NONE
+
# define OBJC_OLD_DISPATCH_PROTOTYPES 1
# include
# include
@@ -17,9 +19,7 @@
#endif
#include
-
#include
-#define GLFW_NATIVE_INCLUDE_NONE
#include
#include
@@ -119,19 +119,24 @@ int main(int argc, const char* argv[])
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
nativeSurfaceDesc.hinstance = GetModuleHandle(nullptr);
nativeSurfaceDesc.hwnd = glfwGetWin32Window(window);
+#elif defined(SYSTEM_LINUX)
+ WGPUSurfaceDescriptorFromXlibWindow nativeSurfaceDesc = {};
+ nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromXlibWindow;
+ nativeSurfaceDesc.display = glfwGetX11Display();
+ nativeSurfaceDesc.window = glfwGetX11Window(window);
#elif defined(SYSTEM_DARWIN)
id cocoaWindow = glfwGetCocoaWindow(window);
id contentView = objc_msgSend(cocoaWindow, sel_registerName("contentView"));
objc_msgSend(contentView, sel_getUid("setWantsLayer:"), 1);
- objc_class *metalLayerClass = objc_getClass("CAMetalLayer");
- id metalLayer = objc_msgSend((id)metalLayerClass, sel_getUid("layer"));
+ objc_class* metalLayerClass = objc_getClass("CAMetalLayer");
+ id metalLayer = objc_msgSend((id)metalLayerClass, sel_getUid("layer"));
objc_msgSend(contentView, sel_registerName("setLayer:"), metalLayer);
WGPUSurfaceDescriptorFromMetalLayer nativeSurfaceDesc = {};
- nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
- nativeSurfaceDesc.layer = metalLayer;
+ nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
+ nativeSurfaceDesc.layer = metalLayer;
#endif
WGPUSurfaceDescriptor surfaceDesc = {};
From fef422b6521a71477a7d3bea5efb102409de73ed Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:18:27 +0100
Subject: [PATCH 028/108] [WebGPU] Add Linux libraries to CMake
---
apps/webgpu/CMakeLists.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 7eb61dd6..55b477a3 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -44,6 +44,10 @@ if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
set_target_properties(wgpu PROPERTIES
IMPORTED_LOCATION "${WGPU_DIR}/libwgpu_native.lib"
INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
+elseif (SYSTEM_NAME_UPPER MATCHES "LINUX")
+ set_target_properties(wgpu PROPERTIES
+ IMPORTED_LOCATION "${WGPU_DIR}/libwgpu_native.a"
+ INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
target_link_libraries(wgpu INTERFACE "-framework CoreFoundation" "-framework QuartzCore" "-framework Metal")
set_target_properties(wgpu PROPERTIES
From c7370487a25a28a7525eb0fa5cf8437fd987c3b1 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 11:31:54 +0100
Subject: [PATCH 029/108] [WebGPU] Link X11 on Linux
---
apps/webgpu/CMakeLists.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 55b477a3..4bc31d6b 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -58,6 +58,8 @@ endif ()
add_executable(webgpu-demo main.cpp)
target_link_libraries(webgpu-demo PRIVATE wgpu ${glfw_LIBS})
-if (SYSTEM_NAME_UPPER MATCHES "DARWIN")
+if (SYSTEM_NAME_UPPER MATCHES "LINUX")
+ target_link_libraries(webgpu-demo PRIVATE "X11")
+elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
target_link_libraries(webgpu-demo PRIVATE "-framework Cocoa" "-framework IOKit")
endif ()
\ No newline at end of file
From 9c340b69d909b8ef410193a9f94b5631d642a13f Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 13:33:34 +0100
Subject: [PATCH 030/108] [WebGPU] Render demo using vertex and index buffers
---
apps/webgpu/CMakeLists.txt | 2 +-
apps/webgpu/main.cpp | 111 ++++++++++++++++++++++++++++++++-----
2 files changed, 98 insertions(+), 15 deletions(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 4bc31d6b..cf777bb2 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -42,7 +42,7 @@ add_library(wgpu STATIC IMPORTED)
if (SYSTEM_NAME_UPPER MATCHES "WINDOWS")
target_link_libraries(wgpu INTERFACE "ws2_32" "userenv" "bcrypt" "d3dcompiler" "ntdll" "opengl32")
set_target_properties(wgpu PROPERTIES
- IMPORTED_LOCATION "${WGPU_DIR}/libwgpu_native.lib"
+ IMPORTED_LOCATION "${WGPU_DIR}/wgpu_native.lib"
INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
elseif (SYSTEM_NAME_UPPER MATCHES "LINUX")
set_target_properties(wgpu PROPERTIES
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 7d48d42e..5bf45c94 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -23,7 +23,9 @@
#include
#include
+#include
#include
+#include
#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
@@ -93,11 +95,26 @@ int main(int argc, const char* argv[])
WGPUAdapter adapter;
wgpuInstanceRequestAdapter(instance, &adapterOptions, handleAdapterRequest, &adapter);
+ WGPUSupportedLimits adapterLimits;
+ wgpuAdapterGetLimits(adapter, &adapterLimits);
+
// === Acquire a WebGPU device ===
// A device provides access to a GPU and is created from an adapter.
+ // We specify the capabilites that we require our device to have in requiredLimits.
+ // We cannot access more resources than specified in the required limits,
+ // which is how WebGPU prevents code from working on one machine and not on another.
+
+ WGPURequiredLimits requiredLimits = {};
+ requiredLimits.limits.maxVertexAttributes = 1;
+ requiredLimits.limits.maxVertexBuffers = 1;
+ requiredLimits.limits.maxBufferSize = 4ull * 2ull * sizeof(float);
+ requiredLimits.limits.maxVertexBufferArrayStride = 2ull * sizeof(float);
+ requiredLimits.limits.minStorageBufferOffsetAlignment = adapterLimits.limits.minStorageBufferOffsetAlignment;
+ requiredLimits.limits.minUniformBufferOffsetAlignment = adapterLimits.limits.minUniformBufferOffsetAlignment;
WGPUDeviceDescriptor deviceDesc = {};
deviceDesc.label = "Demo Device";
+ deviceDesc.requiredLimits = &requiredLimits;
deviceDesc.defaultQueue.label = "Demo Queue";
WGPUDevice device;
@@ -170,6 +187,58 @@ int main(int argc, const char* argv[])
wgpuSurfaceConfigure(surface, &surfaceConfig);
WEBGPU_DEMO_LOG("[WebGPU] Surface configured");
+ // === Create the WebGPU vertex buffer ===
+ // The vertex buffer contains the input data for the shader.
+
+ // clang-format off
+ std::vector vertexData =
+ {
+ -0.5, 0.5, // top-left corner
+ -0.5, -0.5, // bottom-left corner
+ 0.5, 0.5, // top-right corner
+ 0.5, -0.5, // bottom-right corner
+ };
+ // clang-format on
+
+ unsigned vertexCount = vertexData.size() / 2;
+ unsigned vertexDataSize = vertexData.size() * sizeof(float);
+
+ WGPUBufferDescriptor vertexBufferDesc = {};
+ vertexBufferDesc.label = "Demo Vertex Buffer";
+ vertexBufferDesc.size = vertexDataSize;
+ vertexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
+
+ WGPUBuffer vertexBuffer = wgpuDeviceCreateBuffer(device, &vertexBufferDesc);
+ WEBGPU_DEMO_CHECK(vertexBuffer, "[WebGPU] Failed to create vertex buffer");
+ WEBGPU_DEMO_LOG("[WebGPU] Vertex buffer created");
+
+ // Upload the data to the GPU.
+ wgpuQueueWriteBuffer(queue, vertexBuffer, 0, vertexData.data(), vertexDataSize);
+
+ // === Create the WebGPU index buffer ===
+
+ // clang-format off
+ std::vector indexData =
+ {
+ 0, 1, 2,
+ 2, 1, 3,
+ };
+ // clang-format on
+
+ unsigned indexCount = indexData.size();
+ unsigned indexDataSize = indexData.size() * sizeof(std::uint16_t);
+
+ WGPUBufferDescriptor indexBufferDesc = {};
+ indexBufferDesc.label = "Demo Index Buffer";
+ indexBufferDesc.size = indexDataSize;
+ indexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index;
+
+ WGPUBuffer indexBuffer = wgpuDeviceCreateBuffer(device, &indexBufferDesc);
+ WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create index buffer");
+ WEBGPU_DEMO_LOG("[WebGPU] Index buffer created");
+
+ wgpuQueueWriteBuffer(queue, indexBuffer, 0, indexData.data(), indexDataSize);
+
// === Create the shader module ===
// Create a shader module for use in our render pipeline.
// Shaders are written in a WebGPU-specific language called WGSL (WebGPU shader language).
@@ -177,14 +246,8 @@ int main(int argc, const char* argv[])
const char* shaderSource = R"(
@vertex
- fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f {
- if (in_vertex_index == 0u) {
- return vec4f(-0.5, -0.5, 0.0, 1.0);
- } else if (in_vertex_index == 1u) {
- return vec4f(0.5, -0.5, 0.0, 1.0);
- } else {
- return vec4f(0.0, 0.5, 0.0, 1.0);
- }
+ fn vs_main(@location(0) in_vertex_position: vec2f) -> @builtin(position) vec4f {
+ return vec4f(in_vertex_position, 0.0, 1.0);
}
@fragment
@@ -198,7 +261,7 @@ int main(int argc, const char* argv[])
shaderModuleWGSLDesc.code = shaderSource;
WGPUShaderModuleDescriptor shaderModuleDesc = {};
- shaderModuleDesc.label = "Hello Triangle Shader";
+ shaderModuleDesc.label = "Demo Shader";
shaderModuleDesc.nextInChain = (const WGPUChainedStruct*)&shaderModuleWGSLDesc;
WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
@@ -209,10 +272,25 @@ int main(int argc, const char* argv[])
// The render pipeline specifies the configuration for the fixed-function stages as well as
// the shaders for the programmable stages of the hardware pipeline.
+ // Description of the vertex attribute for the vertex buffer layout
+ WGPUVertexAttribute vertexAttribute = {};
+ vertexAttribute.format = WGPUVertexFormat_Float32x2;
+ vertexAttribute.offset = 0;
+ vertexAttribute.shaderLocation = 0;
+
+ // Description of the vertex buffer layout for the vertex shader stage
+ WGPUVertexBufferLayout vertexBufferLayout = {};
+ vertexBufferLayout.arrayStride = 2ull * sizeof(float);
+ vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
+ vertexBufferLayout.attributeCount = 1;
+ vertexBufferLayout.attributes = &vertexAttribute;
+
// Configuration for the vertex shader stage
WGPUVertexState vertexState = {};
vertexState.module = shaderModule;
vertexState.entryPoint = "vs_main";
+ vertexState.bufferCount = 1;
+ vertexState.buffers = &vertexBufferLayout;
// Configuration for the primitive assembly and rasterization stages
WGPUPrimitiveState primitiveState = {};
@@ -238,7 +316,7 @@ int main(int argc, const char* argv[])
// Configuration for the entire pipeline
WGPURenderPipelineDescriptor pipelineDesc = {};
- pipelineDesc.label = "Hello Triangle Pipeline";
+ pipelineDesc.label = "Demo Pipeline";
pipelineDesc.vertex = vertexState;
pipelineDesc.primitive = primitiveState;
pipelineDesc.multisample = multisampleState;
@@ -252,6 +330,7 @@ int main(int argc, const char* argv[])
while (!glfwWindowShouldClose(window))
{
+
// === Create a WebGPU texture view ===
// The texture view is where we render our image into.
@@ -267,7 +346,7 @@ int main(int argc, const char* argv[])
// The encoder encodes the commands for the GPU into a command buffer.
WGPUCommandEncoderDescriptor cmdEncoderDesc = {};
- cmdEncoderDesc.label = " Hello Triangle Command Encoder";
+ cmdEncoderDesc.label = "Demo Command Encoder";
WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(device, &cmdEncoderDesc);
WEBGPU_DEMO_CHECK(cmdEncoder, "[WebGPU] Failed to create command encoder");
@@ -287,7 +366,7 @@ int main(int argc, const char* argv[])
colorAttachment.clearValue.a = 1.0;
WGPURenderPassDescriptor renderPassDesc = {};
- renderPassDesc.label = "Hello Triangle Render Pass";
+ renderPassDesc.label = "Demo Render Pass";
renderPassDesc.colorAttachmentCount = 1;
renderPassDesc.colorAttachments = &colorAttachment;
@@ -297,14 +376,16 @@ int main(int argc, const char* argv[])
WGPURenderPassEncoder renderPassEncoder = wgpuCommandEncoderBeginRenderPass(cmdEncoder, &renderPassDesc);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipeline);
- wgpuRenderPassEncoderDraw(renderPassEncoder, 3, 1, 0, 0);
+ wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, vertexBuffer, 0, vertexDataSize);
+ wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, indexBuffer, WGPUIndexFormat_Uint16, 0, indexDataSize);
+ wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
wgpuRenderPassEncoderEnd(renderPassEncoder);
// === Get the command buffer ===
// The command encoder is finished to get the commands for the GPU to execute in a command buffer.
WGPUCommandBufferDescriptor cmdBufferDesc = {};
- cmdBufferDesc.label = "Hello Triangle Command Buffer";
+ cmdBufferDesc.label = "Demo Command Buffer";
WGPUCommandBuffer cmdBuffer = wgpuCommandEncoderFinish(cmdEncoder, &cmdBufferDesc);
@@ -330,6 +411,8 @@ int main(int argc, const char* argv[])
wgpuRenderPipelineRelease(pipeline);
wgpuShaderModuleRelease(shaderModule);
+ wgpuBufferDestroy(vertexBuffer);
+ wgpuBufferRelease(vertexBuffer);
wgpuSurfaceRelease(surface);
wgpuQueueRelease(queue);
wgpuDeviceRelease(device);
From 0794f766ec7eaa9b73a7a47d3658613b3c77efc9 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 13:43:49 +0100
Subject: [PATCH 031/108] [WebGPU] Add surface re-configuring to demo
---
apps/webgpu/main.cpp | 65 ++++++++++++++++++++++++++++++++++----------
1 file changed, 51 insertions(+), 14 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 5bf45c94..96a672d3 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -74,9 +74,6 @@ int main(int argc, const char* argv[])
// Prevent GLFW from creating an OpenGL context as the underlying graphics API probably won't be OpenGL.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- // Create a non-resizable window as we currently don't recreate surfaces when the window size changes.
- glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
-
GLFWwindow* window = glfwCreateWindow(1280, 720, "WebGPU Demo", nullptr, nullptr);
WEBGPU_DEMO_CHECK(window, "[GLFW] Window created");
@@ -200,7 +197,7 @@ int main(int argc, const char* argv[])
};
// clang-format on
- unsigned vertexCount = vertexData.size() / 2;
+ unsigned vertexCount = vertexData.size() / 2;
unsigned vertexDataSize = vertexData.size() * sizeof(float);
WGPUBufferDescriptor vertexBufferDesc = {};
@@ -216,7 +213,7 @@ int main(int argc, const char* argv[])
wgpuQueueWriteBuffer(queue, vertexBuffer, 0, vertexData.data(), vertexDataSize);
// === Create the WebGPU index buffer ===
-
+
// clang-format off
std::vector indexData =
{
@@ -225,7 +222,7 @@ int main(int argc, const char* argv[])
};
// clang-format on
- unsigned indexCount = indexData.size();
+ unsigned indexCount = indexData.size();
unsigned indexDataSize = indexData.size() * sizeof(std::uint16_t);
WGPUBufferDescriptor indexBufferDesc = {};
@@ -274,16 +271,16 @@ int main(int argc, const char* argv[])
// Description of the vertex attribute for the vertex buffer layout
WGPUVertexAttribute vertexAttribute = {};
- vertexAttribute.format = WGPUVertexFormat_Float32x2;
- vertexAttribute.offset = 0;
- vertexAttribute.shaderLocation = 0;
+ vertexAttribute.format = WGPUVertexFormat_Float32x2;
+ vertexAttribute.offset = 0;
+ vertexAttribute.shaderLocation = 0;
// Description of the vertex buffer layout for the vertex shader stage
WGPUVertexBufferLayout vertexBufferLayout = {};
- vertexBufferLayout.arrayStride = 2ull * sizeof(float);
- vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
- vertexBufferLayout.attributeCount = 1;
- vertexBufferLayout.attributes = &vertexAttribute;
+ vertexBufferLayout.arrayStride = 2ull * sizeof(float);
+ vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
+ vertexBufferLayout.attributeCount = 1;
+ vertexBufferLayout.attributes = &vertexAttribute;
// Configuration for the vertex shader stage
WGPUVertexState vertexState = {};
@@ -337,7 +334,47 @@ int main(int argc, const char* argv[])
// Get a texture from the surface to render into.
WGPUSurfaceTexture surfaceTexture;
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
- WEBGPU_DEMO_CHECK(surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_Success, "[WebGPU] Failed to acquire current surface texture");
+
+ // The surface might change over time.
+ // For example, the window might be resized or minimized.
+ // We have to check the status and adapt to it.
+ switch (surfaceTexture.status)
+ {
+ case WGPUSurfaceGetCurrentTextureStatus_Success:
+ // Everything is ok.
+ // TODO: check for a suboptimal texture and re-configure it if needed.
+ break;
+
+ case WGPUSurfaceGetCurrentTextureStatus_Timeout:
+ case WGPUSurfaceGetCurrentTextureStatus_Outdated:
+ case WGPUSurfaceGetCurrentTextureStatus_Lost:
+ // The surface needs to be re-configured.
+
+ // Get the window size from the GLFW window.
+ glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
+
+ // The surface size might be zero if the window is minimized.
+ if (surfaceWidth != 0 && surfaceHeight != 0)
+ {
+ WEBGPU_DEMO_LOG("[WebGPU] Re-configuring surface");
+ surfaceConfig.width = surfaceWidth;
+ surfaceConfig.height = surfaceHeight;
+ wgpuSurfaceConfigure(surface, &surfaceConfig);
+ }
+
+ // Skip this frame.
+ glfwPollEvents();
+ continue;
+
+ case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
+ case WGPUSurfaceGetCurrentTextureStatus_DeviceLost:
+ // An error occured.
+ WEBGPU_DEMO_CHECK(false, "[WebGPU] Failed to acquire current surface texture");
+ break;
+
+ case WGPUSurfaceGetCurrentTextureStatus_Force32:
+ break;
+ }
// Create a view into the texture to specify where and how to modify the texture.
WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
From 1cf61b7d645de46b1aa79d91e0fdf1cee0d20271 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 14:29:57 +0100
Subject: [PATCH 032/108] [WebGPU] Add uniforms to demo
---
apps/webgpu/main.cpp | 109 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 98 insertions(+), 11 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 96a672d3..c433a0f0 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -102,10 +102,14 @@ int main(int argc, const char* argv[])
// which is how WebGPU prevents code from working on one machine and not on another.
WGPURequiredLimits requiredLimits = {};
- requiredLimits.limits.maxVertexAttributes = 1;
- requiredLimits.limits.maxVertexBuffers = 1;
+ requiredLimits.limits.maxVertexAttributes = 1u;
+ requiredLimits.limits.maxVertexBuffers = 1u;
requiredLimits.limits.maxBufferSize = 4ull * 2ull * sizeof(float);
- requiredLimits.limits.maxVertexBufferArrayStride = 2ull * sizeof(float);
+ requiredLimits.limits.maxVertexBufferArrayStride = 2u * sizeof(float);
+ requiredLimits.limits.maxInterStageShaderComponents = 2u;
+ requiredLimits.limits.maxBindGroups = 1u;
+ requiredLimits.limits.maxUniformBuffersPerShaderStage = 1u;
+ requiredLimits.limits.maxUniformBufferBindingSize = 16ull * 4ull;
requiredLimits.limits.minStorageBufferOffsetAlignment = adapterLimits.limits.minStorageBufferOffsetAlignment;
requiredLimits.limits.minUniformBufferOffsetAlignment = adapterLimits.limits.minUniformBufferOffsetAlignment;
@@ -184,7 +188,7 @@ int main(int argc, const char* argv[])
wgpuSurfaceConfigure(surface, &surfaceConfig);
WEBGPU_DEMO_LOG("[WebGPU] Surface configured");
- // === Create the WebGPU vertex buffer ===
+ // === Create the vertex buffer ===
// The vertex buffer contains the input data for the shader.
// clang-format off
@@ -212,7 +216,7 @@ int main(int argc, const char* argv[])
// Upload the data to the GPU.
wgpuQueueWriteBuffer(queue, vertexBuffer, 0, vertexData.data(), vertexDataSize);
- // === Create the WebGPU index buffer ===
+ // === Create the index buffer ===
// clang-format off
std::vector indexData =
@@ -236,20 +240,46 @@ int main(int argc, const char* argv[])
wgpuQueueWriteBuffer(queue, indexBuffer, 0, indexData.data(), indexDataSize);
+ // === Create the uniform buffer ===
+
+ WGPUBufferDescriptor uniformBufferDesc = {};
+ uniformBufferDesc.label = "Demo Uniform Buffer";
+ uniformBufferDesc.size = sizeof(float);
+ uniformBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
+
+ WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer(device, &uniformBufferDesc);
+ WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create uniform buffer");
+ WEBGPU_DEMO_LOG("[WebGPU] Uniform buffer created");
+
+ float uniformBufferData = 0.0f;
+ wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformBufferData, sizeof(float));
+
// === Create the shader module ===
// Create a shader module for use in our render pipeline.
// Shaders are written in a WebGPU-specific language called WGSL (WebGPU shader language).
// Shader modules can be used in multiple pipeline stages by specifying different entry points.
const char* shaderSource = R"(
+ @group(0) @binding(0) var u_time: f32;
+
+ struct VertexOutput {
+ @builtin(position) position: vec4f,
+ @location(0) texture_coords: vec2f,
+ }
+
@vertex
- fn vs_main(@location(0) in_vertex_position: vec2f) -> @builtin(position) vec4f {
- return vec4f(in_vertex_position, 0.0, 1.0);
+ fn vs_main(@location(0) in_vertex_position: vec2f) -> VertexOutput {
+ var offset = vec2(0.5 * sin(u_time), 0.5 * cos(u_time));
+
+ var out: VertexOutput;
+ out.position = vec4f(in_vertex_position + offset, 0.0, 1.0);
+ out.texture_coords = in_vertex_position + vec2(0.5, 0.5);
+ return out;
}
@fragment
- fn fs_main() -> @location(0) vec4f {
- return vec4f(0.2, 0.2, 1.0, 1.0);
+ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
+ return vec4f(in.texture_coords, 1.0, 1.0);
}
)";
@@ -265,7 +295,52 @@ int main(int argc, const char* argv[])
WEBGPU_DEMO_CHECK(shaderModule, "[WebGPU] Failed to create shader module");
WEBGPU_DEMO_LOG("[WebGPU] Shader module created");
- // === Create the WebGPU render pipeline ===
+ // === Create the bind group layout ===
+ // Bind groups contain binding layouts that describe how uniforms are passed to shaders.
+
+ WGPUBindGroupLayoutEntry bindingLayout = {};
+ bindingLayout.binding = 0;
+ bindingLayout.visibility = WGPUShaderStage_Vertex;
+ bindingLayout.buffer.type = WGPUBufferBindingType_Uniform;
+ bindingLayout.buffer.minBindingSize = sizeof(float);
+
+ WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc = {};
+ bindGroupLayoutDesc.label = "Demo Bind Group Layout";
+ bindGroupLayoutDesc.entryCount = 1;
+ bindGroupLayoutDesc.entries = &bindingLayout;
+ WGPUBindGroupLayout bindGroupLayout = wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
+ WEBGPU_DEMO_CHECK(bindGroupLayout, "[WebGPU] Failed to create bind group layout");
+ WEBGPU_DEMO_LOG("[WebGPU] Bind group layout created");
+
+ // === Create the bind group ===
+ // The bind group actually binds the buffer to the uniform.
+
+ WGPUBindGroupEntry binding = {};
+ binding.binding = 0;
+ binding.buffer = uniformBuffer;
+ binding.offset = 0;
+ binding.size = sizeof(float);
+
+ WGPUBindGroupDescriptor bindGroupDesc = {};
+ bindGroupDesc.layout = bindGroupLayout;
+ bindGroupDesc.entryCount = bindGroupLayoutDesc.entryCount;
+ bindGroupDesc.entries = &binding;
+ WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDesc);
+ WEBGPU_DEMO_CHECK(bindGroup, "[WebGPU] Failed to create bind group");
+ WEBGPU_DEMO_LOG("[WebGPU] Bind group created");
+
+ // === Create the pipeline layout ===
+ // The pipeline layout specifies the bind groups the pipeline uses.
+
+ WGPUPipelineLayoutDescriptor pipelineLayoutDesc = {};
+ pipelineLayoutDesc.label = "Demo Pipeline Layout";
+ pipelineLayoutDesc.bindGroupLayoutCount = 1;
+ pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
+ WGPUPipelineLayout pipelineLayout = wgpuDeviceCreatePipelineLayout(device, &pipelineLayoutDesc);
+ WEBGPU_DEMO_CHECK(pipelineLayout, "[WebGPU] Failed to create pipeline layout");
+ WEBGPU_DEMO_LOG("[WebGPU] Pipeline layout created");
+
+ // === Create the render pipeline ===
// The render pipeline specifies the configuration for the fixed-function stages as well as
// the shaders for the programmable stages of the hardware pipeline.
@@ -314,6 +389,7 @@ int main(int argc, const char* argv[])
// Configuration for the entire pipeline
WGPURenderPipelineDescriptor pipelineDesc = {};
pipelineDesc.label = "Demo Pipeline";
+ pipelineDesc.layout = pipelineLayout;
pipelineDesc.vertex = vertexState;
pipelineDesc.primitive = primitiveState;
pipelineDesc.multisample = multisampleState;
@@ -327,7 +403,6 @@ int main(int argc, const char* argv[])
while (!glfwWindowShouldClose(window))
{
-
// === Create a WebGPU texture view ===
// The texture view is where we render our image into.
@@ -379,6 +454,10 @@ int main(int argc, const char* argv[])
// Create a view into the texture to specify where and how to modify the texture.
WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
+ // === Update the uniform ===
+ float time = static_cast(glfwGetTime());
+ wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &time, sizeof(float));
+
// === Create a WebGPU command encoder ===
// The encoder encodes the commands for the GPU into a command buffer.
@@ -415,6 +494,7 @@ int main(int argc, const char* argv[])
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipeline);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, vertexBuffer, 0, vertexDataSize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, indexBuffer, WGPUIndexFormat_Uint16, 0, indexDataSize);
+ wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroup, 0, nullptr);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
wgpuRenderPassEncoderEnd(renderPassEncoder);
@@ -447,7 +527,14 @@ int main(int argc, const char* argv[])
// === Release all WebGPU resources ===
wgpuRenderPipelineRelease(pipeline);
+ wgpuPipelineLayoutRelease(pipelineLayout);
+ wgpuBindGroupRelease(bindGroup);
+ wgpuBindGroupLayoutRelease(bindGroupLayout);
wgpuShaderModuleRelease(shaderModule);
+ wgpuBufferDestroy(uniformBuffer);
+ wgpuBufferRelease(uniformBuffer);
+ wgpuBufferDestroy(indexBuffer);
+ wgpuBufferRelease(indexBuffer);
wgpuBufferDestroy(vertexBuffer);
wgpuBufferRelease(vertexBuffer);
wgpuSurfaceRelease(surface);
From 7f7bd944f2bf3a0569d6896addfe62f97df3a7a5 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 16:13:41 +0100
Subject: [PATCH 033/108] [WebGPU] Add texture to demo
---
apps/webgpu/CMakeLists.txt | 2 +-
apps/webgpu/main.cpp | 142 +++++++++++++++++++++++++++++--------
2 files changed, 115 insertions(+), 29 deletions(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index cf777bb2..373f3bec 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -56,7 +56,7 @@ elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
endif ()
add_executable(webgpu-demo main.cpp)
-target_link_libraries(webgpu-demo PRIVATE wgpu ${glfw_LIBS})
+target_link_libraries(webgpu-demo PRIVATE wgpu sl_cv ${glfw_LIBS})
if (SYSTEM_NAME_UPPER MATCHES "LINUX")
target_link_libraries(webgpu-demo PRIVATE "X11")
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index c433a0f0..5a8f2286 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -21,6 +21,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -101,17 +103,22 @@ int main(int argc, const char* argv[])
// We cannot access more resources than specified in the required limits,
// which is how WebGPU prevents code from working on one machine and not on another.
- WGPURequiredLimits requiredLimits = {};
- requiredLimits.limits.maxVertexAttributes = 1u;
- requiredLimits.limits.maxVertexBuffers = 1u;
- requiredLimits.limits.maxBufferSize = 4ull * 2ull * sizeof(float);
- requiredLimits.limits.maxVertexBufferArrayStride = 2u * sizeof(float);
- requiredLimits.limits.maxInterStageShaderComponents = 2u;
- requiredLimits.limits.maxBindGroups = 1u;
- requiredLimits.limits.maxUniformBuffersPerShaderStage = 1u;
- requiredLimits.limits.maxUniformBufferBindingSize = 16ull * 4ull;
- requiredLimits.limits.minStorageBufferOffsetAlignment = adapterLimits.limits.minStorageBufferOffsetAlignment;
- requiredLimits.limits.minUniformBufferOffsetAlignment = adapterLimits.limits.minUniformBufferOffsetAlignment;
+ WGPURequiredLimits requiredLimits = {};
+ requiredLimits.limits.maxVertexAttributes = 1u;
+ requiredLimits.limits.maxVertexBuffers = 1u;
+ requiredLimits.limits.maxBufferSize = 4ull * 2ull * sizeof(float);
+ requiredLimits.limits.maxVertexBufferArrayStride = 2u * sizeof(float);
+ requiredLimits.limits.maxInterStageShaderComponents = 2u;
+ requiredLimits.limits.maxBindGroups = 2u;
+ requiredLimits.limits.maxBindingsPerBindGroup = 2u;
+ requiredLimits.limits.maxUniformBuffersPerShaderStage = 1u;
+ requiredLimits.limits.maxUniformBufferBindingSize = 16ull * 4ull;
+ requiredLimits.limits.maxSampledTexturesPerShaderStage = 1u;
+ requiredLimits.limits.maxTextureDimension1D = 2048;
+ requiredLimits.limits.maxTextureDimension2D = 2048;
+ requiredLimits.limits.maxTextureArrayLayers = 1;
+ requiredLimits.limits.minStorageBufferOffsetAlignment = adapterLimits.limits.minStorageBufferOffsetAlignment;
+ requiredLimits.limits.minUniformBufferOffsetAlignment = adapterLimits.limits.minUniformBufferOffsetAlignment;
WGPUDeviceDescriptor deviceDesc = {};
deviceDesc.label = "Demo Device";
@@ -254,6 +261,65 @@ int main(int argc, const char* argv[])
float uniformBufferData = 0.0f;
wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformBufferData, sizeof(float));
+ // === Create the texture ===
+
+ // unsigned pixelDataSize = 256 * 256 * 4;
+ // std::vector pixelData(pixelDataSize, 100);
+
+ cv::Mat image = cv::imread(std::string(SL_PROJECT_ROOT) + "/data/images/textures/brickwall0512_C.jpg");
+ cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);
+
+ unsigned imageWidth = image.cols;
+ unsigned imageHeight = image.rows;
+ unsigned pixelDataSize = 4 * imageWidth * imageHeight;
+
+ WGPUTextureDescriptor textureDesc = {};
+ textureDesc.label = "Demo Texture";
+ textureDesc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
+ textureDesc.dimension = WGPUTextureDimension_2D;
+ textureDesc.size.width = imageWidth;
+ textureDesc.size.height = imageHeight;
+ textureDesc.size.depthOrArrayLayers = 1;
+ textureDesc.format = WGPUTextureFormat_RGBA8UnormSrgb;
+ textureDesc.mipLevelCount = 1;
+ textureDesc.sampleCount = 1;
+
+ WGPUTexture texture = wgpuDeviceCreateTexture(device, &textureDesc);
+ WEBGPU_DEMO_CHECK(texture, "[WebGPU] Failed to create texture");
+ WEBGPU_DEMO_LOG("[WebGPU] Texture created");
+
+ // Where do we copyu the pixel data to?
+ WGPUImageCopyTexture destination = {};
+ destination.texture = texture;
+ destination.mipLevel = 0;
+ destination.origin.x = 0;
+ destination.origin.y = 0;
+ destination.origin.z = 0;
+ destination.aspect = WGPUTextureAspect_All;
+
+ // Where do we copy the pixel data from?
+ WGPUTextureDataLayout pixelDataLayout = {};
+ pixelDataLayout.offset = 0;
+ pixelDataLayout.bytesPerRow = 4 * textureDesc.size.width;
+ pixelDataLayout.rowsPerImage = textureDesc.size.height;
+
+ // Upload the data to the GPU.
+ wgpuQueueWriteTexture(queue, &destination, image.data, pixelDataSize, &pixelDataLayout, &textureDesc.size);
+
+ // === Create a texture view into the texture ===
+ WGPUTextureViewDescriptor textureViewDesc = {};
+ textureViewDesc.aspect = WGPUTextureAspect_All;
+ textureViewDesc.baseArrayLayer = 0;
+ textureViewDesc.arrayLayerCount = 1;
+ textureViewDesc.baseMipLevel = 0;
+ textureViewDesc.mipLevelCount = 1;
+ textureViewDesc.dimension = WGPUTextureViewDimension_2D;
+ textureViewDesc.format = textureDesc.format;
+
+ WGPUTextureView textureView = wgpuTextureCreateView(texture, &textureViewDesc);
+ WEBGPU_DEMO_CHECK(textureView, "[WebGPU] Failed to create texture view");
+ WEBGPU_DEMO_LOG("[WebGPU] Texture view created");
+
// === Create the shader module ===
// Create a shader module for use in our render pipeline.
// Shaders are written in a WebGPU-specific language called WGSL (WebGPU shader language).
@@ -261,6 +327,7 @@ int main(int argc, const char* argv[])
const char* shaderSource = R"(
@group(0) @binding(0) var u_time: f32;
+ @group(0) @binding(1) var texture: texture_2d;
struct VertexOutput {
@builtin(position) position: vec4f,
@@ -279,7 +346,7 @@ int main(int argc, const char* argv[])
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
- return vec4f(in.texture_coords, 1.0, 1.0);
+ return textureLoad(texture, vec2i(i32(512.0 * in.texture_coords.x), i32(512.0 * in.texture_coords.y)), 0).rgba;
}
)";
@@ -296,35 +363,51 @@ int main(int argc, const char* argv[])
WEBGPU_DEMO_LOG("[WebGPU] Shader module created");
// === Create the bind group layout ===
- // Bind groups contain binding layouts that describe how uniforms are passed to shaders.
+ // Bind groups contain binding layouts that describe how uniforms and textures are passed to shaders.
+
+ // Entry for the uniform
+ WGPUBindGroupLayoutEntry uniformLayout = {};
+ uniformLayout.binding = 0;
+ uniformLayout.visibility = WGPUShaderStage_Vertex;
+ uniformLayout.buffer.type = WGPUBufferBindingType_Uniform;
+ uniformLayout.buffer.minBindingSize = sizeof(float);
- WGPUBindGroupLayoutEntry bindingLayout = {};
- bindingLayout.binding = 0;
- bindingLayout.visibility = WGPUShaderStage_Vertex;
- bindingLayout.buffer.type = WGPUBufferBindingType_Uniform;
- bindingLayout.buffer.minBindingSize = sizeof(float);
+ // Entry for the texture
+ WGPUBindGroupLayoutEntry textureLayout = {};
+ textureLayout.binding = 1;
+ textureLayout.visibility = WGPUShaderStage_Fragment;
+ textureLayout.texture.sampleType = WGPUTextureSampleType_Float;
+ textureLayout.texture.viewDimension = WGPUTextureViewDimension_2D;
+
+ std::vector bindGroupLayoutEntries = {uniformLayout, textureLayout};
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc = {};
bindGroupLayoutDesc.label = "Demo Bind Group Layout";
- bindGroupLayoutDesc.entryCount = 1;
- bindGroupLayoutDesc.entries = &bindingLayout;
+ bindGroupLayoutDesc.entryCount = bindGroupLayoutEntries.size();
+ bindGroupLayoutDesc.entries = bindGroupLayoutEntries.data();
WGPUBindGroupLayout bindGroupLayout = wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
WEBGPU_DEMO_CHECK(bindGroupLayout, "[WebGPU] Failed to create bind group layout");
WEBGPU_DEMO_LOG("[WebGPU] Bind group layout created");
// === Create the bind group ===
- // The bind group actually binds the buffer to the uniform.
+ // The bind group actually binds the buffer to uniforms and textures.
+
+ WGPUBindGroupEntry uniformBinding = {};
+ uniformBinding.binding = 0;
+ uniformBinding.buffer = uniformBuffer;
+ uniformBinding.offset = 0;
+ uniformBinding.size = sizeof(float);
+
+ WGPUBindGroupEntry textureBinding = {};
+ textureBinding.binding = 1;
+ textureBinding.textureView = textureView;
- WGPUBindGroupEntry binding = {};
- binding.binding = 0;
- binding.buffer = uniformBuffer;
- binding.offset = 0;
- binding.size = sizeof(float);
+ std::vector bindGroupEntries = {uniformBinding, textureBinding};
WGPUBindGroupDescriptor bindGroupDesc = {};
bindGroupDesc.layout = bindGroupLayout;
- bindGroupDesc.entryCount = bindGroupLayoutDesc.entryCount;
- bindGroupDesc.entries = &binding;
+ bindGroupDesc.entryCount = bindGroupEntries.size();
+ bindGroupDesc.entries = bindGroupEntries.data();
WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDesc);
WEBGPU_DEMO_CHECK(bindGroup, "[WebGPU] Failed to create bind group");
WEBGPU_DEMO_LOG("[WebGPU] Bind group created");
@@ -531,6 +614,9 @@ int main(int argc, const char* argv[])
wgpuBindGroupRelease(bindGroup);
wgpuBindGroupLayoutRelease(bindGroupLayout);
wgpuShaderModuleRelease(shaderModule);
+ wgpuTextureViewRelease(textureView);
+ wgpuTextureDestroy(texture);
+ wgpuTextureRelease(texture);
wgpuBufferDestroy(uniformBuffer);
wgpuBufferRelease(uniformBuffer);
wgpuBufferDestroy(indexBuffer);
From 7339609d7410f7a1baa7efb4ec5d1898e52a8f34 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Fri, 3 Nov 2023 16:15:12 +0100
Subject: [PATCH 034/108] [WebGPU] Use mailbox present mode in demo
---
apps/webgpu/main.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 5a8f2286..ccad5570 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -188,7 +188,7 @@ int main(int argc, const char* argv[])
surfaceConfig.device = device;
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
surfaceConfig.format = surfaceCapabilities.formats[0];
- surfaceConfig.presentMode = WGPUPresentMode_Fifo;
+ surfaceConfig.presentMode = WGPUPresentMode_Mailbox;
surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
surfaceConfig.width = surfaceWidth;
surfaceConfig.height = surfaceHeight;
@@ -263,9 +263,6 @@ int main(int argc, const char* argv[])
// === Create the texture ===
- // unsigned pixelDataSize = 256 * 256 * 4;
- // std::vector pixelData(pixelDataSize, 100);
-
cv::Mat image = cv::imread(std::string(SL_PROJECT_ROOT) + "/data/images/textures/brickwall0512_C.jpg");
cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);
From 68a6d9ffe70b54245c8a59df33cb3a06e6f732db Mon Sep 17 00:00:00 2001
From: luc
Date: Fri, 3 Nov 2023 18:32:16 +0100
Subject: [PATCH 035/108] Add option to swith particle rendering method in the
gui and fix some particles instanced rendering shaders
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 8 ++
modules/sl/source/SLAssetManager.cpp | 16 +++
modules/sl/source/SLAssetManager.h | 3 +
modules/sl/source/SLMaterial.cpp | 18 ++-
modules/sl/source/SLMaterial.h | 3 +
modules/sl/source/gl/SLGLProgramGenerated.cpp | 133 +++++++++++++-----
modules/sl/source/gl/SLGLProgramGenerated.h | 3 +-
modules/sl/source/mesh/SLParticleSystem.cpp | 41 +++---
modules/sl/source/mesh/SLParticleSystem.h | 8 +-
9 files changed, 180 insertions(+), 53 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index e4d20e0d..d943894d 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -2393,6 +2393,7 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
if (ImGui::MenuItem("Skeleton", "K", sv->drawBits()->get(SL_DB_SKELETON)))
sv->drawBits()->toggle(SL_DB_SKELETON);
+
if (ImGui::MenuItem("All off"))
sv->drawBits()->allOff();
@@ -3770,6 +3771,13 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
ps->isGenerated(false);
}
+ bool instanced = ps->renderInstanced();
+ if (ImGui::Checkbox("Instanced draw", &instanced))
+ {
+ ps->drawInstanced(instanced);
+ ps->isGenerated(false);
+ }
+
// TTL (Time to live)
if (ImGui::CollapsingHeader("Time to live"))
{
diff --git a/modules/sl/source/SLAssetManager.cpp b/modules/sl/source/SLAssetManager.cpp
index 020a6c99..1fedf31f 100644
--- a/modules/sl/source/SLAssetManager.cpp
+++ b/modules/sl/source/SLAssetManager.cpp
@@ -95,6 +95,21 @@ bool SLAssetManager::removeMesh(SLMesh* mesh)
}
return false;
}
+
+//! Removes the specified program from the meshes resource vector.
+bool SLAssetManager::removeProgram(SLGLProgram* program)
+{
+ assert(program);
+ for (SLulong i = 0; i < _programs.size(); ++i)
+ {
+ if (_programs[i] == program)
+ {
+ _programs.erase(_programs.begin() + i);
+ return true;
+ }
+ }
+ return false;
+}
//-----------------------------------------------------------------------------
//! Returns the pointer to shader program if found by name
SLGLProgram* SLAssetManager::getProgramByName(const string& programName)
@@ -104,6 +119,7 @@ SLGLProgram* SLAssetManager::getProgramByName(const string& programName)
return sp;
return nullptr;
}
+
//-----------------------------------------------------------------------------
//! merge other asset manager into this
void SLAssetManager::merge(SLAssetManager& other)
diff --git a/modules/sl/source/SLAssetManager.h b/modules/sl/source/SLAssetManager.h
index c261a6b2..773cde87 100644
--- a/modules/sl/source/SLAssetManager.h
+++ b/modules/sl/source/SLAssetManager.h
@@ -52,6 +52,9 @@ class SLAssetManager
//! Removes the specified mesh from the meshes resource vector.
bool removeMesh(SLMesh* mesh);
+ //! Removes the specified mesh from the meshes resource vector.
+ bool removeProgram(SLGLProgram* program);
+
//! Returns the pointer to shader program if found by name
SLGLProgram* getProgramByName(const string& programName);
diff --git a/modules/sl/source/SLMaterial.cpp b/modules/sl/source/SLMaterial.cpp
index d26365a3..3f8c0bab 100644
--- a/modules/sl/source/SLMaterial.cpp
+++ b/modules/sl/source/SLMaterial.cpp
@@ -372,6 +372,20 @@ SLMaterial::~SLMaterial()
_errorTexture = nullptr;
}
}
+
+
+void SLMaterial::deleteDataGpu()
+{
+ if (_program)
+ {
+ _assetManager->removeProgram(_program);
+ _program->deleteDataGpu();
+ delete _program;
+ _program = nullptr;
+ }
+}
+
+
//-----------------------------------------------------------------------------
/*!
If this material has not yet a shader program assigned (SLMaterial::_program)
@@ -389,7 +403,7 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
// Check first the asset manager if the requested program type already exists
string programNameDraw;
- SLGLProgramGenerated::buildProgramNamePS(this, programNameDraw, true);
+ SLGLProgramGenerated::buildProgramNamePS(this, programNameDraw, true, renderInstanced);
_program = _assetManager->getProgramByName(programNameDraw);
// If the program was not found by name generate a new one
@@ -415,7 +429,7 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
// Check first the asset manager if the requested programTF type already exists
string programNameUpdate;
- SLGLProgramGenerated::buildProgramNamePS(this, programNameUpdate, false);
+ SLGLProgramGenerated::buildProgramNamePS(this, programNameUpdate, false, renderInstanced);
_programTF = _assetManager->getProgramByName(programNameUpdate);
if (!_programTF)
{
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index 983f2ff5..9ae29fcb 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -114,6 +114,9 @@ class SLMaterial : public SLObject
SLSkybox* skybox = nullptr);
SLint passToUniforms(SLGLProgram* program, SLint nextTexUnit);
+
+ void deleteDataGpu();
+
//! Returns true if there is any transparency in diffuse alpha or textures
SLbool hasAlpha()
{
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 9aee3ca3..81cec78c 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -74,16 +74,19 @@ const string vertConstant_PS_pi = R"(
)";
//-----------------------------------------------------------------------------
const string vertInput_PS_u_time = R"(
-
uniform float u_time; // Simulation time
uniform float u_difTime; // Simulation delta time after frustum culling
uniform float u_tTL; // Time to live of a particle)";
+const string fragInput_PS_u_tTL = R"(
+uniform float u_tTL; // Time to live of a particle)";
const string vertInput_PS_u_al_bernstein_alpha = R"(
uniform vec4 u_al_bernstein; // Bernstein polynomial for alpha over time)";
const string vertInput_PS_u_al_bernstein_size = R"(
uniform vec4 u_si_bernstein; // Bernstein polynomial for size over time)";
const string vertInput_PS_u_colorOvLF = R"(
uniform float u_colorArr[256 * 3]; // Array of color value (for color over life))";
+const string fragInput_PS_u_colorOvLF = R"(
+uniform float u_colorArr[256 * 3]; // Array of color value (for color over life))";
const string vertInput_PS_u_deltaTime = R"(
uniform float u_deltaTime; // Elapsed time between frames)";
const string vertInput_PS_u_pgPos = R"(
@@ -122,7 +125,14 @@ out vec3 v_lightDirTS[NUM_LIGHTS]; // Vector to the light 0 in tangent spac
out vec3 v_spotDirTS[NUM_LIGHTS]; // Spot direction in tangent space)";
//-----------------------------------------------------------------------------
const string vertFunction_PS_ColorOverLT = R"(
+vec3 colorByAge(float age)
+{
+ int cachePos = int(clamp(age, 0.0, 1.0) * 255.0) * 3;
+ vec3 color = vec3(u_colorArr[cachePos], u_colorArr[cachePos + 1], u_colorArr[cachePos + 2]);
+ return color;
+})";
+const string fragFunction_PS_ColorOverLT = R"(
vec3 colorByAge(float age)
{
int cachePos = int(clamp(age, 0.0, 1.0) * 255.0) * 3;
@@ -162,13 +172,14 @@ const string fragMain_PS_v_c = R"(
vec4 color = u_color; // Particle color)";
const string fragMain_PS_v_doColorOverLT = R"(
vec4 color = vec4(vert[0].color, 1.0); // Particle color)";
+const string fragMain_PS_instanced_v_doColorOverLT = R"(
+ vec4 color = vec4(colorByAge(v_age/u_tTL), 1.0); // Particle color)";
const string fragMain_PS_v_withoutColor = R"(
vec4 color = vec4( 0.0, 0.0, 0.0, 1.0); // Particle color)";
const string fragMain_PS_instanced_c = R"(
- vec4 color = u_color; // Particle color
- color.w *= transparency; // Apply transparency
- )";
-
+ vec4 color = u_color; // Particle color)";
+const string fragMain_PS_instanced_transparency = R"(
+ color.w *= transparency; // Apply transparency)";
const string vertInput_u_matrix_p = R"(
uniform mat4 u_pMatrix; // Projection matrix)";
const string vertInput_u_matrix_vertBillboard = R"(
@@ -231,7 +242,6 @@ const string vertMain_v_R_OS = R"(
vec3 N = normalize(v_N_VS);
v_R_OS = invMvMatrix * reflect(I, N); // R = I-2.0*dot(N,I)*N;)";
const string vertMain_v_uv0 = R"(
-
v_uv0 = a_uv0; // pass diffuse color tex.coord. 1 for interpolation)";
const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
@@ -310,18 +320,38 @@ const string vertMain_PS_instanced_v_sS = R"(
const string vertMain_PS_v_doColorOverLT = R"(
vert.color = colorByAge(age/u_tTL);)";
+
+const string vertOutput_PS_age = R"(
+ out float v_age; // Age of a particle)";
+
+const string fragInput_PS_age = R"(
+ in float v_age; // Age of a particle)";
+
const string vertMain_PS_v_color = R"(
vert.color = u_color.rgb;)";
const string vertMain_PS_v_texNum = R"(
vert.texNum = a_texNum;)";
+const string vertMain_PS_instanced_v_texNum = R"(
+ texNum = a_texNum;)";
+
const string vertMain_PS_v_a = R"(
float age = u_time - a_startTime; // Get the age of the particle)";
const string vertMain_PS_v_tC = R"(
v_texCoord = 0.5 * (a_positionP.xy + vec2(1.0));)";
+const string vertMain_PS_v_tC_flipbook = R"(
+ uint actCI = uint(mod(float(a_texNum), float(u_col)));
+ uint actRI = (a_texNum - actCI) / u_col;
+ float actC = float(actCI);
+ float actR = float(actRI);
+
+ vec2 p = 0.5 * (a_positionP.xy + vec2(1.0));
+ v_texCoord = vec2((actC + p.x)/float(u_col), 1.0 - (actR - p.y)/float(u_row));
+)";
+
const string vertMain_PS_instanced_v_t_default = R"(
if(age < 0.0)
transparency = 0.0; // To be discard, because the particle is to be born
@@ -341,7 +371,6 @@ const string vertMain_PS_instanced_v_t_curve = R"(
transparency * u_al_bernstein.z +
u_al_bernstein.w; // Get transparency by bezier curve)";
-
const string vertMain_PS_instanced_scale = R"(
position = vec3(u_radiusW * position.x, u_radiusH * position.y, position.z);
position = u_scale * position;
@@ -362,12 +391,12 @@ const string vertMain_PS_instanced_EndAll = R"(
)";
const string vertMain_PS_instanced_EndAll_VertBillboard = R"(
- gl_Position = vec4(position + a_positionP, 1);
+ //gl_Position = vec4(a_position + a_positionP, 1);
+ gl_Position = u_pMatrix * u_vYawPMatrix * vec4(a_position + position, 1.0);
}
)";
-
const string vertMain_PS_EndAll = R"(
// Modelview matrix multiplication with (particle position + particle generator position)
@@ -377,7 +406,7 @@ const string vertMain_PS_EndAll = R"(
)";
const string vertMain_PS_EndAll_VertBillboard = R"(
- gl_Position = vec4(a_position, 1);
+ gl_Position = vec4(a_position, 1);
}
)";
@@ -765,8 +794,6 @@ void main()
)";
//-----------------------------------------------------------------------------
const string fragMain_PS = R"(
-void main()
-{
// Just set the interpolated color from the vertex shader
o_fragColor = v_particleColor;
@@ -776,10 +803,9 @@ void main()
if(o_fragColor.a < 0.001)
discard;
-
)";
-const string fragMain_instanced_PS_begin = R"(
+const string fragMain_PS_begin = R"(
void main()
{
)";
@@ -791,7 +817,20 @@ const string fragMain_PS_withoutColor = R"(
else
o_fragColor = vec4(0,0,0,1.0);
- o_fragColor.a *= transparency;
+ o_fragColor.a *= v_particleColor.a;
+
+ if(o_fragColor.a < 0.001)
+ discard;
+)";
+
+const string fragMain_PS_instanced_withoutColor = R"(
+ // componentwise multiply w. texture color
+ if(!u_doWireFrame)
+ o_fragColor = texture(u_matTextureDiffuse0, v_texCoord);
+ else
+ o_fragColor = vec4(0,0,0,1.0);
+
+ o_fragColor.a *= transparency;
if(o_fragColor.a < 0.001)
discard;
@@ -1750,7 +1789,8 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
*/
void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
string& programName,
- bool isDrawProg)
+ bool isDrawProg,
+ bool instancedRendering)
{
assert(mat && "No material pointer passed!");
programName = "gen";
@@ -1764,6 +1804,10 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
if (isDrawProg) // Drawing program
{
programName += "-Draw";
+
+ if (instancedRendering)
+ programName += "-Inst";
+
programName += mat->texturesString();
GLint billboardType = mat->ps()->billboardType(); // Billboard type (0 -> default; 1 -> vertical billboard, 2 -> horizontal billboard)
bool AlOvLi = mat->ps()->doAlphaOverLT(); // Alpha over life
@@ -2114,7 +2158,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
//-----------------------------------------------------------------------------
void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
{
- assert(_shaders.size() > 2 &&
+ assert(_shaders.size() == 2 &&
_shaders[0]->type() == ST_vertex &&
_shaders[1]->type() == ST_fragment);
@@ -2142,29 +2186,41 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
vertCode += vertInput_PS_a_p; //position
vertCode += vertInput_PS_a_st; // start time
if (rot) vertCode += vertInput_PS_a_r; //rotation as float
- if (FlBoTex) vertCode += vertInput_PS_a_texNum; // per particle texture number
+ if (FlBoTex)
+ {
+ vertCode += vertInput_PS_u_col;
+ vertCode += vertInput_PS_u_row;
+ vertCode += vertInput_PS_a_texNum; // per particle texture number
+ }
// Vertex shader uniforms
vertCode += vertInput_PS_u_ScaRa;
vertCode += vertInput_u_matrix_p;
vertCode += vertInput_PS_u_time;
+
+ if (billboardType == BT_Vertical)
+ vertCode += vertInput_u_matrix_vertBillboard;
+
vertCode += vertInput_u_matrix_vOmv;
+
if (AlOvLi && AlOvLiCu) vertCode += vertInput_PS_u_al_bernstein_alpha;
if (SiOvLi && SiOvLiCu) vertCode += vertInput_PS_u_al_bernstein_size;
- if (Co && CoOvLi) vertCode += vertInput_PS_u_colorOvLF;
// Vertex shader outputs
- if (FlBoTex) vertCode += vertOutput_PS_instanced_texNum;
vertCode += vertOutput_PS_instanced_transparency;
vertCode += vertOutput_PS_v_tC;
- // Vertex shader functions
- if (Co && CoOvLi) vertCode += vertFunction_PS_ColorOverLT;
+ if (CoOvLi) vertCode += vertOutput_PS_age;
+ // Vertex shader functions
// Vertex shader main loop
vertCode += vertMain_instanced_Begin;
vertCode += vertMain_PS_v_a;
- vertCode += vertMain_PS_v_tC;
+ if (FlBoTex)
+ vertCode += vertMain_PS_v_tC_flipbook;
+ else
+ vertCode += vertMain_PS_v_tC;
+
if (AlOvLi)
vertCode += vertMain_PS_instanced_v_t_begin;
else
@@ -2177,10 +2233,9 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
if (SiOvLi && SiOvLiCu) vertCode += vertMain_PS_instanced_v_s_curve;
if (SiOvLi) vertCode += vertMain_PS_instanced_v_sS;
if (rot) vertCode += vertMain_PS_instanced_rotate;
- if (Co && CoOvLi) vertCode += vertMain_PS_v_doColorOverLT;
- if (FlBoTex) vertCode += vertMain_PS_v_texNum;
+ //if (Co && CoOvLi) vertCode += vertMain_PS_v_doColorOverLT;
if (billboardType == BT_Vertical || billboardType == BT_Horizontal)
- vertCode += vertMain_PS_EndAll_VertBillboard;
+ vertCode += vertMain_PS_instanced_EndAll_VertBillboard;
else
vertCode += vertMain_PS_instanced_EndAll;
@@ -2193,11 +2248,15 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
string fragCode;
fragCode += shaderHeader();
- if (Co && !CoOvLi) vertCode += fragInput_PS_u_c;
// Fragment shader inputs
if (FlBoTex) fragCode += fragInput_PS_instanced_texNum;
fragCode += fragInput_PS_v_tC;
if (Co && !CoOvLi) fragCode += fragInput_PS_u_c;
+ if (CoOvLi)
+ { fragCode += fragInput_PS_u_tTL;
+ fragCode += fragInput_PS_age;
+ fragCode += fragInput_PS_u_colorOvLF;
+ }
fragCode += fragInput_PS_instanced_transparency;
// Fragment shader uniforms
@@ -2208,15 +2267,23 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
// Fragment shader outputs
fragCode += fragOutputs_o_fragColor;
+ if (CoOvLi) fragCode += fragFunction_PS_ColorOverLT;
+
// Fragment shader main loop
- fragCode += fragMain_instanced_PS_begin;
+ fragCode += fragMain_PS_begin;
+
+
+ if (Co && !CoOvLi) fragCode += fragMain_PS_instanced_c;
+
+ if (CoOvLi) fragCode += fragMain_PS_instanced_v_doColorOverLT;
+
if (Co || CoOvLi)
{
- fragCode += fragMain_PS_instanced_c;
+ fragCode += fragMain_PS_instanced_transparency;
fragCode += fragMain_instanced_PS_end;
}
else
- fragCode += fragMain_PS_withoutColor;
+ fragCode += fragMain_PS_instanced_withoutColor;
fragCode += fragMain_PS_endAll;
@@ -2281,6 +2348,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
vertCode += vertMain_PS_v_t_begin;
else
vertCode += vertMain_PS_v_t_default;
+
if (AlOvLi) vertCode += AlOvLiCu ? vertMain_PS_v_t_curve : vertMain_PS_v_t_linear;
if (AlOvLi) vertCode += vertMain_PS_v_t_end;
if (rot) vertCode += vertMain_PS_v_r;
@@ -2292,7 +2360,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
vertCode += vertMain_PS_EndAll_VertBillboard;
else
vertCode += vertMain_PS_EndAll;
-
+
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
////////////////////////////////
@@ -2369,9 +2437,10 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
fragCode += fragOutputs_o_fragColor;
// Fragment shader main loop
+ fragCode += fragMain_PS_begin;
fragCode += Co ? fragMain_PS : fragMain_PS_withoutColor;
fragCode += fragMain_PS_endAll;
-
+
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
}
//-----------------------------------------------------------------------------
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index 22865155..b410bbc8 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -98,7 +98,8 @@ class SLGLProgramGenerated : public SLGLProgram
string& programName);
static void buildProgramNamePS(SLMaterial* mat,
string& programName,
- bool isDrawProg);
+ bool isDrawProg,
+ bool instancedRendering);
void buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool isRenderInstanced = false);
void buildProgramCode(SLMaterial* mat,
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index c5751e4c..52c9bb13 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -29,17 +29,17 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
const SLfloat& timeToLive,
SLGLTexture* texC,
const SLstring& name,
- SLGLTexture* texFlipbook) : SLMesh(assetMgr, name)
+ SLGLTexture* texFlipbook,
+ const bool renderInstanced) : SLMesh(assetMgr, name)
{
assert(!name.empty());
// To be added to constructor
- _renderInstanced = true;
+ _renderInstanced = renderInstanced;
+ _primitive = PT_points;
- if (_renderInstanced)
- _primitive = PT_triangles;
- else
- _primitive = PT_points;
+ P.push_back(SLVec3f(0, 0, 0)); // Trick SL project because it want mesh to have vertex
+ I32.push_back(0);
if (amount > UINT_MAX) // Need to change for number of floats
SL_EXIT_MSG("SLParticleSystem supports max. 2^32 vertices.");
@@ -58,6 +58,7 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
_updateTime.init(60, 0.0f);
_drawTime.init(60, 0.0f);
+
}
//-----------------------------------------------------------------------------
//! Function which return a position in a sphere
@@ -312,6 +313,13 @@ void SLParticleSystem::generate()
SLVuint tempTexNum;
SLVVec3f tempInitP;
+ if (_renderInstanced)
+ _primitive = PT_triangles;
+ else
+ _primitive = PT_points;
+
+ deleteDataGpu();
+
tempP.resize(_amount);
tempV.resize(_amount);
tempST.resize(_amount);
@@ -453,6 +461,8 @@ void SLParticleSystem::generate()
if (_renderInstanced)
{
+ P.clear();
+ I32.clear();
/* Generate for billboard (for drawing without geometry shader)*/
P.push_back(SLVec3f(-1, -1, 0));
P.push_back(SLVec3f(1, -1, 0));
@@ -478,11 +488,6 @@ void SLParticleSystem::generate()
_renderVao1.generate((SLuint)P.size());
_renderVao2.generate((SLuint)P.size());
}
- else
- {
- P.push_back(SLVec3f(1, 1, 0));
- I32.push_back(0);
- }
_isGenerated = true;
}
@@ -591,9 +596,10 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
////////////////////
// Generate programs
////////////////////
-
if (!_mat->program() || !_mat->programTF())
+ {
_mat->generateProgramPS(_renderInstanced);
+ }
////////////////////////////////////////////////
// Calculate time and paused and frustum culling
@@ -718,7 +724,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
_vao1.drawArrayAs(PT_points);
_vao1.endTF();
if (_renderInstanced)
- _vao = _renderVao2;
+ _vao = _renderVao1;
else
_vao = _vao2;
}
@@ -880,7 +886,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
///////////////////////
if (_renderInstanced)
- SLMesh::draw(sv, node, _amount*2);
+ SLMesh::draw(sv, node, _amount);
else
SLMesh::draw(sv, node);
///////////////////////
@@ -898,9 +904,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
//! deleteData deletes all mesh data and VAOs
void SLParticleSystem::deleteData()
{
- _vao1.deleteGL();
- _vao2.deleteGL();
- SLMesh::deleteData();
+ return;
}
//-----------------------------------------------------------------------------
//! deleteData deletes all mesh data and VAOs
@@ -908,7 +912,10 @@ void SLParticleSystem::deleteDataGpu()
{
_vao1.deleteGL();
_vao2.deleteGL();
+ _renderVao1.deleteGL();
+ _renderVao2.deleteGL();
SLMesh::deleteDataGpu();
+ _mat->deleteDataGpu();
}
//-----------------------------------------------------------------------------
/*! SLParticleSystem::buildAABB builds the passed axis-aligned bounding box in
diff --git a/modules/sl/source/mesh/SLParticleSystem.h b/modules/sl/source/mesh/SLParticleSystem.h
index c3c1ec62..d856e62f 100644
--- a/modules/sl/source/mesh/SLParticleSystem.h
+++ b/modules/sl/source/mesh/SLParticleSystem.h
@@ -40,7 +40,8 @@ class SLParticleSystem : public SLMesh
const SLfloat& timeToLive,
SLGLTexture* texC,
const SLstring& name = "Particle system",
- SLGLTexture* texFlipbook = nullptr);
+ SLGLTexture* texFlipbook = nullptr,
+ const bool renderInstanced = false);
void draw(SLSceneView* sv, SLNode* node, SLuint instances = 1);
void deleteData();
@@ -52,8 +53,12 @@ class SLParticleSystem : public SLMesh
void changeTexture();
void setNotVisibleInFrustum();
void pauseOrResume();
+ void calcNormals() { N.push_back(SLVec3f(0, 1, 0)); };
+
// Getters
+
+ SLbool renderInstanced() { return _renderInstanced; }
SLVec3f acceleration() { return _acceleration; }
SLfloat accelerationConst() { return _accelerationConst; }
SLint amount() { return _amount; }
@@ -117,6 +122,7 @@ class SLParticleSystem : public SLMesh
SLVec3f velocityRndMax() { return _velocityRndMax; }
// Setters
+ void drawInstanced(bool instanced) {_renderInstanced = instanced; }
void amount(SLint i) { _amount = i; }
void accConst(SLfloat f) { _accelerationConst = f; }
void acceleration(SLVec3f v) { _acceleration = v; }
From 7ffe7273215358b4ad9f059a01adb8c5e5da557e Mon Sep 17 00:00:00 2001
From: luc
Date: Fri, 3 Nov 2023 19:38:14 +0100
Subject: [PATCH 036/108] Fix color over life in instanced particle shader
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 81cec78c..1cd9a6ac 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -322,10 +322,10 @@ const string vertMain_PS_v_doColorOverLT = R"(
vert.color = colorByAge(age/u_tTL);)";
const string vertOutput_PS_age = R"(
- out float v_age; // Age of a particle)";
+out float v_age; // Age of a particle)";
const string fragInput_PS_age = R"(
- in float v_age; // Age of a particle)";
+in float v_age; // Age of a particle)";
const string vertMain_PS_v_color = R"(
vert.color = u_color.rgb;)";
@@ -333,15 +333,15 @@ const string vertMain_PS_v_color = R"(
const string vertMain_PS_v_texNum = R"(
vert.texNum = a_texNum;)";
-const string vertMain_PS_instanced_v_texNum = R"(
- texNum = a_texNum;)";
-
const string vertMain_PS_v_a = R"(
float age = u_time - a_startTime; // Get the age of the particle)";
const string vertMain_PS_v_tC = R"(
v_texCoord = 0.5 * (a_positionP.xy + vec2(1.0));)";
+const string vertMain_PS_v_age = R"(
+ v_age = age;)";
+
const string vertMain_PS_v_tC_flipbook = R"(
uint actCI = uint(mod(float(a_texNum), float(u_col)));
uint actRI = (a_texNum - actCI) / u_col;
@@ -2212,7 +2212,6 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
if (CoOvLi) vertCode += vertOutput_PS_age;
- // Vertex shader functions
// Vertex shader main loop
vertCode += vertMain_instanced_Begin;
vertCode += vertMain_PS_v_a;
@@ -2227,13 +2226,13 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
vertCode += vertMain_PS_instanced_v_t_default;
if (AlOvLi) vertCode += AlOvLiCu ? vertMain_PS_instanced_v_t_curve : vertMain_PS_instanced_v_t_linear;
if (AlOvLi) vertCode += vertMain_PS_v_t_end;
- //if (rot) vertCode += vertMain_PS_v_r;
vertCode += vertMain_PS_instanced_scale;
if (SiOvLi) vertCode += vertMain_PS_instanced_v_s;
if (SiOvLi && SiOvLiCu) vertCode += vertMain_PS_instanced_v_s_curve;
if (SiOvLi) vertCode += vertMain_PS_instanced_v_sS;
if (rot) vertCode += vertMain_PS_instanced_rotate;
- //if (Co && CoOvLi) vertCode += vertMain_PS_v_doColorOverLT;
+ if (CoOvLi) vertCode += vertMain_PS_v_age;
+
if (billboardType == BT_Vertical || billboardType == BT_Horizontal)
vertCode += vertMain_PS_instanced_EndAll_VertBillboard;
else
@@ -2360,7 +2359,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
vertCode += vertMain_PS_EndAll_VertBillboard;
else
vertCode += vertMain_PS_EndAll;
-
+
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
////////////////////////////////
@@ -2440,7 +2439,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
fragCode += fragMain_PS_begin;
fragCode += Co ? fragMain_PS : fragMain_PS_withoutColor;
fragCode += fragMain_PS_endAll;
-
+
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
}
//-----------------------------------------------------------------------------
From 77d7c2b077333751ef184a43d51230b096488d1f Mon Sep 17 00:00:00 2001
From: luc
Date: Mon, 6 Nov 2023 11:14:49 +0100
Subject: [PATCH 037/108] comment and small modif
---
modules/sl/source/mesh/SLParticleSystem.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index 52c9bb13..bef75869 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -886,7 +886,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
///////////////////////
if (_renderInstanced)
- SLMesh::draw(sv, node, _amount);
+ SLMesh::draw(sv, node, 2*_amount); //2 triangles per particle
else
SLMesh::draw(sv, node);
///////////////////////
From 6fb69e03e7f748f121b6dd492986a4ebea145847 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 11:36:16 +0100
Subject: [PATCH 038/108] [WebGPU] Add 3d cube to demo
---
apps/webgpu/CMakeLists.txt | 2 +-
apps/webgpu/main.cpp | 335 ++++++++++++++++++++++++++++++-------
2 files changed, 272 insertions(+), 65 deletions(-)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 373f3bec..0c747f93 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -56,7 +56,7 @@ elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
endif ()
add_executable(webgpu-demo main.cpp)
-target_link_libraries(webgpu-demo PRIVATE wgpu sl_cv ${glfw_LIBS})
+target_link_libraries(webgpu-demo PRIVATE wgpu sl_cv sl_math ${glfw_LIBS})
if (SYSTEM_NAME_UPPER MATCHES "LINUX")
target_link_libraries(webgpu-demo PRIVATE "X11")
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index ccad5570..0a57aef4 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -23,11 +23,13 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
@@ -38,6 +40,15 @@
std::exit(1); \
}
+struct alignas(16) ShaderUniformData
+{
+ float projectionMatrix[16];
+ float viewMatrix[16];
+ float modelMatrix[16];
+};
+
+static_assert(sizeof(ShaderUniformData) % 16 == 0, "uniform data size must be a multiple of 16");
+
void handleAdapterRequest(WGPURequestAdapterStatus status,
WGPUAdapter adapter,
char const* message,
@@ -104,18 +115,19 @@ int main(int argc, const char* argv[])
// which is how WebGPU prevents code from working on one machine and not on another.
WGPURequiredLimits requiredLimits = {};
- requiredLimits.limits.maxVertexAttributes = 1u;
+ requiredLimits.limits.maxVertexAttributes = 2u;
requiredLimits.limits.maxVertexBuffers = 1u;
- requiredLimits.limits.maxBufferSize = 4ull * 2ull * sizeof(float);
- requiredLimits.limits.maxVertexBufferArrayStride = 2u * sizeof(float);
+ requiredLimits.limits.maxBufferSize = 1024ull;
+ requiredLimits.limits.maxVertexBufferArrayStride = 5u * sizeof(float);
requiredLimits.limits.maxInterStageShaderComponents = 2u;
- requiredLimits.limits.maxBindGroups = 2u;
- requiredLimits.limits.maxBindingsPerBindGroup = 2u;
+ requiredLimits.limits.maxBindGroups = 1u;
+ requiredLimits.limits.maxBindingsPerBindGroup = 3u;
requiredLimits.limits.maxUniformBuffersPerShaderStage = 1u;
- requiredLimits.limits.maxUniformBufferBindingSize = 16ull * 4ull;
+ requiredLimits.limits.maxUniformBufferBindingSize = 512ull;
requiredLimits.limits.maxSampledTexturesPerShaderStage = 1u;
- requiredLimits.limits.maxTextureDimension1D = 2048;
- requiredLimits.limits.maxTextureDimension2D = 2048;
+ requiredLimits.limits.maxSamplersPerShaderStage = 1u;
+ requiredLimits.limits.maxTextureDimension1D = 4096;
+ requiredLimits.limits.maxTextureDimension2D = 4096;
requiredLimits.limits.maxTextureArrayLayers = 1;
requiredLimits.limits.minStorageBufferOffsetAlignment = adapterLimits.limits.minStorageBufferOffsetAlignment;
requiredLimits.limits.minUniformBufferOffsetAlignment = adapterLimits.limits.minUniformBufferOffsetAlignment;
@@ -201,14 +213,57 @@ int main(int argc, const char* argv[])
// clang-format off
std::vector vertexData =
{
- -0.5, 0.5, // top-left corner
- -0.5, -0.5, // bottom-left corner
- 0.5, 0.5, // top-right corner
- 0.5, -0.5, // bottom-right corner
+ // left
+ -0.5, 0.5, -0.5, 0.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, -0.5, 0.5, 1.0f, 1.0f,
+
+ // right
+ 0.5, 0.5, 0.5, 0.0f, 0.0f,
+ 0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // bottom
+ -0.5, -0.5, 0.5, 0.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ 0.5, -0.5, 0.5, 1.0f, 0.0f,
+ 0.5, -0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ 0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // top
+ -0.5, 0.5, -0.5, 0.0f, 0.0f,
+ -0.5, 0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ -0.5, 0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, 0.5, 1.0f, 1.0f,
+
+ // back
+ 0.5, 0.5, -0.5, 0.0f, 0.0f,
+ 0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, 0.5, -0.5, 1.0f, 0.0f,
+ -0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // front
+ -0.5, 0.5, 0.5, 0.0f, 0.0f,
+ -0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, 0.5, 1.0f, 0.0f,
+ 0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, -0.5, 0.5, 1.0f, 1.0f,
};
// clang-format on
- unsigned vertexCount = vertexData.size() / 2;
+ unsigned vertexCount = vertexData.size() / 5;
unsigned vertexDataSize = vertexData.size() * sizeof(float);
WGPUBufferDescriptor vertexBufferDesc = {};
@@ -225,13 +280,9 @@ int main(int argc, const char* argv[])
// === Create the index buffer ===
- // clang-format off
- std::vector indexData =
- {
- 0, 1, 2,
- 2, 1, 3,
- };
- // clang-format on
+ std::vector indexData = {};
+ for (std::uint16_t index = 0; index < 36; index++)
+ indexData.push_back(index);
unsigned indexCount = indexData.size();
unsigned indexDataSize = indexData.size() * sizeof(std::uint16_t);
@@ -251,23 +302,56 @@ int main(int argc, const char* argv[])
WGPUBufferDescriptor uniformBufferDesc = {};
uniformBufferDesc.label = "Demo Uniform Buffer";
- uniformBufferDesc.size = sizeof(float);
+ uniformBufferDesc.size = sizeof(ShaderUniformData);
uniformBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer(device, &uniformBufferDesc);
WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create uniform buffer");
WEBGPU_DEMO_LOG("[WebGPU] Uniform buffer created");
- float uniformBufferData = 0.0f;
- wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformBufferData, sizeof(float));
+ ShaderUniformData uniformData = {};
+ wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
+
+ // === Create the depth texture ===
+
+ WGPUTextureFormat depthTextureFormat = WGPUTextureFormat_Depth24Plus;
+
+ WGPUTextureDescriptor depthTextureDesc = {};
+ depthTextureDesc.dimension = WGPUTextureDimension_2D;
+ depthTextureDesc.format = depthTextureFormat;
+ depthTextureDesc.mipLevelCount = 1;
+ depthTextureDesc.sampleCount = 1;
+ depthTextureDesc.size.width = surfaceWidth;
+ depthTextureDesc.size.height = surfaceHeight;
+ depthTextureDesc.size.depthOrArrayLayers = 1;
+ depthTextureDesc.usage = WGPUTextureUsage_RenderAttachment;
+ depthTextureDesc.viewFormatCount = 1;
+ depthTextureDesc.viewFormats = &depthTextureFormat;
+
+ WGPUTexture depthTexture = wgpuDeviceCreateTexture(device, &depthTextureDesc);
+ WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to create depth texture");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture created");
+
+ WGPUTextureViewDescriptor depthTextureViewDesc = {};
+ depthTextureViewDesc.aspect = WGPUTextureAspect_DepthOnly;
+ depthTextureViewDesc.baseArrayLayer = 0;
+ depthTextureViewDesc.arrayLayerCount = 1;
+ depthTextureViewDesc.baseMipLevel = 0;
+ depthTextureViewDesc.mipLevelCount = 1;
+ depthTextureViewDesc.dimension = WGPUTextureViewDimension_2D;
+ depthTextureViewDesc.format = depthTextureFormat;
+
+ WGPUTextureView depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
+ WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to create depth texture view");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture view created");
// === Create the texture ===
cv::Mat image = cv::imread(std::string(SL_PROJECT_ROOT) + "/data/images/textures/brickwall0512_C.jpg");
cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);
- unsigned imageWidth = image.cols;
- unsigned imageHeight = image.rows;
+ unsigned imageWidth = image.cols;
+ unsigned imageHeight = image.rows;
unsigned pixelDataSize = 4 * imageWidth * imageHeight;
WGPUTextureDescriptor textureDesc = {};
@@ -317,33 +401,67 @@ int main(int argc, const char* argv[])
WEBGPU_DEMO_CHECK(textureView, "[WebGPU] Failed to create texture view");
WEBGPU_DEMO_LOG("[WebGPU] Texture view created");
+ // === Create the texture sampler ===
+ // The sampler is used to look up values of the texture in the shader.
+ // We could look up values directly without a sampler, but with a sampler we
+ // get access to features like interpolation and mipmapping.
+
+ WGPUSamplerDescriptor samplerDesc = {};
+ samplerDesc.addressModeU = WGPUAddressMode_ClampToEdge;
+ samplerDesc.addressModeV = WGPUAddressMode_ClampToEdge;
+ samplerDesc.addressModeW = WGPUAddressMode_ClampToEdge;
+ samplerDesc.magFilter = WGPUFilterMode_Linear;
+ samplerDesc.minFilter = WGPUFilterMode_Linear;
+ samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
+ samplerDesc.lodMinClamp = 0.0f;
+ samplerDesc.lodMaxClamp = 1.0f;
+ samplerDesc.compare = WGPUCompareFunction_Undefined;
+ samplerDesc.maxAnisotropy = 1;
+
+ WGPUSampler sampler = wgpuDeviceCreateSampler(device, &samplerDesc);
+ WEBGPU_DEMO_CHECK(sampler, "[WebGPU] Failed to create sampler");
+ WEBGPU_DEMO_LOG("[WebGPU] Sampler created");
+
// === Create the shader module ===
// Create a shader module for use in our render pipeline.
// Shaders are written in a WebGPU-specific language called WGSL (WebGPU shader language).
// Shader modules can be used in multiple pipeline stages by specifying different entry points.
const char* shaderSource = R"(
- @group(0) @binding(0) var u_time: f32;
- @group(0) @binding(1) var texture: texture_2d;
+ struct VertexInput {
+ @location(0) position: vec3f,
+ @location(1) uvs: vec2f,
+ };
+
+ struct Uniforms {
+ projectionMatrix: mat4x4f,
+ viewMatrix: mat4x4f,
+ modelMatrix: mat4x4f,
+ };
struct VertexOutput {
@builtin(position) position: vec4f,
- @location(0) texture_coords: vec2f,
+ @location(0) uvs: vec2f,
}
+
+ @group(0) @binding(0) var uniforms: Uniforms;
+ @group(0) @binding(1) var texture: texture_2d;
+ @group(0) @binding(2) var textureSampler: sampler;
@vertex
- fn vs_main(@location(0) in_vertex_position: vec2f) -> VertexOutput {
- var offset = vec2(0.5 * sin(u_time), 0.5 * cos(u_time));
-
+ fn vs_main(in: VertexInput) -> VertexOutput {
+ var localPos = vec4f(in.position, 1.0);
+ var worldPos = uniforms.modelMatrix * localPos;
+
var out: VertexOutput;
- out.position = vec4f(in_vertex_position + offset, 0.0, 1.0);
- out.texture_coords = in_vertex_position + vec2(0.5, 0.5);
+ out.position = uniforms.projectionMatrix * uniforms.viewMatrix * worldPos;
+ out.uvs = in.uvs;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
- return textureLoad(texture, vec2i(i32(512.0 * in.texture_coords.x), i32(512.0 * in.texture_coords.y)), 0).rgba;
+ return textureSample(texture, textureSampler, in.uvs).rgba;
}
)";
@@ -363,20 +481,28 @@ int main(int argc, const char* argv[])
// Bind groups contain binding layouts that describe how uniforms and textures are passed to shaders.
// Entry for the uniform
- WGPUBindGroupLayoutEntry uniformLayout = {};
- uniformLayout.binding = 0;
- uniformLayout.visibility = WGPUShaderStage_Vertex;
- uniformLayout.buffer.type = WGPUBufferBindingType_Uniform;
- uniformLayout.buffer.minBindingSize = sizeof(float);
+ WGPUBindGroupLayoutEntry uniformBindLayout = {};
+ uniformBindLayout.binding = 0;
+ uniformBindLayout.visibility = WGPUShaderStage_Vertex;
+ uniformBindLayout.buffer.type = WGPUBufferBindingType_Uniform;
+ uniformBindLayout.buffer.minBindingSize = sizeof(ShaderUniformData);
// Entry for the texture
- WGPUBindGroupLayoutEntry textureLayout = {};
- textureLayout.binding = 1;
- textureLayout.visibility = WGPUShaderStage_Fragment;
- textureLayout.texture.sampleType = WGPUTextureSampleType_Float;
- textureLayout.texture.viewDimension = WGPUTextureViewDimension_2D;
-
- std::vector bindGroupLayoutEntries = {uniformLayout, textureLayout};
+ WGPUBindGroupLayoutEntry textureBindLayout = {};
+ textureBindLayout.binding = 1;
+ textureBindLayout.visibility = WGPUShaderStage_Fragment;
+ textureBindLayout.texture.sampleType = WGPUTextureSampleType_Float;
+ textureBindLayout.texture.viewDimension = WGPUTextureViewDimension_2D;
+
+ // Entry for the sampler
+ WGPUBindGroupLayoutEntry samplerBindLayout = {};
+ samplerBindLayout.binding = 2;
+ samplerBindLayout.visibility = WGPUShaderStage_Fragment;
+ samplerBindLayout.sampler.type = WGPUSamplerBindingType_Filtering;
+
+ std::vector bindGroupLayoutEntries = {uniformBindLayout,
+ textureBindLayout,
+ samplerBindLayout};
WGPUBindGroupLayoutDescriptor bindGroupLayoutDesc = {};
bindGroupLayoutDesc.label = "Demo Bind Group Layout";
@@ -390,16 +516,22 @@ int main(int argc, const char* argv[])
// The bind group actually binds the buffer to uniforms and textures.
WGPUBindGroupEntry uniformBinding = {};
- uniformBinding.binding = 0;
- uniformBinding.buffer = uniformBuffer;
- uniformBinding.offset = 0;
- uniformBinding.size = sizeof(float);
+ uniformBinding.binding = 0;
+ uniformBinding.buffer = uniformBuffer;
+ uniformBinding.offset = 0;
+ uniformBinding.size = sizeof(ShaderUniformData);
WGPUBindGroupEntry textureBinding = {};
- textureBinding.binding = 1;
- textureBinding.textureView = textureView;
+ textureBinding.binding = 1;
+ textureBinding.textureView = textureView;
+
+ WGPUBindGroupEntry samplerBinding = {};
+ samplerBinding.binding = 2;
+ samplerBinding.sampler = sampler;
- std::vector bindGroupEntries = {uniformBinding, textureBinding};
+ std::vector bindGroupEntries = {uniformBinding,
+ textureBinding,
+ samplerBinding};
WGPUBindGroupDescriptor bindGroupDesc = {};
bindGroupDesc.layout = bindGroupLayout;
@@ -424,18 +556,25 @@ int main(int argc, const char* argv[])
// The render pipeline specifies the configuration for the fixed-function stages as well as
// the shaders for the programmable stages of the hardware pipeline.
- // Description of the vertex attribute for the vertex buffer layout
- WGPUVertexAttribute vertexAttribute = {};
- vertexAttribute.format = WGPUVertexFormat_Float32x2;
- vertexAttribute.offset = 0;
- vertexAttribute.shaderLocation = 0;
+ // Description of the vertex attributes for the vertex buffer layout
+ WGPUVertexAttribute positionAttribute = {};
+ positionAttribute.format = WGPUVertexFormat_Float32x3;
+ positionAttribute.offset = 0;
+ positionAttribute.shaderLocation = 0;
+
+ WGPUVertexAttribute uvsAttribute = {};
+ uvsAttribute.format = WGPUVertexFormat_Float32x2;
+ uvsAttribute.offset = 3 * sizeof(float);
+ uvsAttribute.shaderLocation = 1;
+
+ std::vector vertexAttributes = {positionAttribute, uvsAttribute};
// Description of the vertex buffer layout for the vertex shader stage
WGPUVertexBufferLayout vertexBufferLayout = {};
- vertexBufferLayout.arrayStride = 2ull * sizeof(float);
+ vertexBufferLayout.arrayStride = 5ull * sizeof(float);
vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
- vertexBufferLayout.attributeCount = 1;
- vertexBufferLayout.attributes = &vertexAttribute;
+ vertexBufferLayout.attributeCount = vertexAttributes.size();
+ vertexBufferLayout.attributes = vertexAttributes.data();
// Configuration for the vertex shader stage
WGPUVertexState vertexState = {};
@@ -451,6 +590,22 @@ int main(int argc, const char* argv[])
primitiveState.frontFace = WGPUFrontFace_CCW;
primitiveState.cullMode = WGPUCullMode_None;
+ // Configuration for depth testing and stencil buffer
+ WGPUDepthStencilState depthStencilState = {};
+ depthStencilState.format = depthTextureFormat;
+ depthStencilState.depthWriteEnabled = true;
+ depthStencilState.depthCompare = WGPUCompareFunction_Less;
+ depthStencilState.stencilReadMask = 0;
+ depthStencilState.stencilWriteMask = 0;
+ depthStencilState.stencilFront.compare = WGPUCompareFunction_Always;
+ depthStencilState.stencilFront.failOp = WGPUStencilOperation_Keep;
+ depthStencilState.stencilFront.depthFailOp = WGPUStencilOperation_Keep;
+ depthStencilState.stencilFront.passOp = WGPUStencilOperation_Keep;
+ depthStencilState.stencilBack.compare = WGPUCompareFunction_Always;
+ depthStencilState.stencilBack.failOp = WGPUStencilOperation_Keep;
+ depthStencilState.stencilBack.depthFailOp = WGPUStencilOperation_Keep;
+ depthStencilState.stencilBack.passOp = WGPUStencilOperation_Keep;
+
// Configuration for multisampling
WGPUMultisampleState multisampleState = {};
multisampleState.count = 1;
@@ -472,6 +627,7 @@ int main(int argc, const char* argv[])
pipelineDesc.layout = pipelineLayout;
pipelineDesc.vertex = vertexState;
pipelineDesc.primitive = primitiveState;
+ pipelineDesc.depthStencil = &depthStencilState;
pipelineDesc.multisample = multisampleState;
pipelineDesc.fragment = &fragmentState;
@@ -479,6 +635,8 @@ int main(int argc, const char* argv[])
WEBGPU_DEMO_CHECK(pipeline, "[WebGPU] Failed to create render pipeline");
WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
+ float rotation = 0.0f;
+
// === Render loop ===
while (!glfwWindowShouldClose(window))
@@ -515,6 +673,23 @@ int main(int argc, const char* argv[])
surfaceConfig.width = surfaceWidth;
surfaceConfig.height = surfaceHeight;
wgpuSurfaceConfigure(surface, &surfaceConfig);
+
+ // Recreate the depth texture.
+
+ wgpuTextureViewRelease(textureView);
+ wgpuTextureDestroy(depthTexture);
+ wgpuTextureRelease(depthTexture);
+
+ depthTextureDesc.size.width = surfaceWidth;
+ depthTextureDesc.size.height = surfaceHeight;
+
+ depthTexture = wgpuDeviceCreateTexture(device, &depthTextureDesc);
+ WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to re-create depth texture");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture re-created");
+
+ depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
+ WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to re-create depth texture view");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
}
// Skip this frame.
@@ -534,9 +709,24 @@ int main(int argc, const char* argv[])
// Create a view into the texture to specify where and how to modify the texture.
WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
- // === Update the uniform ===
- float time = static_cast(glfwGetTime());
- wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &time, sizeof(float));
+ // === Prepare uniform data ===
+ float aspectRatio = static_cast(surfaceWidth) / static_cast(surfaceHeight);
+
+ SLMat4f projectionMatrix;
+ projectionMatrix.perspective(70.0f, aspectRatio, 0.1, 1000.0f);
+
+ SLMat4f viewMatrix;
+ viewMatrix.translate(0.0f, 0.0f, -2.0f);
+
+ SLMat4f modelMatrix;
+ modelMatrix.rotation(90.0f * static_cast(glfwGetTime()), SLVec3f::AXISY);
+
+ // === Update uniforms ===
+ ShaderUniformData uniformData = {};
+ std::memcpy(uniformData.projectionMatrix, projectionMatrix.m(), sizeof(uniformData.projectionMatrix));
+ std::memcpy(uniformData.viewMatrix, viewMatrix.m(), sizeof(uniformData.viewMatrix));
+ std::memcpy(uniformData.modelMatrix, modelMatrix.m(), sizeof(uniformData.modelMatrix));
+ wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
// === Create a WebGPU command encoder ===
// The encoder encodes the commands for the GPU into a command buffer.
@@ -551,6 +741,7 @@ int main(int argc, const char* argv[])
// The render pass specifies what attachments to use while rendering.
// A color attachment specifies what view to render into and what to do with the texture before and after
// rendering. We clear the texture before rendering and store the results after rendering.
+ // The depth attachment specifies what depth texture to use.
WGPURenderPassColorAttachment colorAttachment = {};
colorAttachment.view = view;
@@ -561,10 +752,22 @@ int main(int argc, const char* argv[])
colorAttachment.clearValue.b = 0.2;
colorAttachment.clearValue.a = 1.0;
+ WGPURenderPassDepthStencilAttachment depthStencilAttachment = {};
+ depthStencilAttachment.view = depthTextureView;
+ depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
+ depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
+ depthStencilAttachment.depthClearValue = 1.0f;
+ depthStencilAttachment.depthReadOnly = false;
+ depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
+ depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
+ depthStencilAttachment.stencilClearValue = 0.0f;
+ depthStencilAttachment.stencilReadOnly = true;
+
WGPURenderPassDescriptor renderPassDesc = {};
renderPassDesc.label = "Demo Render Pass";
renderPassDesc.colorAttachmentCount = 1;
renderPassDesc.colorAttachments = &colorAttachment;
+ renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
// === Encode the commands ===
// The commands to begin a render pass, bind a pipeline, draw the triangle and end the render pass
@@ -611,9 +814,13 @@ int main(int argc, const char* argv[])
wgpuBindGroupRelease(bindGroup);
wgpuBindGroupLayoutRelease(bindGroupLayout);
wgpuShaderModuleRelease(shaderModule);
+ wgpuSamplerRelease(sampler);
wgpuTextureViewRelease(textureView);
wgpuTextureDestroy(texture);
wgpuTextureRelease(texture);
+ wgpuTextureViewRelease(depthTextureView);
+ wgpuTextureDestroy(depthTexture);
+ wgpuTextureRelease(depthTexture);
wgpuBufferDestroy(uniformBuffer);
wgpuBufferRelease(uniformBuffer);
wgpuBufferDestroy(indexBuffer);
From 7aa30d574dcbff1bd35524c4154ba340b0e18128 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 13:11:40 +0100
Subject: [PATCH 039/108] [WebGPU] Add mipmapping to demo
---
apps/webgpu/main.cpp | 87 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 77 insertions(+), 10 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 0a57aef4..3173eeeb 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
@@ -362,7 +363,7 @@ int main(int argc, const char* argv[])
textureDesc.size.height = imageHeight;
textureDesc.size.depthOrArrayLayers = 1;
textureDesc.format = WGPUTextureFormat_RGBA8UnormSrgb;
- textureDesc.mipLevelCount = 1;
+ textureDesc.mipLevelCount = 4;
textureDesc.sampleCount = 1;
WGPUTexture texture = wgpuDeviceCreateTexture(device, &textureDesc);
@@ -384,8 +385,51 @@ int main(int argc, const char* argv[])
pixelDataLayout.bytesPerRow = 4 * textureDesc.size.width;
pixelDataLayout.rowsPerImage = textureDesc.size.height;
- // Upload the data to the GPU.
- wgpuQueueWriteTexture(queue, &destination, image.data, pixelDataSize, &pixelDataLayout, &textureDesc.size);
+ // Generate mip levels.
+
+ WGPUExtent3D mipLevelSize;
+ mipLevelSize.width = textureDesc.size.width;
+ mipLevelSize.height = textureDesc.size.height;
+ mipLevelSize.depthOrArrayLayers = 1;
+
+ for (unsigned mipLevel = 0; mipLevel < textureDesc.mipLevelCount; mipLevel++)
+ {
+ // === Test colors ===
+ //
+ // std::uint64_t mipLevelColors[] =
+ // {
+ // 0xFF0000FF,
+ // 0xFFFF00FF,
+ // 0x00FF00FF,
+ // 0x0000FFFF
+ // };
+ //
+ // for (unsigned y = 0; y < mipLevelSize.height; y++)
+ // {
+ // for (unsigned x = 0; x < mipLevelSize.width; x++)
+ // {
+ // unsigned pixelIndex = x + y * mipLevelSize.width;
+ // std::memcpy(&mipLevelData[4ull * pixelIndex], &mipLevelColors[mipLevel], 4);
+ // }
+ // }
+
+ cv::Mat mipLevelImage;
+ cv::Size cvSize(static_cast(mipLevelSize.width), static_cast(mipLevelSize.height));
+ cv::resize(image, mipLevelImage, cvSize);
+
+ std::size_t mipLevelBytes = 4ull * mipLevelSize.width * mipLevelSize.height;
+
+ destination.mipLevel = mipLevel;
+ pixelDataLayout.bytesPerRow = 4 * mipLevelSize.width;
+ pixelDataLayout.rowsPerImage = mipLevelSize.height;
+
+ // Upload the data to the GPU.
+ wgpuQueueWriteTexture(queue, &destination, mipLevelImage.data, mipLevelBytes, &pixelDataLayout, &mipLevelSize);
+
+ // Scale the image down for the next mip level.
+ mipLevelSize.width /= 2;
+ mipLevelSize.height /= 2;
+ }
// === Create a texture view into the texture ===
WGPUTextureViewDescriptor textureViewDesc = {};
@@ -393,7 +437,7 @@ int main(int argc, const char* argv[])
textureViewDesc.baseArrayLayer = 0;
textureViewDesc.arrayLayerCount = 1;
textureViewDesc.baseMipLevel = 0;
- textureViewDesc.mipLevelCount = 1;
+ textureViewDesc.mipLevelCount = textureDesc.mipLevelCount;
textureViewDesc.dimension = WGPUTextureViewDimension_2D;
textureViewDesc.format = textureDesc.format;
@@ -414,9 +458,9 @@ int main(int argc, const char* argv[])
samplerDesc.minFilter = WGPUFilterMode_Linear;
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
samplerDesc.lodMinClamp = 0.0f;
- samplerDesc.lodMaxClamp = 1.0f;
+ samplerDesc.lodMaxClamp = static_cast(textureDesc.mipLevelCount);
samplerDesc.compare = WGPUCompareFunction_Undefined;
- samplerDesc.maxAnisotropy = 1;
+ samplerDesc.maxAnisotropy = 1.0f;
WGPUSampler sampler = wgpuDeviceCreateSampler(device, &samplerDesc);
WEBGPU_DEMO_CHECK(sampler, "[WebGPU] Failed to create sampler");
@@ -635,12 +679,38 @@ int main(int argc, const char* argv[])
WEBGPU_DEMO_CHECK(pipeline, "[WebGPU] Failed to create render pipeline");
WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
- float rotation = 0.0f;
+ SLMat4f modelMatrix;
+
+ double lastCursorX = 0.0f;
+ double lastCursorY = 0.0f;
// === Render loop ===
while (!glfwWindowShouldClose(window))
{
+ // === Update cube model matrix ===
+
+ double cursorX;
+ double cursorY;
+ glfwGetCursorPos(window, &cursorX, &cursorY);
+
+ SLMat4f rotationX;
+ SLMat4f rotationY;
+
+ if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS)
+ {
+ float deltaRotX = 0.5f * static_cast(cursorY - lastCursorY);
+ float deltaRotY = 0.5f * static_cast(cursorX - lastCursorX);
+
+ rotationX.rotate(deltaRotX, SLVec3f::AXISX);
+ rotationY.rotate(deltaRotY, SLVec3f::AXISY);
+ }
+
+ modelMatrix = rotationY * rotationX * modelMatrix;
+
+ lastCursorX = cursorX;
+ lastCursorY = cursorY;
+
// === Create a WebGPU texture view ===
// The texture view is where we render our image into.
@@ -718,9 +788,6 @@ int main(int argc, const char* argv[])
SLMat4f viewMatrix;
viewMatrix.translate(0.0f, 0.0f, -2.0f);
- SLMat4f modelMatrix;
- modelMatrix.rotation(90.0f * static_cast(glfwGetTime()), SLVec3f::AXISY);
-
// === Update uniforms ===
ShaderUniformData uniformData = {};
std::memcpy(uniformData.projectionMatrix, projectionMatrix.m(), sizeof(uniformData.projectionMatrix));
From e6ad617ba7abce5a73c27bdbee96e91e017a378c Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 13:14:05 +0100
Subject: [PATCH 040/108] [WebGPU] Re-configure suboptimal surfaces in demo
---
apps/webgpu/main.cpp | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 3173eeeb..4939f53e 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -725,7 +725,20 @@ int main(int argc, const char* argv[])
{
case WGPUSurfaceGetCurrentTextureStatus_Success:
// Everything is ok.
- // TODO: check for a suboptimal texture and re-configure it if needed.
+
+ // Check for a suboptimal texture and re-configure it if needed.
+ if (surfaceTexture.suboptimal)
+ {
+ WEBGPU_DEMO_LOG("[WebGPU] Re-configuring currently suboptimal surface");
+ surfaceConfig.width = surfaceWidth;
+ surfaceConfig.height = surfaceHeight;
+ wgpuSurfaceConfigure(surface, &surfaceConfig);
+
+ // Skip this frame.
+ glfwPollEvents();
+ continue;
+ }
+
break;
case WGPUSurfaceGetCurrentTextureStatus_Timeout:
From 2f3e6c40b9d462b362f68e19671c69cd55fcbfca Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 15:14:33 +0100
Subject: [PATCH 041/108] [WebGPU] Use new Objective-C runtime declarations in
demo
---
apps/webgpu/main.cpp | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 4939f53e..2b63ec6b 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -11,7 +11,6 @@
# define GLFW_EXPOSE_NATIVE_COCOA
# define GLFW_NATIVE_INCLUDE_NONE
-# define OBJC_OLD_DISPATCH_PROTOTYPES 1
# include
# include
# include
@@ -165,12 +164,18 @@ int main(int argc, const char* argv[])
#elif defined(SYSTEM_DARWIN)
id cocoaWindow = glfwGetCocoaWindow(window);
- id contentView = objc_msgSend(cocoaWindow, sel_registerName("contentView"));
- objc_msgSend(contentView, sel_getUid("setWantsLayer:"), 1);
+ // We call the Objective-C runtime directly to get the Metal surface.
+
+ // We need to cast 'objc_msgSend' to appropiate function pointer types before calling them.
+ auto* sendMessageReturnId = (id(*)(id, ...))objc_msgSend;
+ auto* sendMessageReturnNothing = (void (*)(id, ...))objc_msgSend;
+
+ id contentView = sendMessageReturnId(cocoaWindow, sel_getUid("contentView"));
+ sendMessageReturnNothing(contentView, sel_getUid("setWantsLayer:"), 1);
objc_class* metalLayerClass = objc_getClass("CAMetalLayer");
- id metalLayer = objc_msgSend((id)metalLayerClass, sel_getUid("layer"));
- objc_msgSend(contentView, sel_registerName("setLayer:"), metalLayer);
+ id metalLayer = sendMessageReturnId((id)metalLayerClass, sel_getUid("layer"));
+ sendMessageReturnNothing(contentView, sel_registerName("setLayer:"), metalLayer);
WGPUSurfaceDescriptorFromMetalLayer nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
@@ -388,8 +393,8 @@ int main(int argc, const char* argv[])
// Generate mip levels.
WGPUExtent3D mipLevelSize;
- mipLevelSize.width = textureDesc.size.width;
- mipLevelSize.height = textureDesc.size.height;
+ mipLevelSize.width = textureDesc.size.width;
+ mipLevelSize.height = textureDesc.size.height;
mipLevelSize.depthOrArrayLayers = 1;
for (unsigned mipLevel = 0; mipLevel < textureDesc.mipLevelCount; mipLevel++)
@@ -403,17 +408,17 @@ int main(int argc, const char* argv[])
// 0x00FF00FF,
// 0x0000FFFF
// };
- //
+ //
// for (unsigned y = 0; y < mipLevelSize.height; y++)
// {
// for (unsigned x = 0; x < mipLevelSize.width; x++)
// {
// unsigned pixelIndex = x + y * mipLevelSize.width;
// std::memcpy(&mipLevelData[4ull * pixelIndex], &mipLevelColors[mipLevel], 4);
- // }
+ // }
// }
- cv::Mat mipLevelImage;
+ cv::Mat mipLevelImage;
cv::Size cvSize(static_cast(mipLevelSize.width), static_cast(mipLevelSize.height));
cv::resize(image, mipLevelImage, cvSize);
@@ -725,7 +730,7 @@ int main(int argc, const char* argv[])
{
case WGPUSurfaceGetCurrentTextureStatus_Success:
// Everything is ok.
-
+
// Check for a suboptimal texture and re-configure it if needed.
if (surfaceTexture.suboptimal)
{
From f35025373c1d8dad65fc386854d65070b368daf1 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 15:17:47 +0100
Subject: [PATCH 042/108] [WebGPU] Use FIFO present mode in demo
---
apps/webgpu/main.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 2b63ec6b..efc71100 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -206,7 +206,7 @@ int main(int argc, const char* argv[])
surfaceConfig.device = device;
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
surfaceConfig.format = surfaceCapabilities.formats[0];
- surfaceConfig.presentMode = WGPUPresentMode_Mailbox;
+ surfaceConfig.presentMode = WGPUPresentMode_Fifo;
surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
surfaceConfig.width = surfaceWidth;
surfaceConfig.height = surfaceHeight;
From f981ed4a78190c2413655a6c9ae29f5f7b311295 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 6 Nov 2023 16:33:40 +0100
Subject: [PATCH 043/108] [WebGPU] Move Metal layer creation into Objective-C
file
---
apps/webgpu/CMakeLists.txt | 7 ++++++-
apps/webgpu/main.cpp | 27 +++++----------------------
apps/webgpu/metal_layer.mm | 11 +++++++++++
3 files changed, 22 insertions(+), 23 deletions(-)
create mode 100644 apps/webgpu/metal_layer.mm
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index 0c747f93..fff48076 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -55,7 +55,12 @@ elseif (SYSTEM_NAME_UPPER MATCHES "DARWIN")
INTERFACE_INCLUDE_DIRECTORIES "${WGPU_DIR}")
endif ()
-add_executable(webgpu-demo main.cpp)
+set(TARGET_SPECIFIC_SOURCES)
+if (SYSTEM_NAME_UPPER MATCHES "DARWIN")
+ set(TARGET_SPECIFIC_SOURCES metal_layer.mm)
+endif ()
+
+add_executable(webgpu-demo main.cpp ${TARGET_SPECIFIC_SOURCES})
target_link_libraries(webgpu-demo PRIVATE wgpu sl_cv sl_math ${glfw_LIBS})
if (SYSTEM_NAME_UPPER MATCHES "LINUX")
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index efc71100..062c56e6 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -9,12 +9,6 @@
#elif defined(__APPLE__)
# define SYSTEM_DARWIN
# define GLFW_EXPOSE_NATIVE_COCOA
-# define GLFW_NATIVE_INCLUDE_NONE
-
-# include
-# include
-# include
-# include
#endif
#include
@@ -49,6 +43,10 @@ struct alignas(16) ShaderUniformData
static_assert(sizeof(ShaderUniformData) % 16 == 0, "uniform data size must be a multiple of 16");
+#ifdef SYSTEM_DARWIN
+extern "C" void* createMetalLayer(void* window);
+#endif
+
void handleAdapterRequest(WGPURequestAdapterStatus status,
WGPUAdapter adapter,
char const* message,
@@ -162,24 +160,9 @@ int main(int argc, const char* argv[])
nativeSurfaceDesc.display = glfwGetX11Display();
nativeSurfaceDesc.window = glfwGetX11Window(window);
#elif defined(SYSTEM_DARWIN)
- id cocoaWindow = glfwGetCocoaWindow(window);
-
- // We call the Objective-C runtime directly to get the Metal surface.
-
- // We need to cast 'objc_msgSend' to appropiate function pointer types before calling them.
- auto* sendMessageReturnId = (id(*)(id, ...))objc_msgSend;
- auto* sendMessageReturnNothing = (void (*)(id, ...))objc_msgSend;
-
- id contentView = sendMessageReturnId(cocoaWindow, sel_getUid("contentView"));
- sendMessageReturnNothing(contentView, sel_getUid("setWantsLayer:"), 1);
-
- objc_class* metalLayerClass = objc_getClass("CAMetalLayer");
- id metalLayer = sendMessageReturnId((id)metalLayerClass, sel_getUid("layer"));
- sendMessageReturnNothing(contentView, sel_registerName("setLayer:"), metalLayer);
-
WGPUSurfaceDescriptorFromMetalLayer nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
- nativeSurfaceDesc.layer = metalLayer;
+ nativeSurfaceDesc.layer = createMetalLayer(glfwGetCocoaWindow(window));
#endif
WGPUSurfaceDescriptor surfaceDesc = {};
diff --git a/apps/webgpu/metal_layer.mm b/apps/webgpu/metal_layer.mm
new file mode 100644
index 00000000..a7a832ca
--- /dev/null
+++ b/apps/webgpu/metal_layer.mm
@@ -0,0 +1,11 @@
+#include
+#include
+
+extern "C" id createMetalLayer(NSWindow* window)
+{
+ [window.contentView setWantsLayer:YES];
+ id metalLayer = [CAMetalLayer layer];
+ [window.contentView setLayer:metalLayer];
+
+ return metalLayer;
+}
\ No newline at end of file
From 2e2c6775e4c15f7d0b73e5dff62a5790ac33bfce Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 6 Nov 2023 18:36:51 +0100
Subject: [PATCH 044/108] Cosmetics
---
apps/webgpu/main.cpp | 92 ++++++++++++++++++++++----------------------
1 file changed, 46 insertions(+), 46 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 062c56e6..f66e72ce 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -202,53 +202,53 @@ int main(int argc, const char* argv[])
// clang-format off
std::vector vertexData =
{
- // left
- -0.5, 0.5, -0.5, 0.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, -0.5, 0.5, 1.0f, 1.0f,
-
- // right
- 0.5, 0.5, 0.5, 0.0f, 0.0f,
- 0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, -0.5, -0.5, 1.0f, 1.0f,
-
- // bottom
- -0.5, -0.5, 0.5, 0.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- 0.5, -0.5, 0.5, 1.0f, 0.0f,
- 0.5, -0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- 0.5, -0.5, -0.5, 1.0f, 1.0f,
-
- // top
+ // left
-0.5, 0.5, -0.5, 0.0f, 0.0f,
- -0.5, 0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- -0.5, 0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, 0.5, 1.0f, 1.0f,
-
- // back
- 0.5, 0.5, -0.5, 0.0f, 0.0f,
- 0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, 0.5, -0.5, 1.0f, 0.0f,
- -0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, -0.5, -0.5, 1.0f, 1.0f,
-
- // front
- -0.5, 0.5, 0.5, 0.0f, 0.0f,
- -0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, 0.5, 1.0f, 0.0f,
- 0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, -0.5, 0.5, 1.0f, 1.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, -0.5, 0.5, 1.0f, 1.0f,
+
+ // right
+ 0.5, 0.5, 0.5, 0.0f, 0.0f,
+ 0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // bottom
+ -0.5, -0.5, 0.5, 0.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ 0.5, -0.5, 0.5, 1.0f, 0.0f,
+ 0.5, -0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, -0.5, 0.0f, 1.0f,
+ 0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // top
+ -0.5, 0.5, -0.5, 0.0f, 0.0f,
+ -0.5, 0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, 0.5, -0.5, 1.0f, 0.0f,
+ -0.5, 0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, 0.5, 1.0f, 1.0f,
+
+ // back
+ 0.5, 0.5, -0.5, 0.0f, 0.0f,
+ 0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, 0.5, -0.5, 1.0f, 0.0f,
+ -0.5, 0.5, -0.5, 1.0f, 0.0f,
+ 0.5, -0.5, -0.5, 0.0f, 1.0f,
+ -0.5, -0.5, -0.5, 1.0f, 1.0f,
+
+ // front
+ -0.5, 0.5, 0.5, 0.0f, 0.0f,
+ -0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, 0.5, 0.5, 1.0f, 0.0f,
+ 0.5, 0.5, 0.5, 1.0f, 0.0f,
+ -0.5, -0.5, 0.5, 0.0f, 1.0f,
+ 0.5, -0.5, 0.5, 1.0f, 1.0f,
};
// clang-format on
From cfa20a95ffedad9a58e26acb7760620492421cb3 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 6 Nov 2023 18:43:54 +0100
Subject: [PATCH 045/108] Fixed Warning
---
apps/webgpu/main.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index f66e72ce..e87ddc83 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -7,7 +7,9 @@
# define SYSTEM_LINUX
# define GLFW_EXPOSE_NATIVE_X11
#elif defined(__APPLE__)
-# define SYSTEM_DARWIN
+# ifndef SYSTEM_DARWIN
+# define SYSTEM_DARWIN
+# endif
# define GLFW_EXPOSE_NATIVE_COCOA
#endif
From 61583d619de36d06785e3e39185c3206a808e616 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 9 Nov 2023 09:48:14 +0100
Subject: [PATCH 046/108] [WebGPU] Update demo
---
apps/webgpu/main.cpp | 173 ++++++++++++++++++++++++-------------------
1 file changed, 95 insertions(+), 78 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 062c56e6..eb231299 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -34,6 +34,14 @@
std::exit(1); \
}
+struct AppData
+{
+ WGPUDevice device = nullptr;
+ WGPUSurface surface = nullptr;
+
+ bool requireSurfaceReconfiguration = false;
+};
+
struct alignas(16) ShaderUniformData
{
float projectionMatrix[16];
@@ -47,6 +55,12 @@ static_assert(sizeof(ShaderUniformData) % 16 == 0, "uniform data size must be a
extern "C" void* createMetalLayer(void* window);
#endif
+void onWindowResized(GLFWwindow* window, int width, int height)
+{
+ AppData& app = *((AppData*)glfwGetWindowUserPointer(window));
+ app.requireSurfaceReconfiguration = true;
+}
+
void handleAdapterRequest(WGPURequestAdapterStatus status,
WGPUAdapter adapter,
char const* message,
@@ -75,6 +89,8 @@ void handleDeviceRequest(WGPURequestDeviceStatus status,
int main(int argc, const char* argv[])
{
+ AppData app;
+
// === Initialize GLFW ===
WEBGPU_DEMO_CHECK(glfwInit(), "[GLFW] Failed to initialize");
@@ -86,7 +102,11 @@ int main(int argc, const char* argv[])
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(1280, 720, "WebGPU Demo", nullptr, nullptr);
- WEBGPU_DEMO_CHECK(window, "[GLFW] Window created");
+ WEBGPU_DEMO_CHECK(window, "[GLFW] Failed to create window");
+ WEBGPU_DEMO_LOG("[GLFW] Window created");
+
+ glfwSetWindowUserPointer(window, &app);
+ glfwSetWindowSizeCallback(window, onWindowResized);
// === Create a WebGPU instance ===
// The instance is the root interface to WebGPU through which we create all other WebGPU resources.
@@ -135,13 +155,12 @@ int main(int argc, const char* argv[])
deviceDesc.requiredLimits = &requiredLimits;
deviceDesc.defaultQueue.label = "Demo Queue";
- WGPUDevice device;
- wgpuAdapterRequestDevice(adapter, &deviceDesc, handleDeviceRequest, &device);
+ wgpuAdapterRequestDevice(adapter, &deviceDesc, handleDeviceRequest, &app.device);
// === Acquire a WebGPU queue ===
// The queue is where the commands for the GPU are submitted to.
- WGPUQueue queue = wgpuDeviceGetQueue(device);
+ WGPUQueue queue = wgpuDeviceGetQueue(app.device);
WEBGPU_DEMO_CHECK(queue, "[WebGPU] Failed to acquire queue");
WEBGPU_DEMO_LOG("[WebGPU] Queue acquired");
@@ -169,8 +188,8 @@ int main(int argc, const char* argv[])
surfaceDesc.label = "Demo Surface";
surfaceDesc.nextInChain = (const WGPUChainedStruct*)&nativeSurfaceDesc;
- WGPUSurface surface = wgpuInstanceCreateSurface(instance, &surfaceDesc);
- WEBGPU_DEMO_CHECK(surface, "[WebGPU] Failed to create surface");
+ app.surface = wgpuInstanceCreateSurface(instance, &surfaceDesc);
+ WEBGPU_DEMO_CHECK(app.surface, "[WebGPU] Failed to create surface");
WEBGPU_DEMO_LOG("[WebGPU] Surface created");
// === Configure the surface ===
@@ -178,7 +197,7 @@ int main(int argc, const char* argv[])
// Query the surface capabilities from the adapter.
WGPUSurfaceCapabilities surfaceCapabilities;
- wgpuSurfaceGetCapabilities(surface, adapter, &surfaceCapabilities);
+ wgpuSurfaceGetCapabilities(app.surface, adapter, &surfaceCapabilities);
// Get the window size from the GLFW window.
int surfaceWidth;
@@ -186,14 +205,14 @@ int main(int argc, const char* argv[])
glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
WGPUSurfaceConfiguration surfaceConfig = {};
- surfaceConfig.device = device;
+ surfaceConfig.device = app.device;
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
surfaceConfig.format = surfaceCapabilities.formats[0];
surfaceConfig.presentMode = WGPUPresentMode_Fifo;
surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
surfaceConfig.width = surfaceWidth;
surfaceConfig.height = surfaceHeight;
- wgpuSurfaceConfigure(surface, &surfaceConfig);
+ wgpuSurfaceConfigure(app.surface, &surfaceConfig);
WEBGPU_DEMO_LOG("[WebGPU] Surface configured");
// === Create the vertex buffer ===
@@ -260,7 +279,7 @@ int main(int argc, const char* argv[])
vertexBufferDesc.size = vertexDataSize;
vertexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
- WGPUBuffer vertexBuffer = wgpuDeviceCreateBuffer(device, &vertexBufferDesc);
+ WGPUBuffer vertexBuffer = wgpuDeviceCreateBuffer(app.device, &vertexBufferDesc);
WEBGPU_DEMO_CHECK(vertexBuffer, "[WebGPU] Failed to create vertex buffer");
WEBGPU_DEMO_LOG("[WebGPU] Vertex buffer created");
@@ -281,7 +300,7 @@ int main(int argc, const char* argv[])
indexBufferDesc.size = indexDataSize;
indexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index;
- WGPUBuffer indexBuffer = wgpuDeviceCreateBuffer(device, &indexBufferDesc);
+ WGPUBuffer indexBuffer = wgpuDeviceCreateBuffer(app.device, &indexBufferDesc);
WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create index buffer");
WEBGPU_DEMO_LOG("[WebGPU] Index buffer created");
@@ -294,7 +313,7 @@ int main(int argc, const char* argv[])
uniformBufferDesc.size = sizeof(ShaderUniformData);
uniformBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
- WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer(device, &uniformBufferDesc);
+ WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer(app.device, &uniformBufferDesc);
WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create uniform buffer");
WEBGPU_DEMO_LOG("[WebGPU] Uniform buffer created");
@@ -317,7 +336,7 @@ int main(int argc, const char* argv[])
depthTextureDesc.viewFormatCount = 1;
depthTextureDesc.viewFormats = &depthTextureFormat;
- WGPUTexture depthTexture = wgpuDeviceCreateTexture(device, &depthTextureDesc);
+ WGPUTexture depthTexture = wgpuDeviceCreateTexture(app.device, &depthTextureDesc);
WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to create depth texture");
WEBGPU_DEMO_LOG("[WebGPU] Depth texture created");
@@ -354,7 +373,7 @@ int main(int argc, const char* argv[])
textureDesc.mipLevelCount = 4;
textureDesc.sampleCount = 1;
- WGPUTexture texture = wgpuDeviceCreateTexture(device, &textureDesc);
+ WGPUTexture texture = wgpuDeviceCreateTexture(app.device, &textureDesc);
WEBGPU_DEMO_CHECK(texture, "[WebGPU] Failed to create texture");
WEBGPU_DEMO_LOG("[WebGPU] Texture created");
@@ -450,7 +469,7 @@ int main(int argc, const char* argv[])
samplerDesc.compare = WGPUCompareFunction_Undefined;
samplerDesc.maxAnisotropy = 1.0f;
- WGPUSampler sampler = wgpuDeviceCreateSampler(device, &samplerDesc);
+ WGPUSampler sampler = wgpuDeviceCreateSampler(app.device, &samplerDesc);
WEBGPU_DEMO_CHECK(sampler, "[WebGPU] Failed to create sampler");
WEBGPU_DEMO_LOG("[WebGPU] Sampler created");
@@ -505,7 +524,7 @@ int main(int argc, const char* argv[])
shaderModuleDesc.label = "Demo Shader";
shaderModuleDesc.nextInChain = (const WGPUChainedStruct*)&shaderModuleWGSLDesc;
- WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(device, &shaderModuleDesc);
+ WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(app.device, &shaderModuleDesc);
WEBGPU_DEMO_CHECK(shaderModule, "[WebGPU] Failed to create shader module");
WEBGPU_DEMO_LOG("[WebGPU] Shader module created");
@@ -540,7 +559,7 @@ int main(int argc, const char* argv[])
bindGroupLayoutDesc.label = "Demo Bind Group Layout";
bindGroupLayoutDesc.entryCount = bindGroupLayoutEntries.size();
bindGroupLayoutDesc.entries = bindGroupLayoutEntries.data();
- WGPUBindGroupLayout bindGroupLayout = wgpuDeviceCreateBindGroupLayout(device, &bindGroupLayoutDesc);
+ WGPUBindGroupLayout bindGroupLayout = wgpuDeviceCreateBindGroupLayout(app.device, &bindGroupLayoutDesc);
WEBGPU_DEMO_CHECK(bindGroupLayout, "[WebGPU] Failed to create bind group layout");
WEBGPU_DEMO_LOG("[WebGPU] Bind group layout created");
@@ -569,7 +588,7 @@ int main(int argc, const char* argv[])
bindGroupDesc.layout = bindGroupLayout;
bindGroupDesc.entryCount = bindGroupEntries.size();
bindGroupDesc.entries = bindGroupEntries.data();
- WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(device, &bindGroupDesc);
+ WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(app.device, &bindGroupDesc);
WEBGPU_DEMO_CHECK(bindGroup, "[WebGPU] Failed to create bind group");
WEBGPU_DEMO_LOG("[WebGPU] Bind group created");
@@ -580,7 +599,7 @@ int main(int argc, const char* argv[])
pipelineLayoutDesc.label = "Demo Pipeline Layout";
pipelineLayoutDesc.bindGroupLayoutCount = 1;
pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
- WGPUPipelineLayout pipelineLayout = wgpuDeviceCreatePipelineLayout(device, &pipelineLayoutDesc);
+ WGPUPipelineLayout pipelineLayout = wgpuDeviceCreatePipelineLayout(app.device, &pipelineLayoutDesc);
WEBGPU_DEMO_CHECK(pipelineLayout, "[WebGPU] Failed to create pipeline layout");
WEBGPU_DEMO_LOG("[WebGPU] Pipeline layout created");
@@ -663,11 +682,12 @@ int main(int argc, const char* argv[])
pipelineDesc.multisample = multisampleState;
pipelineDesc.fragment = &fragmentState;
- WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device, &pipelineDesc);
+ WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(app.device, &pipelineDesc);
WEBGPU_DEMO_CHECK(pipeline, "[WebGPU] Failed to create render pipeline");
WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
- SLMat4f modelMatrix;
+ float camRotX = 0.0f;
+ float camRotY = 0.0f;
double lastCursorX = 0.0f;
double lastCursorY = 0.0f;
@@ -682,29 +702,59 @@ int main(int argc, const char* argv[])
double cursorY;
glfwGetCursorPos(window, &cursorX, &cursorY);
- SLMat4f rotationX;
- SLMat4f rotationY;
-
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS)
{
- float deltaRotX = 0.5f * static_cast(cursorY - lastCursorY);
- float deltaRotY = 0.5f * static_cast(cursorX - lastCursorX);
-
- rotationX.rotate(deltaRotX, SLVec3f::AXISX);
- rotationY.rotate(deltaRotY, SLVec3f::AXISY);
+ camRotX -= 0.25f * static_cast(cursorY - lastCursorY);
+ camRotY -= 0.25f * static_cast(cursorX - lastCursorX);
}
- modelMatrix = rotationY * rotationX * modelMatrix;
-
lastCursorX = cursorX;
lastCursorY = cursorY;
// === Create a WebGPU texture view ===
// The texture view is where we render our image into.
+ if (app.requireSurfaceReconfiguration)
+ {
+ app.requireSurfaceReconfiguration = false;
+
+ // Get the window size from the GLFW window.
+ glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
+
+ // The surface size might be zero if the window is minimized.
+ if (surfaceWidth != 0 && surfaceHeight != 0)
+ {
+ WEBGPU_DEMO_LOG("[WebGPU] Re-configuring surface");
+ surfaceConfig.width = surfaceWidth;
+ surfaceConfig.height = surfaceHeight;
+ wgpuSurfaceConfigure(app.surface, &surfaceConfig);
+
+ // Recreate the depth texture.
+
+ wgpuTextureViewRelease(textureView);
+ wgpuTextureDestroy(depthTexture);
+ wgpuTextureRelease(depthTexture);
+
+ depthTextureDesc.size.width = surfaceWidth;
+ depthTextureDesc.size.height = surfaceHeight;
+
+ depthTexture = wgpuDeviceCreateTexture(app.device, &depthTextureDesc);
+ WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to re-create depth texture");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture re-created");
+
+ depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
+ WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to re-create depth texture view");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
+ }
+
+ // Skip this frame.
+ glfwPollEvents();
+ continue;
+ }
+
// Get a texture from the surface to render into.
WGPUSurfaceTexture surfaceTexture;
- wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
+ wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
// The surface might change over time.
// For example, the window might be resized or minimized.
@@ -712,18 +762,11 @@ int main(int argc, const char* argv[])
switch (surfaceTexture.status)
{
case WGPUSurfaceGetCurrentTextureStatus_Success:
- // Everything is ok.
-
- // Check for a suboptimal texture and re-configure it if needed.
+ // Everything is ok, but still check for a suboptimal texture and re-configure it if needed.
if (surfaceTexture.suboptimal)
{
WEBGPU_DEMO_LOG("[WebGPU] Re-configuring currently suboptimal surface");
- surfaceConfig.width = surfaceWidth;
- surfaceConfig.height = surfaceHeight;
- wgpuSurfaceConfigure(surface, &surfaceConfig);
-
- // Skip this frame.
- glfwPollEvents();
+ app.requireSurfaceReconfiguration = true;
continue;
}
@@ -733,38 +776,7 @@ int main(int argc, const char* argv[])
case WGPUSurfaceGetCurrentTextureStatus_Outdated:
case WGPUSurfaceGetCurrentTextureStatus_Lost:
// The surface needs to be re-configured.
-
- // Get the window size from the GLFW window.
- glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
-
- // The surface size might be zero if the window is minimized.
- if (surfaceWidth != 0 && surfaceHeight != 0)
- {
- WEBGPU_DEMO_LOG("[WebGPU] Re-configuring surface");
- surfaceConfig.width = surfaceWidth;
- surfaceConfig.height = surfaceHeight;
- wgpuSurfaceConfigure(surface, &surfaceConfig);
-
- // Recreate the depth texture.
-
- wgpuTextureViewRelease(textureView);
- wgpuTextureDestroy(depthTexture);
- wgpuTextureRelease(depthTexture);
-
- depthTextureDesc.size.width = surfaceWidth;
- depthTextureDesc.size.height = surfaceHeight;
-
- depthTexture = wgpuDeviceCreateTexture(device, &depthTextureDesc);
- WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to re-create depth texture");
- WEBGPU_DEMO_LOG("[WebGPU] Depth texture re-created");
-
- depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
- WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to re-create depth texture view");
- WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
- }
-
- // Skip this frame.
- glfwPollEvents();
+ app.requireSurfaceReconfiguration = true;
continue;
case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
@@ -783,11 +795,16 @@ int main(int argc, const char* argv[])
// === Prepare uniform data ===
float aspectRatio = static_cast(surfaceWidth) / static_cast(surfaceHeight);
+ SLMat4f modelMatrix;
+
SLMat4f projectionMatrix;
projectionMatrix.perspective(70.0f, aspectRatio, 0.1, 1000.0f);
SLMat4f viewMatrix;
- viewMatrix.translate(0.0f, 0.0f, -2.0f);
+ viewMatrix.rotate(camRotY, SLVec3f::AXISY);
+ viewMatrix.rotate(camRotX, SLVec3f::AXISX);
+ viewMatrix.translate(0.0f, 0.0f, 2.0f);
+ viewMatrix.invert();
// === Update uniforms ===
ShaderUniformData uniformData = {};
@@ -802,7 +819,7 @@ int main(int argc, const char* argv[])
WGPUCommandEncoderDescriptor cmdEncoderDesc = {};
cmdEncoderDesc.label = "Demo Command Encoder";
- WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(device, &cmdEncoderDesc);
+ WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(app.device, &cmdEncoderDesc);
WEBGPU_DEMO_CHECK(cmdEncoder, "[WebGPU] Failed to create command encoder");
// === Create a WebGPU render pass ===
@@ -863,7 +880,7 @@ int main(int argc, const char* argv[])
// === Present the surface ===
// This presents our rendered texture to the screen.
- wgpuSurfacePresent(surface);
+ wgpuSurfacePresent(app.surface);
// === Clean up resources ===
wgpuCommandBufferRelease(cmdBuffer);
@@ -895,9 +912,9 @@ int main(int argc, const char* argv[])
wgpuBufferRelease(indexBuffer);
wgpuBufferDestroy(vertexBuffer);
wgpuBufferRelease(vertexBuffer);
- wgpuSurfaceRelease(surface);
+ wgpuSurfaceRelease(app.surface);
wgpuQueueRelease(queue);
- wgpuDeviceRelease(device);
+ wgpuDeviceRelease(app.device);
wgpuAdapterRelease(adapter);
wgpuInstanceRelease(instance);
WEBGPU_DEMO_LOG("[WebGPU] Resources released");
From efc509cbfca68cb2c8e28dd1e7f0bcfd7030dd99 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 9 Nov 2023 10:57:59 +0100
Subject: [PATCH 047/108] [WebGPU] Improve surface re-configuring in demo
---
apps/webgpu/main.cpp | 719 +++++++++++++++++++++++--------------------
1 file changed, 383 insertions(+), 336 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index e4c2999a..316b3fa5 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -38,10 +38,43 @@
struct AppData
{
- WGPUDevice device = nullptr;
- WGPUSurface surface = nullptr;
+ GLFWwindow* window = nullptr;
+ int surfaceWidth = 0;
+ int surfaceHeight = 0;
+
+ WGPUInstance instance = nullptr;
+ WGPUAdapter adapter = nullptr;
+ WGPUDevice device = nullptr;
+ WGPUQueue queue = nullptr;
+ WGPUSurface surface = nullptr;
+ WGPUTexture depthTexture = nullptr;
+ WGPUTextureView depthTextureView = nullptr;
+ WGPUBuffer vertexBuffer = nullptr;
+ WGPUBuffer indexBuffer = nullptr;
+ WGPUBuffer uniformBuffer = nullptr;
+ WGPUTexture texture = nullptr;
+ WGPUTextureView textureView = nullptr;
+ WGPUSampler sampler = nullptr;
+ WGPUShaderModule shaderModule = nullptr;
+ WGPUBindGroupLayout bindGroupLayout = nullptr;
+ WGPUBindGroup bindGroup = nullptr;
+ WGPUPipelineLayout pipelineLayout = nullptr;
+ WGPURenderPipeline pipeline = nullptr;
+
+ WGPUSurfaceConfiguration surfaceConfig;
+ WGPUTextureFormat depthTextureFormat;
+ WGPUTextureDescriptor depthTextureDesc;
+ WGPUTextureViewDescriptor depthTextureViewDesc;
+
+ unsigned vertexDataSize;
+ unsigned indexCount;
+ unsigned indexDataSize;
bool requireSurfaceReconfiguration = false;
+
+ float camRotX = 0.0f;
+ float camRotY = 0.0f;
+ float camZ = 2.0f;
};
struct alignas(16) ShaderUniformData
@@ -57,10 +90,207 @@ static_assert(sizeof(ShaderUniformData) % 16 == 0, "uniform data size must be a
extern "C" void* createMetalLayer(void* window);
#endif
-void onWindowResized(GLFWwindow* window, int width, int height)
+void reconfigureSurface(AppData& app)
+{
+ // Get the window size from the GLFW window.
+ glfwGetWindowSize(app.window, &app.surfaceWidth, &app.surfaceHeight);
+
+ // The surface size might be zero if the window is minimized.
+ if (app.surfaceWidth == 0 || app.surfaceHeight == 0)
+ return;
+
+ WEBGPU_DEMO_LOG("[WebGPU] Re-configuring surface");
+ app.surfaceConfig.width = app.surfaceWidth;
+ app.surfaceConfig.height = app.surfaceHeight;
+ wgpuSurfaceConfigure(app.surface, &app.surfaceConfig);
+
+ // Recreate the depth texture.
+
+ wgpuTextureViewRelease(app.depthTextureView);
+ wgpuTextureDestroy(app.depthTexture);
+ wgpuTextureRelease(app.depthTexture);
+
+ app.depthTextureDesc.size.width = app.surfaceWidth;
+ app.depthTextureDesc.size.height = app.surfaceHeight;
+
+ app.depthTexture = wgpuDeviceCreateTexture(app.device, &app.depthTextureDesc);
+ WEBGPU_DEMO_CHECK(app.depthTexture, "[WebGPU] Failed to re-create depth texture");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture re-created");
+
+ app.depthTextureView = wgpuTextureCreateView(app.depthTexture, &app.depthTextureViewDesc);
+ WEBGPU_DEMO_CHECK(app.depthTextureView, "[WebGPU] Failed to re-create depth texture view");
+ WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
+}
+
+void onPaint(AppData& app)
+{
+ // Get a texture from the surface to render into.
+ WGPUSurfaceTexture surfaceTexture;
+ wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
+
+ // The surface might change over time.
+ // For example, the window might be resized or minimized.
+ // We have to check the status and adapt to it.
+ switch (surfaceTexture.status)
+ {
+ case WGPUSurfaceGetCurrentTextureStatus_Success:
+ // Everything is ok, but still check for a suboptimal texture and re-configure it if needed.
+ if (surfaceTexture.suboptimal)
+ {
+ WEBGPU_DEMO_LOG("[WebGPU] Re-configuring currently suboptimal surface");
+ reconfigureSurface(app);
+ wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
+ }
+
+ break;
+
+ case WGPUSurfaceGetCurrentTextureStatus_Timeout:
+ case WGPUSurfaceGetCurrentTextureStatus_Outdated:
+ case WGPUSurfaceGetCurrentTextureStatus_Lost:
+ // The surface needs to be re-configured.
+ reconfigureSurface(app);
+ wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
+ break;
+
+ case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
+ case WGPUSurfaceGetCurrentTextureStatus_DeviceLost:
+ // An error occured.
+ WEBGPU_DEMO_CHECK(false, "[WebGPU] Failed to acquire current surface texture");
+ break;
+
+ case WGPUSurfaceGetCurrentTextureStatus_Force32:
+ break;
+ }
+
+ // === Create a WebGPU texture view ===
+ // The texture view is where we render our image into.
+
+ // Create a view into the texture to specify where and how to modify the texture.
+ WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
+
+ // === Prepare uniform data ===
+ float aspectRatio = static_cast(app.surfaceWidth) / static_cast(app.surfaceHeight);
+
+ SLMat4f modelMatrix;
+
+ SLMat4f projectionMatrix;
+ projectionMatrix.perspective(70.0f, aspectRatio, 0.1, 1000.0f);
+
+ SLMat4f viewMatrix;
+ viewMatrix.rotate(app.camRotY, SLVec3f::AXISY);
+ viewMatrix.rotate(app.camRotX, SLVec3f::AXISX);
+ viewMatrix.translate(0.0f, 0.0f, 2.0f);
+ viewMatrix.invert();
+
+ // === Update uniforms ===
+ ShaderUniformData uniformData = {};
+ std::memcpy(uniformData.projectionMatrix, projectionMatrix.m(), sizeof(uniformData.projectionMatrix));
+ std::memcpy(uniformData.viewMatrix, viewMatrix.m(), sizeof(uniformData.viewMatrix));
+ std::memcpy(uniformData.modelMatrix, modelMatrix.m(), sizeof(uniformData.modelMatrix));
+ wgpuQueueWriteBuffer(app.queue, app.uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
+
+ // === Create a WebGPU command encoder ===
+ // The encoder encodes the commands for the GPU into a command buffer.
+
+ WGPUCommandEncoderDescriptor cmdEncoderDesc = {};
+ cmdEncoderDesc.label = "Demo Command Encoder";
+
+ WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(app.device, &cmdEncoderDesc);
+ WEBGPU_DEMO_CHECK(cmdEncoder, "[WebGPU] Failed to create command encoder");
+
+ // === Create a WebGPU render pass ===
+ // The render pass specifies what attachments to use while rendering.
+ // A color attachment specifies what view to render into and what to do with the texture before and after
+ // rendering. We clear the texture before rendering and store the results after rendering.
+ // The depth attachment specifies what depth texture to use.
+
+ WGPURenderPassColorAttachment colorAttachment = {};
+ colorAttachment.view = view;
+ colorAttachment.loadOp = WGPULoadOp_Clear;
+ colorAttachment.storeOp = WGPUStoreOp_Store;
+ colorAttachment.clearValue.r = 0.3;
+ colorAttachment.clearValue.g = 0.0;
+ colorAttachment.clearValue.b = 0.2;
+ colorAttachment.clearValue.a = 1.0;
+
+ WGPURenderPassDepthStencilAttachment depthStencilAttachment = {};
+ depthStencilAttachment.view = app.depthTextureView;
+ depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
+ depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
+ depthStencilAttachment.depthClearValue = 1.0f;
+ depthStencilAttachment.depthReadOnly = false;
+ depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
+ depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
+ depthStencilAttachment.stencilClearValue = 0.0f;
+ depthStencilAttachment.stencilReadOnly = true;
+
+ WGPURenderPassDescriptor renderPassDesc = {};
+ renderPassDesc.label = "Demo Render Pass";
+ renderPassDesc.colorAttachmentCount = 1;
+ renderPassDesc.colorAttachments = &colorAttachment;
+ renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
+
+ // === Encode the commands ===
+ // The commands to begin a render pass, bind a pipeline, draw the triangle and end the render pass
+ // are encoded into a buffer.
+
+ WGPURenderPassEncoder renderPassEncoder = wgpuCommandEncoderBeginRenderPass(cmdEncoder, &renderPassDesc);
+ wgpuRenderPassEncoderSetPipeline(renderPassEncoder, app.pipeline);
+ wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, app.vertexBuffer, 0, app.vertexDataSize);
+ wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, app.indexBuffer, WGPUIndexFormat_Uint16, 0, app.indexDataSize);
+ wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, app.bindGroup, 0, nullptr);
+ wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, app.indexCount, 1, 0, 0, 0);
+ wgpuRenderPassEncoderEnd(renderPassEncoder);
+
+ // === Get the command buffer ===
+ // The command encoder is finished to get the commands for the GPU to execute in a command buffer.
+
+ WGPUCommandBufferDescriptor cmdBufferDesc = {};
+ cmdBufferDesc.label = "Demo Command Buffer";
+
+ WGPUCommandBuffer cmdBuffer = wgpuCommandEncoderFinish(cmdEncoder, &cmdBufferDesc);
+
+ // === Submit the command buffer to the GPU ===
+ // The work for the GPU is submitted through the queue and executed.
+ wgpuQueueSubmit(app.queue, 1, &cmdBuffer);
+
+ // === Present the surface ===
+ // This presents our rendered texture to the screen.
+ wgpuSurfacePresent(app.surface);
+
+ // === Clean up resources ===
+ wgpuCommandBufferRelease(cmdBuffer);
+ wgpuRenderPassEncoderRelease(renderPassEncoder);
+ wgpuCommandEncoderRelease(cmdEncoder);
+ wgpuTextureViewRelease(view);
+ wgpuTextureRelease(surfaceTexture.texture);
+}
+
+void onResize(GLFWwindow* window, int width, int height)
{
AppData& app = *((AppData*)glfwGetWindowUserPointer(window));
- app.requireSurfaceReconfiguration = true;
+ reconfigureSurface(app);
+ onPaint(app);
+}
+
+void initGLFW(AppData& app)
+{
+ // === Initialize GLFW ===
+
+ WEBGPU_DEMO_CHECK(glfwInit(), "[GLFW] Failed to initialize");
+ WEBGPU_DEMO_LOG("[GLFW] Initialized");
+
+ // === Create the GLFW window ===
+
+ // Prevent GLFW from creating an OpenGL context as the underlying graphics API probably won't be OpenGL.
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+
+ app.window = glfwCreateWindow(1280, 720, "WebGPU Demo", nullptr, nullptr);
+ WEBGPU_DEMO_CHECK(app.window, "[GLFW] Failed to create window");
+ WEBGPU_DEMO_LOG("[GLFW] Window created");
+
+ glfwSetWindowUserPointer(app.window, &app);
+ glfwSetFramebufferSizeCallback(app.window, onResize);
}
void handleAdapterRequest(WGPURequestAdapterStatus status,
@@ -89,32 +319,13 @@ void handleDeviceRequest(WGPURequestDeviceStatus status,
*outDevice = device;
}
-int main(int argc, const char* argv[])
+void initWebGPU(AppData& app)
{
- AppData app;
-
- // === Initialize GLFW ===
-
- WEBGPU_DEMO_CHECK(glfwInit(), "[GLFW] Failed to initialize");
- WEBGPU_DEMO_LOG("[GLFW] Initialized");
-
- // === Create the GLFW window ===
-
- // Prevent GLFW from creating an OpenGL context as the underlying graphics API probably won't be OpenGL.
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
-
- GLFWwindow* window = glfwCreateWindow(1280, 720, "WebGPU Demo", nullptr, nullptr);
- WEBGPU_DEMO_CHECK(window, "[GLFW] Failed to create window");
- WEBGPU_DEMO_LOG("[GLFW] Window created");
-
- glfwSetWindowUserPointer(window, &app);
- glfwSetWindowSizeCallback(window, onWindowResized);
-
// === Create a WebGPU instance ===
// The instance is the root interface to WebGPU through which we create all other WebGPU resources.
- WGPUInstance instance = wgpuCreateInstance(nullptr);
- WEBGPU_DEMO_CHECK(instance, "[WebGPU] Failed to create instance");
+ app.instance = wgpuCreateInstance(nullptr);
+ WEBGPU_DEMO_CHECK(app.instance, "[WebGPU] Failed to create instance");
WEBGPU_DEMO_LOG("[WebGPU] Instance created");
// === Acquire a WebGPU adapter ===
@@ -122,11 +333,10 @@ int main(int argc, const char* argv[])
WGPURequestAdapterOptions adapterOptions = {};
- WGPUAdapter adapter;
- wgpuInstanceRequestAdapter(instance, &adapterOptions, handleAdapterRequest, &adapter);
+ wgpuInstanceRequestAdapter(app.instance, &adapterOptions, handleAdapterRequest, &app.adapter);
WGPUSupportedLimits adapterLimits;
- wgpuAdapterGetLimits(adapter, &adapterLimits);
+ wgpuAdapterGetLimits(app.adapter, &adapterLimits);
// === Acquire a WebGPU device ===
// A device provides access to a GPU and is created from an adapter.
@@ -157,13 +367,13 @@ int main(int argc, const char* argv[])
deviceDesc.requiredLimits = &requiredLimits;
deviceDesc.defaultQueue.label = "Demo Queue";
- wgpuAdapterRequestDevice(adapter, &deviceDesc, handleDeviceRequest, &app.device);
+ wgpuAdapterRequestDevice(app.adapter, &deviceDesc, handleDeviceRequest, &app.device);
// === Acquire a WebGPU queue ===
// The queue is where the commands for the GPU are submitted to.
- WGPUQueue queue = wgpuDeviceGetQueue(app.device);
- WEBGPU_DEMO_CHECK(queue, "[WebGPU] Failed to acquire queue");
+ app.queue = wgpuDeviceGetQueue(app.device);
+ WEBGPU_DEMO_CHECK(app.queue, "[WebGPU] Failed to acquire queue");
WEBGPU_DEMO_LOG("[WebGPU] Queue acquired");
// === Create a WebGPU surface ===
@@ -174,23 +384,23 @@ int main(int argc, const char* argv[])
WGPUSurfaceDescriptorFromWindowsHWND nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromWindowsHWND;
nativeSurfaceDesc.hinstance = GetModuleHandle(nullptr);
- nativeSurfaceDesc.hwnd = glfwGetWin32Window(window);
+ nativeSurfaceDesc.hwnd = glfwGetWin32Window(app.window);
#elif defined(SYSTEM_LINUX)
WGPUSurfaceDescriptorFromXlibWindow nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromXlibWindow;
nativeSurfaceDesc.display = glfwGetX11Display();
- nativeSurfaceDesc.window = glfwGetX11Window(window);
+ nativeSurfaceDesc.window = glfwGetX11Window(app.window);
#elif defined(SYSTEM_DARWIN)
WGPUSurfaceDescriptorFromMetalLayer nativeSurfaceDesc = {};
nativeSurfaceDesc.chain.sType = WGPUSType_SurfaceDescriptorFromMetalLayer;
- nativeSurfaceDesc.layer = createMetalLayer(glfwGetCocoaWindow(window));
+ nativeSurfaceDesc.layer = createMetalLayer(glfwGetCocoaWindow(app.window));
#endif
WGPUSurfaceDescriptor surfaceDesc = {};
surfaceDesc.label = "Demo Surface";
surfaceDesc.nextInChain = (const WGPUChainedStruct*)&nativeSurfaceDesc;
- app.surface = wgpuInstanceCreateSurface(instance, &surfaceDesc);
+ app.surface = wgpuInstanceCreateSurface(app.instance, &surfaceDesc);
WEBGPU_DEMO_CHECK(app.surface, "[WebGPU] Failed to create surface");
WEBGPU_DEMO_LOG("[WebGPU] Surface created");
@@ -199,22 +409,20 @@ int main(int argc, const char* argv[])
// Query the surface capabilities from the adapter.
WGPUSurfaceCapabilities surfaceCapabilities;
- wgpuSurfaceGetCapabilities(app.surface, adapter, &surfaceCapabilities);
+ wgpuSurfaceGetCapabilities(app.surface, app.adapter, &surfaceCapabilities);
// Get the window size from the GLFW window.
- int surfaceWidth;
- int surfaceHeight;
- glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
-
- WGPUSurfaceConfiguration surfaceConfig = {};
- surfaceConfig.device = app.device;
- surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
- surfaceConfig.format = surfaceCapabilities.formats[0];
- surfaceConfig.presentMode = WGPUPresentMode_Fifo;
- surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
- surfaceConfig.width = surfaceWidth;
- surfaceConfig.height = surfaceHeight;
- wgpuSurfaceConfigure(app.surface, &surfaceConfig);
+ glfwGetFramebufferSize(app.window, &app.surfaceWidth, &app.surfaceHeight);
+
+ app.surfaceConfig = {};
+ app.surfaceConfig.device = app.device;
+ app.surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
+ app.surfaceConfig.format = surfaceCapabilities.formats[0];
+ app.surfaceConfig.presentMode = WGPUPresentMode_Fifo;
+ app.surfaceConfig.alphaMode = surfaceCapabilities.alphaModes[0];
+ app.surfaceConfig.width = app.surfaceWidth;
+ app.surfaceConfig.height = app.surfaceHeight;
+ wgpuSurfaceConfigure(app.surface, &app.surfaceConfig);
WEBGPU_DEMO_LOG("[WebGPU] Surface configured");
// === Create the vertex buffer ===
@@ -273,20 +481,20 @@ int main(int argc, const char* argv[])
};
// clang-format on
- unsigned vertexCount = vertexData.size() / 5;
- unsigned vertexDataSize = vertexData.size() * sizeof(float);
+ unsigned vertexCount = vertexData.size() / 5;
+ app.vertexDataSize = vertexData.size() * sizeof(float);
WGPUBufferDescriptor vertexBufferDesc = {};
vertexBufferDesc.label = "Demo Vertex Buffer";
- vertexBufferDesc.size = vertexDataSize;
+ vertexBufferDesc.size = app.vertexDataSize;
vertexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex;
- WGPUBuffer vertexBuffer = wgpuDeviceCreateBuffer(app.device, &vertexBufferDesc);
- WEBGPU_DEMO_CHECK(vertexBuffer, "[WebGPU] Failed to create vertex buffer");
+ app.vertexBuffer = wgpuDeviceCreateBuffer(app.device, &vertexBufferDesc);
+ WEBGPU_DEMO_CHECK(app.vertexBuffer, "[WebGPU] Failed to create vertex buffer");
WEBGPU_DEMO_LOG("[WebGPU] Vertex buffer created");
// Upload the data to the GPU.
- wgpuQueueWriteBuffer(queue, vertexBuffer, 0, vertexData.data(), vertexDataSize);
+ wgpuQueueWriteBuffer(app.queue, app.vertexBuffer, 0, vertexData.data(), app.vertexDataSize);
// === Create the index buffer ===
@@ -294,19 +502,19 @@ int main(int argc, const char* argv[])
for (std::uint16_t index = 0; index < 36; index++)
indexData.push_back(index);
- unsigned indexCount = indexData.size();
- unsigned indexDataSize = indexData.size() * sizeof(std::uint16_t);
+ app.indexCount = indexData.size();
+ app.indexDataSize = indexData.size() * sizeof(std::uint16_t);
WGPUBufferDescriptor indexBufferDesc = {};
indexBufferDesc.label = "Demo Index Buffer";
- indexBufferDesc.size = indexDataSize;
+ indexBufferDesc.size = app.indexDataSize;
indexBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index;
- WGPUBuffer indexBuffer = wgpuDeviceCreateBuffer(app.device, &indexBufferDesc);
- WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create index buffer");
+ app.indexBuffer = wgpuDeviceCreateBuffer(app.device, &indexBufferDesc);
+ WEBGPU_DEMO_CHECK(app.indexBuffer, "[WebGPU] Failed to create index buffer");
WEBGPU_DEMO_LOG("[WebGPU] Index buffer created");
- wgpuQueueWriteBuffer(queue, indexBuffer, 0, indexData.data(), indexDataSize);
+ wgpuQueueWriteBuffer(app.queue, app.indexBuffer, 0, indexData.data(), app.indexDataSize);
// === Create the uniform buffer ===
@@ -315,44 +523,44 @@ int main(int argc, const char* argv[])
uniformBufferDesc.size = sizeof(ShaderUniformData);
uniformBufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform;
- WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer(app.device, &uniformBufferDesc);
- WEBGPU_DEMO_CHECK(indexBuffer, "[WebGPU] Failed to create uniform buffer");
+ app.uniformBuffer = wgpuDeviceCreateBuffer(app.device, &uniformBufferDesc);
+ WEBGPU_DEMO_CHECK(app.indexBuffer, "[WebGPU] Failed to create uniform buffer");
WEBGPU_DEMO_LOG("[WebGPU] Uniform buffer created");
ShaderUniformData uniformData = {};
- wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
+ wgpuQueueWriteBuffer(app.queue, app.uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
// === Create the depth texture ===
- WGPUTextureFormat depthTextureFormat = WGPUTextureFormat_Depth24Plus;
-
- WGPUTextureDescriptor depthTextureDesc = {};
- depthTextureDesc.dimension = WGPUTextureDimension_2D;
- depthTextureDesc.format = depthTextureFormat;
- depthTextureDesc.mipLevelCount = 1;
- depthTextureDesc.sampleCount = 1;
- depthTextureDesc.size.width = surfaceWidth;
- depthTextureDesc.size.height = surfaceHeight;
- depthTextureDesc.size.depthOrArrayLayers = 1;
- depthTextureDesc.usage = WGPUTextureUsage_RenderAttachment;
- depthTextureDesc.viewFormatCount = 1;
- depthTextureDesc.viewFormats = &depthTextureFormat;
-
- WGPUTexture depthTexture = wgpuDeviceCreateTexture(app.device, &depthTextureDesc);
- WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to create depth texture");
+ app.depthTextureFormat = WGPUTextureFormat_Depth24Plus;
+
+ app.depthTextureDesc = {};
+ app.depthTextureDesc.dimension = WGPUTextureDimension_2D;
+ app.depthTextureDesc.format = app.depthTextureFormat;
+ app.depthTextureDesc.mipLevelCount = 1;
+ app.depthTextureDesc.sampleCount = 1;
+ app.depthTextureDesc.size.width = app.surfaceWidth;
+ app.depthTextureDesc.size.height = app.surfaceHeight;
+ app.depthTextureDesc.size.depthOrArrayLayers = 1;
+ app.depthTextureDesc.usage = WGPUTextureUsage_RenderAttachment;
+ app.depthTextureDesc.viewFormatCount = 1;
+ app.depthTextureDesc.viewFormats = &app.depthTextureFormat;
+
+ app.depthTexture = wgpuDeviceCreateTexture(app.device, &app.depthTextureDesc);
+ WEBGPU_DEMO_CHECK(app.depthTexture, "[WebGPU] Failed to create depth texture");
WEBGPU_DEMO_LOG("[WebGPU] Depth texture created");
- WGPUTextureViewDescriptor depthTextureViewDesc = {};
- depthTextureViewDesc.aspect = WGPUTextureAspect_DepthOnly;
- depthTextureViewDesc.baseArrayLayer = 0;
- depthTextureViewDesc.arrayLayerCount = 1;
- depthTextureViewDesc.baseMipLevel = 0;
- depthTextureViewDesc.mipLevelCount = 1;
- depthTextureViewDesc.dimension = WGPUTextureViewDimension_2D;
- depthTextureViewDesc.format = depthTextureFormat;
-
- WGPUTextureView depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
- WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to create depth texture view");
+ app.depthTextureViewDesc = {};
+ app.depthTextureViewDesc.aspect = WGPUTextureAspect_DepthOnly;
+ app.depthTextureViewDesc.baseArrayLayer = 0;
+ app.depthTextureViewDesc.arrayLayerCount = 1;
+ app.depthTextureViewDesc.baseMipLevel = 0;
+ app.depthTextureViewDesc.mipLevelCount = 1;
+ app.depthTextureViewDesc.dimension = WGPUTextureViewDimension_2D;
+ app.depthTextureViewDesc.format = app.depthTextureFormat;
+
+ app.depthTextureView = wgpuTextureCreateView(app.depthTexture, &app.depthTextureViewDesc);
+ WEBGPU_DEMO_CHECK(app.depthTextureView, "[WebGPU] Failed to create depth texture view");
WEBGPU_DEMO_LOG("[WebGPU] Depth texture view created");
// === Create the texture ===
@@ -375,13 +583,13 @@ int main(int argc, const char* argv[])
textureDesc.mipLevelCount = 4;
textureDesc.sampleCount = 1;
- WGPUTexture texture = wgpuDeviceCreateTexture(app.device, &textureDesc);
- WEBGPU_DEMO_CHECK(texture, "[WebGPU] Failed to create texture");
+ app.texture = wgpuDeviceCreateTexture(app.device, &textureDesc);
+ WEBGPU_DEMO_CHECK(app.texture, "[WebGPU] Failed to create texture");
WEBGPU_DEMO_LOG("[WebGPU] Texture created");
// Where do we copyu the pixel data to?
WGPUImageCopyTexture destination = {};
- destination.texture = texture;
+ destination.texture = app.texture;
destination.mipLevel = 0;
destination.origin.x = 0;
destination.origin.y = 0;
@@ -433,7 +641,7 @@ int main(int argc, const char* argv[])
pixelDataLayout.rowsPerImage = mipLevelSize.height;
// Upload the data to the GPU.
- wgpuQueueWriteTexture(queue, &destination, mipLevelImage.data, mipLevelBytes, &pixelDataLayout, &mipLevelSize);
+ wgpuQueueWriteTexture(app.queue, &destination, mipLevelImage.data, mipLevelBytes, &pixelDataLayout, &mipLevelSize);
// Scale the image down for the next mip level.
mipLevelSize.width /= 2;
@@ -450,8 +658,8 @@ int main(int argc, const char* argv[])
textureViewDesc.dimension = WGPUTextureViewDimension_2D;
textureViewDesc.format = textureDesc.format;
- WGPUTextureView textureView = wgpuTextureCreateView(texture, &textureViewDesc);
- WEBGPU_DEMO_CHECK(textureView, "[WebGPU] Failed to create texture view");
+ app.textureView = wgpuTextureCreateView(app.texture, &textureViewDesc);
+ WEBGPU_DEMO_CHECK(app.textureView, "[WebGPU] Failed to create texture view");
WEBGPU_DEMO_LOG("[WebGPU] Texture view created");
// === Create the texture sampler ===
@@ -471,8 +679,8 @@ int main(int argc, const char* argv[])
samplerDesc.compare = WGPUCompareFunction_Undefined;
samplerDesc.maxAnisotropy = 1.0f;
- WGPUSampler sampler = wgpuDeviceCreateSampler(app.device, &samplerDesc);
- WEBGPU_DEMO_CHECK(sampler, "[WebGPU] Failed to create sampler");
+ app.sampler = wgpuDeviceCreateSampler(app.device, &samplerDesc);
+ WEBGPU_DEMO_CHECK(app.sampler, "[WebGPU] Failed to create sampler");
WEBGPU_DEMO_LOG("[WebGPU] Sampler created");
// === Create the shader module ===
@@ -526,8 +734,8 @@ int main(int argc, const char* argv[])
shaderModuleDesc.label = "Demo Shader";
shaderModuleDesc.nextInChain = (const WGPUChainedStruct*)&shaderModuleWGSLDesc;
- WGPUShaderModule shaderModule = wgpuDeviceCreateShaderModule(app.device, &shaderModuleDesc);
- WEBGPU_DEMO_CHECK(shaderModule, "[WebGPU] Failed to create shader module");
+ app.shaderModule = wgpuDeviceCreateShaderModule(app.device, &shaderModuleDesc);
+ WEBGPU_DEMO_CHECK(app.shaderModule, "[WebGPU] Failed to create shader module");
WEBGPU_DEMO_LOG("[WebGPU] Shader module created");
// === Create the bind group layout ===
@@ -561,8 +769,9 @@ int main(int argc, const char* argv[])
bindGroupLayoutDesc.label = "Demo Bind Group Layout";
bindGroupLayoutDesc.entryCount = bindGroupLayoutEntries.size();
bindGroupLayoutDesc.entries = bindGroupLayoutEntries.data();
- WGPUBindGroupLayout bindGroupLayout = wgpuDeviceCreateBindGroupLayout(app.device, &bindGroupLayoutDesc);
- WEBGPU_DEMO_CHECK(bindGroupLayout, "[WebGPU] Failed to create bind group layout");
+
+ app.bindGroupLayout = wgpuDeviceCreateBindGroupLayout(app.device, &bindGroupLayoutDesc);
+ WEBGPU_DEMO_CHECK(app.bindGroupLayout, "[WebGPU] Failed to create bind group layout");
WEBGPU_DEMO_LOG("[WebGPU] Bind group layout created");
// === Create the bind group ===
@@ -570,28 +779,28 @@ int main(int argc, const char* argv[])
WGPUBindGroupEntry uniformBinding = {};
uniformBinding.binding = 0;
- uniformBinding.buffer = uniformBuffer;
+ uniformBinding.buffer = app.uniformBuffer;
uniformBinding.offset = 0;
uniformBinding.size = sizeof(ShaderUniformData);
WGPUBindGroupEntry textureBinding = {};
textureBinding.binding = 1;
- textureBinding.textureView = textureView;
+ textureBinding.textureView = app.textureView;
WGPUBindGroupEntry samplerBinding = {};
samplerBinding.binding = 2;
- samplerBinding.sampler = sampler;
+ samplerBinding.sampler = app.sampler;
std::vector bindGroupEntries = {uniformBinding,
textureBinding,
samplerBinding};
WGPUBindGroupDescriptor bindGroupDesc = {};
- bindGroupDesc.layout = bindGroupLayout;
+ bindGroupDesc.layout = app.bindGroupLayout;
bindGroupDesc.entryCount = bindGroupEntries.size();
bindGroupDesc.entries = bindGroupEntries.data();
- WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(app.device, &bindGroupDesc);
- WEBGPU_DEMO_CHECK(bindGroup, "[WebGPU] Failed to create bind group");
+ app.bindGroup = wgpuDeviceCreateBindGroup(app.device, &bindGroupDesc);
+ WEBGPU_DEMO_CHECK(app.bindGroup, "[WebGPU] Failed to create bind group");
WEBGPU_DEMO_LOG("[WebGPU] Bind group created");
// === Create the pipeline layout ===
@@ -600,9 +809,10 @@ int main(int argc, const char* argv[])
WGPUPipelineLayoutDescriptor pipelineLayoutDesc = {};
pipelineLayoutDesc.label = "Demo Pipeline Layout";
pipelineLayoutDesc.bindGroupLayoutCount = 1;
- pipelineLayoutDesc.bindGroupLayouts = &bindGroupLayout;
- WGPUPipelineLayout pipelineLayout = wgpuDeviceCreatePipelineLayout(app.device, &pipelineLayoutDesc);
- WEBGPU_DEMO_CHECK(pipelineLayout, "[WebGPU] Failed to create pipeline layout");
+ pipelineLayoutDesc.bindGroupLayouts = &app.bindGroupLayout;
+
+ app.pipelineLayout = wgpuDeviceCreatePipelineLayout(app.device, &pipelineLayoutDesc);
+ WEBGPU_DEMO_CHECK(app.pipelineLayout, "[WebGPU] Failed to create pipeline layout");
WEBGPU_DEMO_LOG("[WebGPU] Pipeline layout created");
// === Create the render pipeline ===
@@ -631,7 +841,7 @@ int main(int argc, const char* argv[])
// Configuration for the vertex shader stage
WGPUVertexState vertexState = {};
- vertexState.module = shaderModule;
+ vertexState.module = app.shaderModule;
vertexState.entryPoint = "vs_main";
vertexState.bufferCount = 1;
vertexState.buffers = &vertexBufferLayout;
@@ -645,7 +855,7 @@ int main(int argc, const char* argv[])
// Configuration for depth testing and stencil buffer
WGPUDepthStencilState depthStencilState = {};
- depthStencilState.format = depthTextureFormat;
+ depthStencilState.format = app.depthTextureFormat;
depthStencilState.depthWriteEnabled = true;
depthStencilState.depthCompare = WGPUCompareFunction_Less;
depthStencilState.stencilReadMask = 0;
@@ -669,7 +879,7 @@ int main(int argc, const char* argv[])
colorTargetState.format = surfaceCapabilities.formats[0];
colorTargetState.writeMask = WGPUColorWriteMask_All;
WGPUFragmentState fragmentState = {};
- fragmentState.module = shaderModule;
+ fragmentState.module = app.shaderModule;
fragmentState.entryPoint = "fs_main";
fragmentState.targetCount = 1;
fragmentState.targets = &colorTargetState;
@@ -677,255 +887,92 @@ int main(int argc, const char* argv[])
// Configuration for the entire pipeline
WGPURenderPipelineDescriptor pipelineDesc = {};
pipelineDesc.label = "Demo Pipeline";
- pipelineDesc.layout = pipelineLayout;
+ pipelineDesc.layout = app.pipelineLayout;
pipelineDesc.vertex = vertexState;
pipelineDesc.primitive = primitiveState;
pipelineDesc.depthStencil = &depthStencilState;
pipelineDesc.multisample = multisampleState;
pipelineDesc.fragment = &fragmentState;
- WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(app.device, &pipelineDesc);
- WEBGPU_DEMO_CHECK(pipeline, "[WebGPU] Failed to create render pipeline");
+ app.pipeline = wgpuDeviceCreateRenderPipeline(app.device, &pipelineDesc);
+ WEBGPU_DEMO_CHECK(app.pipeline, "[WebGPU] Failed to create render pipeline");
WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
+}
- float camRotX = 0.0f;
- float camRotY = 0.0f;
+void deinitWebGPU(AppData& app)
+{
+ // === Release all WebGPU resources ===
+
+ wgpuRenderPipelineRelease(app.pipeline);
+ wgpuPipelineLayoutRelease(app.pipelineLayout);
+ wgpuBindGroupRelease(app.bindGroup);
+ wgpuBindGroupLayoutRelease(app.bindGroupLayout);
+ wgpuShaderModuleRelease(app.shaderModule);
+ wgpuSamplerRelease(app.sampler);
+ wgpuTextureViewRelease(app.textureView);
+ wgpuTextureDestroy(app.texture);
+ wgpuTextureRelease(app.texture);
+ wgpuTextureViewRelease(app.depthTextureView);
+ wgpuTextureDestroy(app.depthTexture);
+ wgpuTextureRelease(app.depthTexture);
+ wgpuBufferDestroy(app.uniformBuffer);
+ wgpuBufferRelease(app.uniformBuffer);
+ wgpuBufferDestroy(app.indexBuffer);
+ wgpuBufferRelease(app.indexBuffer);
+ wgpuBufferDestroy(app.vertexBuffer);
+ wgpuBufferRelease(app.vertexBuffer);
+ wgpuSurfaceRelease(app.surface);
+ wgpuQueueRelease(app.queue);
+ wgpuDeviceRelease(app.device);
+ wgpuAdapterRelease(app.adapter);
+ wgpuInstanceRelease(app.instance);
+
+ WEBGPU_DEMO_LOG("[WebGPU] Resources released");
+}
+
+void deinitGLFW(AppData& app)
+{
+ // === Destroy the window and terminate GLFW ===
+
+ glfwDestroyWindow(app.window);
+ glfwTerminate();
+ WEBGPU_DEMO_LOG("[GLFW] Window closed and terminated");
+}
+
+int main(int argc, const char* argv[])
+{
+ AppData app;
+ initGLFW(app);
+ initWebGPU(app);
double lastCursorX = 0.0f;
double lastCursorY = 0.0f;
// === Render loop ===
- while (!glfwWindowShouldClose(window))
+ while (!glfwWindowShouldClose(app.window))
{
// === Update cube model matrix ===
double cursorX;
double cursorY;
- glfwGetCursorPos(window, &cursorX, &cursorY);
+ glfwGetCursorPos(app.window, &cursorX, &cursorY);
- if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS)
+ if (glfwGetMouseButton(app.window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS)
{
- camRotX -= 0.25f * static_cast(cursorY - lastCursorY);
- camRotY -= 0.25f * static_cast(cursorX - lastCursorX);
+ app.camRotX -= 0.25f * static_cast(cursorY - lastCursorY);
+ app.camRotY -= 0.25f * static_cast(cursorX - lastCursorX);
}
lastCursorX = cursorX;
lastCursorY = cursorY;
- // === Create a WebGPU texture view ===
- // The texture view is where we render our image into.
-
- if (app.requireSurfaceReconfiguration)
- {
- app.requireSurfaceReconfiguration = false;
-
- // Get the window size from the GLFW window.
- glfwGetWindowSize(window, &surfaceWidth, &surfaceHeight);
-
- // The surface size might be zero if the window is minimized.
- if (surfaceWidth != 0 && surfaceHeight != 0)
- {
- WEBGPU_DEMO_LOG("[WebGPU] Re-configuring surface");
- surfaceConfig.width = surfaceWidth;
- surfaceConfig.height = surfaceHeight;
- wgpuSurfaceConfigure(app.surface, &surfaceConfig);
-
- // Recreate the depth texture.
-
- wgpuTextureViewRelease(textureView);
- wgpuTextureDestroy(depthTexture);
- wgpuTextureRelease(depthTexture);
-
- depthTextureDesc.size.width = surfaceWidth;
- depthTextureDesc.size.height = surfaceHeight;
-
- depthTexture = wgpuDeviceCreateTexture(app.device, &depthTextureDesc);
- WEBGPU_DEMO_CHECK(depthTexture, "[WebGPU] Failed to re-create depth texture");
- WEBGPU_DEMO_LOG("[WebGPU] Depth texture re-created");
-
- depthTextureView = wgpuTextureCreateView(depthTexture, &depthTextureViewDesc);
- WEBGPU_DEMO_CHECK(depthTextureView, "[WebGPU] Failed to re-create depth texture view");
- WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
- }
-
- // Skip this frame.
- glfwPollEvents();
- continue;
- }
-
- // Get a texture from the surface to render into.
- WGPUSurfaceTexture surfaceTexture;
- wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
-
- // The surface might change over time.
- // For example, the window might be resized or minimized.
- // We have to check the status and adapt to it.
- switch (surfaceTexture.status)
- {
- case WGPUSurfaceGetCurrentTextureStatus_Success:
- // Everything is ok, but still check for a suboptimal texture and re-configure it if needed.
- if (surfaceTexture.suboptimal)
- {
- WEBGPU_DEMO_LOG("[WebGPU] Re-configuring currently suboptimal surface");
- app.requireSurfaceReconfiguration = true;
- continue;
- }
-
- break;
-
- case WGPUSurfaceGetCurrentTextureStatus_Timeout:
- case WGPUSurfaceGetCurrentTextureStatus_Outdated:
- case WGPUSurfaceGetCurrentTextureStatus_Lost:
- // The surface needs to be re-configured.
- app.requireSurfaceReconfiguration = true;
- continue;
-
- case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
- case WGPUSurfaceGetCurrentTextureStatus_DeviceLost:
- // An error occured.
- WEBGPU_DEMO_CHECK(false, "[WebGPU] Failed to acquire current surface texture");
- break;
-
- case WGPUSurfaceGetCurrentTextureStatus_Force32:
- break;
- }
-
- // Create a view into the texture to specify where and how to modify the texture.
- WGPUTextureView view = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
-
- // === Prepare uniform data ===
- float aspectRatio = static_cast(surfaceWidth) / static_cast(surfaceHeight);
-
- SLMat4f modelMatrix;
-
- SLMat4f projectionMatrix;
- projectionMatrix.perspective(70.0f, aspectRatio, 0.1, 1000.0f);
-
- SLMat4f viewMatrix;
- viewMatrix.rotate(camRotY, SLVec3f::AXISY);
- viewMatrix.rotate(camRotX, SLVec3f::AXISX);
- viewMatrix.translate(0.0f, 0.0f, 2.0f);
- viewMatrix.invert();
-
- // === Update uniforms ===
- ShaderUniformData uniformData = {};
- std::memcpy(uniformData.projectionMatrix, projectionMatrix.m(), sizeof(uniformData.projectionMatrix));
- std::memcpy(uniformData.viewMatrix, viewMatrix.m(), sizeof(uniformData.viewMatrix));
- std::memcpy(uniformData.modelMatrix, modelMatrix.m(), sizeof(uniformData.modelMatrix));
- wgpuQueueWriteBuffer(queue, uniformBuffer, 0, &uniformData, sizeof(ShaderUniformData));
-
- // === Create a WebGPU command encoder ===
- // The encoder encodes the commands for the GPU into a command buffer.
-
- WGPUCommandEncoderDescriptor cmdEncoderDesc = {};
- cmdEncoderDesc.label = "Demo Command Encoder";
-
- WGPUCommandEncoder cmdEncoder = wgpuDeviceCreateCommandEncoder(app.device, &cmdEncoderDesc);
- WEBGPU_DEMO_CHECK(cmdEncoder, "[WebGPU] Failed to create command encoder");
-
- // === Create a WebGPU render pass ===
- // The render pass specifies what attachments to use while rendering.
- // A color attachment specifies what view to render into and what to do with the texture before and after
- // rendering. We clear the texture before rendering and store the results after rendering.
- // The depth attachment specifies what depth texture to use.
-
- WGPURenderPassColorAttachment colorAttachment = {};
- colorAttachment.view = view;
- colorAttachment.loadOp = WGPULoadOp_Clear;
- colorAttachment.storeOp = WGPUStoreOp_Store;
- colorAttachment.clearValue.r = 0.3;
- colorAttachment.clearValue.g = 0.0;
- colorAttachment.clearValue.b = 0.2;
- colorAttachment.clearValue.a = 1.0;
-
- WGPURenderPassDepthStencilAttachment depthStencilAttachment = {};
- depthStencilAttachment.view = depthTextureView;
- depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
- depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
- depthStencilAttachment.depthClearValue = 1.0f;
- depthStencilAttachment.depthReadOnly = false;
- depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
- depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
- depthStencilAttachment.stencilClearValue = 0.0f;
- depthStencilAttachment.stencilReadOnly = true;
-
- WGPURenderPassDescriptor renderPassDesc = {};
- renderPassDesc.label = "Demo Render Pass";
- renderPassDesc.colorAttachmentCount = 1;
- renderPassDesc.colorAttachments = &colorAttachment;
- renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
-
- // === Encode the commands ===
- // The commands to begin a render pass, bind a pipeline, draw the triangle and end the render pass
- // are encoded into a buffer.
-
- WGPURenderPassEncoder renderPassEncoder = wgpuCommandEncoderBeginRenderPass(cmdEncoder, &renderPassDesc);
- wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipeline);
- wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, vertexBuffer, 0, vertexDataSize);
- wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, indexBuffer, WGPUIndexFormat_Uint16, 0, indexDataSize);
- wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroup, 0, nullptr);
- wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
- wgpuRenderPassEncoderEnd(renderPassEncoder);
-
- // === Get the command buffer ===
- // The command encoder is finished to get the commands for the GPU to execute in a command buffer.
-
- WGPUCommandBufferDescriptor cmdBufferDesc = {};
- cmdBufferDesc.label = "Demo Command Buffer";
-
- WGPUCommandBuffer cmdBuffer = wgpuCommandEncoderFinish(cmdEncoder, &cmdBufferDesc);
-
- // === Submit the command buffer to the GPU ===
- // The work for the GPU is submitted through the queue and executed.
- wgpuQueueSubmit(queue, 1, &cmdBuffer);
-
- // === Present the surface ===
- // This presents our rendered texture to the screen.
- wgpuSurfacePresent(app.surface);
-
- // === Clean up resources ===
- wgpuCommandBufferRelease(cmdBuffer);
- wgpuRenderPassEncoderRelease(renderPassEncoder);
- wgpuCommandEncoderRelease(cmdEncoder);
- wgpuTextureViewRelease(view);
- wgpuTextureRelease(surfaceTexture.texture);
-
+ onPaint(app);
glfwPollEvents();
}
- // === Release all WebGPU resources ===
-
- wgpuRenderPipelineRelease(pipeline);
- wgpuPipelineLayoutRelease(pipelineLayout);
- wgpuBindGroupRelease(bindGroup);
- wgpuBindGroupLayoutRelease(bindGroupLayout);
- wgpuShaderModuleRelease(shaderModule);
- wgpuSamplerRelease(sampler);
- wgpuTextureViewRelease(textureView);
- wgpuTextureDestroy(texture);
- wgpuTextureRelease(texture);
- wgpuTextureViewRelease(depthTextureView);
- wgpuTextureDestroy(depthTexture);
- wgpuTextureRelease(depthTexture);
- wgpuBufferDestroy(uniformBuffer);
- wgpuBufferRelease(uniformBuffer);
- wgpuBufferDestroy(indexBuffer);
- wgpuBufferRelease(indexBuffer);
- wgpuBufferDestroy(vertexBuffer);
- wgpuBufferRelease(vertexBuffer);
- wgpuSurfaceRelease(app.surface);
- wgpuQueueRelease(queue);
- wgpuDeviceRelease(app.device);
- wgpuAdapterRelease(adapter);
- wgpuInstanceRelease(instance);
- WEBGPU_DEMO_LOG("[WebGPU] Resources released");
-
- // === Destroy the window and terminate GLFW ===
-
- glfwDestroyWindow(window);
- glfwTerminate();
- WEBGPU_DEMO_LOG("[GLFW] Window closed and terminated");
+ deinitWebGPU(app);
+ deinitGLFW(app);
return 0;
}
\ No newline at end of file
From d3d5336a3ce729f49e616925a7a4e7fad2775cb9 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 9 Nov 2023 12:23:50 +0100
Subject: [PATCH 048/108] [WebGPU] Add normal mapping to demo
---
apps/webgpu/main.cpp | 138 ++++++++++++++++++++++++++-----------------
1 file changed, 84 insertions(+), 54 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 316b3fa5..b52d794d 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -77,6 +77,18 @@ struct AppData
float camZ = 2.0f;
};
+struct VertexData
+{
+ float positionX;
+ float positionY;
+ float positionZ;
+ float normalX;
+ float normalY;
+ float normalZ;
+ float uvX;
+ float uvY;
+};
+
struct alignas(16) ShaderUniformData
{
float projectionMatrix[16];
@@ -124,6 +136,9 @@ void reconfigureSurface(AppData& app)
void onPaint(AppData& app)
{
+ if (app.surfaceWidth == 0 || app.surfaceHeight == 0)
+ return;
+
// Get a texture from the surface to render into.
WGPUSurfaceTexture surfaceTexture;
wgpuSurfaceGetCurrentTexture(app.surface, &surfaceTexture);
@@ -345,11 +360,11 @@ void initWebGPU(AppData& app)
// which is how WebGPU prevents code from working on one machine and not on another.
WGPURequiredLimits requiredLimits = {};
- requiredLimits.limits.maxVertexAttributes = 2u;
+ requiredLimits.limits.maxVertexAttributes = 3u;
requiredLimits.limits.maxVertexBuffers = 1u;
- requiredLimits.limits.maxBufferSize = 1024ull;
- requiredLimits.limits.maxVertexBufferArrayStride = 5u * sizeof(float);
- requiredLimits.limits.maxInterStageShaderComponents = 2u;
+ requiredLimits.limits.maxBufferSize = 2048ull;
+ requiredLimits.limits.maxVertexBufferArrayStride = sizeof(VertexData);
+ requiredLimits.limits.maxInterStageShaderComponents = 5u;
requiredLimits.limits.maxBindGroups = 1u;
requiredLimits.limits.maxBindingsPerBindGroup = 3u;
requiredLimits.limits.maxUniformBuffersPerShaderStage = 1u;
@@ -429,60 +444,60 @@ void initWebGPU(AppData& app)
// The vertex buffer contains the input data for the shader.
// clang-format off
- std::vector vertexData =
+ std::vector vertexData =
{
// left
- -0.5, 0.5, -0.5, 0.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, -0.5, 0.5, 1.0f, 1.0f,
+ {-0.5, 0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ {-0.5, -0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ {-0.5, 0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
+ {-0.5, 0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
+ {-0.5, -0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ {-0.5, -0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
// right
- 0.5, 0.5, 0.5, 0.0f, 0.0f,
- 0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, -0.5, -0.5, 1.0f, 1.0f,
+ { 0.5, 0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ { 0.5, -0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, 0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
+ { 0.5, 0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
+ { 0.5, -0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, -0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
// bottom
- -0.5, -0.5, 0.5, 0.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- 0.5, -0.5, 0.5, 1.0f, 0.0f,
- 0.5, -0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, -0.5, 0.0f, 1.0f,
- 0.5, -0.5, -0.5, 1.0f, 1.0f,
+ {-0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f},
+ {-0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f},
+ { 0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f},
+ {-0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f},
// top
- -0.5, 0.5, -0.5, 0.0f, 0.0f,
- -0.5, 0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, 0.5, -0.5, 1.0f, 0.0f,
- -0.5, 0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, 0.5, 1.0f, 1.0f,
+ {-0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
+ {-0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
+ { 0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
+ {-0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},
+ { 0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f},
// back
- 0.5, 0.5, -0.5, 0.0f, 0.0f,
- 0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, 0.5, -0.5, 1.0f, 0.0f,
- -0.5, 0.5, -0.5, 1.0f, 0.0f,
- 0.5, -0.5, -0.5, 0.0f, 1.0f,
- -0.5, -0.5, -0.5, 1.0f, 1.0f,
+ { 0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
+ { 0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f},
+ {-0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
+ {-0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
+ { 0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f},
+ {-0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f},
// front
- -0.5, 0.5, 0.5, 0.0f, 0.0f,
- -0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, 0.5, 0.5, 1.0f, 0.0f,
- 0.5, 0.5, 0.5, 1.0f, 0.0f,
- -0.5, -0.5, 0.5, 0.0f, 1.0f,
- 0.5, -0.5, 0.5, 1.0f, 1.0f,
+ {-0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
+ {-0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { 0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f},
+ { 0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f},
+ {-0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { 0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f},
};
// clang-format on
- unsigned vertexCount = vertexData.size() / 5;
- app.vertexDataSize = vertexData.size() * sizeof(float);
+ unsigned vertexCount = vertexData.size();
+ app.vertexDataSize = vertexData.size() * sizeof(VertexData);
WGPUBufferDescriptor vertexBufferDesc = {};
vertexBufferDesc.label = "Demo Vertex Buffer";
@@ -587,7 +602,7 @@ void initWebGPU(AppData& app)
WEBGPU_DEMO_CHECK(app.texture, "[WebGPU] Failed to create texture");
WEBGPU_DEMO_LOG("[WebGPU] Texture created");
- // Where do we copyu the pixel data to?
+ // Where do we copy the pixel data to?
WGPUImageCopyTexture destination = {};
destination.texture = app.texture;
destination.mipLevel = 0;
@@ -691,7 +706,8 @@ void initWebGPU(AppData& app)
const char* shaderSource = R"(
struct VertexInput {
@location(0) position: vec3f,
- @location(1) uvs: vec2f,
+ @location(1) normal: vec3f,
+ @location(2) uv: vec2f,
};
struct Uniforms {
@@ -702,9 +718,12 @@ void initWebGPU(AppData& app)
struct VertexOutput {
@builtin(position) position: vec4f,
- @location(0) uvs: vec2f,
+ @location(0) worldNormal: vec3f,
+ @location(1) uv: vec2f,
}
+ const LIGHT_DIR = vec3f(4.0, -8.0, 1.0);
+
@group(0) @binding(0) var uniforms: Uniforms;
@group(0) @binding(1) var texture: texture_2d;
@group(0) @binding(2) var textureSampler: sampler;
@@ -716,13 +735,19 @@ void initWebGPU(AppData& app)
var out: VertexOutput;
out.position = uniforms.projectionMatrix * uniforms.viewMatrix * worldPos;
- out.uvs = in.uvs;
+ out.worldNormal = in.normal;
+ out.uv = in.uv;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
- return textureSample(texture, textureSampler, in.uvs).rgba;
+ var baseColor = textureSample(texture, textureSampler, in.uv);
+
+ var diffuse = dot(-normalize(in.worldNormal), normalize(LIGHT_DIR));
+ diffuse = diffuse * 0.5 + 0.5;
+
+ return vec4(baseColor.rgb * diffuse, baseColor.a);
}
)";
@@ -825,16 +850,21 @@ void initWebGPU(AppData& app)
positionAttribute.offset = 0;
positionAttribute.shaderLocation = 0;
- WGPUVertexAttribute uvsAttribute = {};
- uvsAttribute.format = WGPUVertexFormat_Float32x2;
- uvsAttribute.offset = 3 * sizeof(float);
- uvsAttribute.shaderLocation = 1;
+ WGPUVertexAttribute normalAttribute = {};
+ normalAttribute.format = WGPUVertexFormat_Float32x3;
+ normalAttribute.offset = 3 * sizeof(float);
+ normalAttribute.shaderLocation = 1;
+
+ WGPUVertexAttribute uvAttribute = {};
+ uvAttribute.format = WGPUVertexFormat_Float32x2;
+ uvAttribute.offset = 6 * sizeof(float);
+ uvAttribute.shaderLocation = 2;
- std::vector vertexAttributes = {positionAttribute, uvsAttribute};
+ std::vector vertexAttributes = {positionAttribute, normalAttribute, uvAttribute};
// Description of the vertex buffer layout for the vertex shader stage
WGPUVertexBufferLayout vertexBufferLayout = {};
- vertexBufferLayout.arrayStride = 5ull * sizeof(float);
+ vertexBufferLayout.arrayStride = sizeof(VertexData);
vertexBufferLayout.stepMode = WGPUVertexStepMode_Vertex;
vertexBufferLayout.attributeCount = vertexAttributes.size();
vertexBufferLayout.attributes = vertexAttributes.data();
From c4963b915493524809a92683611977c9a72cde3e Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Thu, 9 Nov 2023 15:21:59 +0100
Subject: [PATCH 049/108] Update main.cpp
---
apps/webgpu/main.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index e4c2999a..7e154334 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -130,7 +130,7 @@ int main(int argc, const char* argv[])
// === Acquire a WebGPU device ===
// A device provides access to a GPU and is created from an adapter.
- // We specify the capabilites that we require our device to have in requiredLimits.
+ // We specify the capabilities that we require our device to have in requiredLimits.
// We cannot access more resources than specified in the required limits,
// which is how WebGPU prevents code from working on one machine and not on another.
From f0420edab9e946498d63b2a5be4836eac7d49cfa Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 13 Nov 2023 10:44:52 +0100
Subject: [PATCH 050/108] [WebGPU] Document WebGPU concepts
---
apps/webgpu/main.cpp | 200 ++++++++++++++++++++++++++++++++-----------
1 file changed, 151 insertions(+), 49 deletions(-)
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/main.cpp
index 71c488b1..93f9b41c 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/main.cpp
@@ -28,7 +28,7 @@
#include
#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
-
+
#define WEBGPU_DEMO_CHECK(condition, errorMsg) \
if (!(condition)) \
{ \
@@ -36,7 +36,134 @@
std::exit(1); \
}
-struct AppData
+/*
+To interact with WebGPU, we create objects with a call to wgpu*Create*. This function normally takes the parent
+object as a parameter and a WGPU*Descriptor that contains the specification for the object. The returned object
+is released after usage with a call to wgpuRelease*. An object can have a label that is used when reporting errors.
+
+WebGPU concepts:
+ - WGPUInstance
+ The core interface through which all other objects are created.
+
+ - WGPUAdapter
+ Represents a physical device and is used to query its capabilities and limits.
+
+ - WGPUDevice
+ Represents a logical device we interact with. It is created by specifying the capabilities we require
+ and fails if the adapter does not support them. We cannot create more resources than specified in the
+ limits at creation. This is done to prevent a function from working on one device but not on another.
+
+ - WGPUQueue
+ The queue is where we submit the commands for the GPU to. Everything that is executed on the GPU goes
+ through the queue. Examples are executing rendering or compute pipelines, writing to or reading from buffers.
+
+ - WGPUSurface
+ The surface we draw onto. How it is acquired depends on the OS so we have to manually convert window handles
+ from the different platforms to surfaces. The surface has to be reconfigured every time the window size
+ changes.
+
+ - WGPUBuffer
+ Represents a chunk of memory on the GPU. They can be used for example as vertex buffers, uniforms buffers or
+ storage buffers. Buffers are created with a fixed size and usage flags that specify e.g. whether we can copy
+ to this buffer or whether it is used as an index buffer. The memory for the buffer is automatically allocated
+ at creation but has to be deallocated manually using wgpuBufferDestroy. wgpuQueueWriteBuffer is used to upload
+ buffer data to the GPU.
+
+ - WGPUTexture
+ Represents pixel data in the memory of the GPU. It is similar to a buffer in that memory for it is allocated at
+ creation, that it has usage flags and that the memory is deallocated using wgpuTextureDestroy. Data is uploaded
+ using wgpuQueueWriteTexture. A texture additionally has a size, a format, a mip level count and a sample count.
+ Textures can be used in shaders or as a render attachment (e.g. the depth buffer). Mip maps have to be created
+ manually.
+
+ - WGPUTextureView
+ To use a texture, a texture view has to be created. It specifies which part of the texture is accessed
+ (which base array layer, how many array layers, which base mip level, which format, ...).
+
+ - WGPUTextureSampler
+ To read a texture in a shader, a sampler is commonly used. Textures can also be accessed directly without a
+ sampler by specifying texel coordinates, which is more like reading the data from a buffer. To get access to
+ features like filtering, mipmapping or clamping, a sampler is used.
+
+ - WGPURenderPipeline
+ Represents a configuration of the GPU pipeline. It specifies completely how input data is transformed into
+ output pixels by settings the configuration for the GPU pipeline stages.
+
+ The WebGPU render pipeline model looks like this:
+ 1. vertex fetch
+ 2. vertex shader
+ 3. primitive assembly
+ 4. rasterization
+ 5. fragment shader
+ 6. stencil test and write
+ 7. depth test and write
+ 8. blending
+ 9. write to attachments
+
+ The descriptor for this structure contains the following configurations:
+
+ - layout: WGPUPipelineLayout
+ - vertex: WGPUVertexState
+ Configuration for the vertex fetch and vertex shader stages.
+ Specifies the shader module to run as well as the buffers and constants used.
+ A vertex buffer is specified using a WGPUVertexBufferLayout structure that contains a list of
+ attributes (WGPUVertexAttribute) along with the stride and step mode (per vertex or per instance).
+ Attributes are specified through a format, an offset in the data and a location in the shader.
+ The location is a number hard-coded for the attribute in the shader code.
+ - primitive: WGPUPrimitiveState
+ Configuration for the primitive assembly and rasterization stages.
+ Specifies the topology (triangles, triangle strips, lines, ...), what index format
+ is used, how the face orientation of triangles is defined and the cull mode.
+ - depthStencil: WGPUDepthStencilState
+ Configuration for the depth test and stencil test stages.
+ Specifies the format of the depth/stencil buffer and how depth and stencil testing are performed.
+ - multisample: WGPUMultisampleState
+ Configuration for multisampling.
+ Specifies the number of samples per pixel as well as additional parameters for muiltisampling.
+ - fragment: WGPUFragmentState
+ Configuration for the fragment shader and blending stages.
+ Specifies the shader module to run as well as the buffers and constants used.
+ This state also specifies a list of color targets that are rendered into which contains
+ additional configuration such as the color attachement format and the blending mode.
+
+ - WGPUShaderModule
+ Represents a shader on the GPU. It is created by specifying code in either the WebGPU shading language (WGSL)
+ or the SPIR-V format (not support on the Web). This code is then compiled by the WebGPU implementation to a
+ backend-specific shader format such as SPIR-V for Vulkan or MSL for Metal. A shader can have multiple entry
+ points, making it possible to use one shader module for both the vertex shader and fragment shader stage.
+
+ - WGPUBindGroup
+ A list of resources bound in a shader. Resources can be buffers, samplers or texture views. Each bind group
+ entry contains a binding (a unique number assigned to the resource in the shader code), the buffer, sampler or
+ texture view bound, an offset and a size. Multiple bind groups can be set per render pass.
+
+ - WGPUBindGroupLayout
+ A list of layouts for bind groups. A bind group references its layout and they both have to have the same
+ number of entries. The entries describe the binding, which shader stages can access it as well as additional
+ info depending on the type. For example, buffer bind group layout entries specify whether they are a uniform
+ buffer, a storage buffer or read-only storage.
+
+ - WGPUPipelineLayout
+ Specifies the bind groups used in the pipeline.
+
+ - WGPUCommandEncoder
+ Work for the GPU has to be recorded into a command buffer. This is done using a command encoder. We call
+ functions on the encoder (wgpuCommandEncoder*) to encode the commands into a buffer that can be accessed by
+ calling wgpuCommandEncoderFinish.
+
+ - WGPUCommandBuffer
+ When all the GPU commands are recorded, wgpuCommandEncoderFinish is called on the queue which returns a
+ command buffer. This buffer can then be submitted to the GPU using wgpuQueueSubmit.
+
+ - WGPURenderPassEncoder
+ Specifies how a render pipeline is executed. It encodes the pipeline used along with the required vertex
+ buffers, index buffers, bind groups, drawing commands, etc. Accessing these render commands is done using a
+ specialized object called a render pass encoder. It is created from a command encoder using
+ wgpuCommandEncoderBeginRenderPass.
+
+*/
+
+struct App
{
GLFWwindow* window = nullptr;
int surfaceWidth = 0;
@@ -47,11 +174,11 @@ struct AppData
WGPUDevice device = nullptr;
WGPUQueue queue = nullptr;
WGPUSurface surface = nullptr;
- WGPUTexture depthTexture = nullptr;
- WGPUTextureView depthTextureView = nullptr;
WGPUBuffer vertexBuffer = nullptr;
WGPUBuffer indexBuffer = nullptr;
WGPUBuffer uniformBuffer = nullptr;
+ WGPUTexture depthTexture = nullptr;
+ WGPUTextureView depthTextureView = nullptr;
WGPUTexture texture = nullptr;
WGPUTextureView textureView = nullptr;
WGPUSampler sampler = nullptr;
@@ -70,8 +197,6 @@ struct AppData
unsigned indexCount;
unsigned indexDataSize;
- bool requireSurfaceReconfiguration = false;
-
float camRotX = 0.0f;
float camRotY = 0.0f;
float camZ = 2.0f;
@@ -102,7 +227,7 @@ static_assert(sizeof(ShaderUniformData) % 16 == 0, "uniform data size must be a
extern "C" void* createMetalLayer(void* window);
#endif
-void reconfigureSurface(AppData& app)
+void reconfigureSurface(App& app)
{
// Get the window size from the GLFW window.
glfwGetWindowSize(app.window, &app.surfaceWidth, &app.surfaceHeight);
@@ -134,7 +259,7 @@ void reconfigureSurface(AppData& app)
WEBGPU_DEMO_LOG("[WebGPU] Depth texture view re-created");
}
-void onPaint(AppData& app)
+void onPaint(App& app)
{
if (app.surfaceWidth == 0 || app.surfaceHeight == 0)
return;
@@ -283,12 +408,12 @@ void onPaint(AppData& app)
void onResize(GLFWwindow* window, int width, int height)
{
- AppData& app = *((AppData*)glfwGetWindowUserPointer(window));
+ App& app = *((App*)glfwGetWindowUserPointer(window));
reconfigureSurface(app);
onPaint(app);
}
-void initGLFW(AppData& app)
+void initGLFW(App& app)
{
// === Initialize GLFW ===
@@ -334,7 +459,7 @@ void handleDeviceRequest(WGPURequestDeviceStatus status,
*outDevice = device;
}
-void initWebGPU(AppData& app)
+void initWebGPU(App& app)
{
// === Create a WebGPU instance ===
// The instance is the root interface to WebGPU through which we create all other WebGPU resources.
@@ -450,48 +575,36 @@ void initWebGPU(AppData& app)
{-0.5, 0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{-0.5, -0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{-0.5, 0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
- {-0.5, 0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
- {-0.5, -0.5, -0.5, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{-0.5, -0.5, 0.5, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
// right
{ 0.5, 0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
{ 0.5, -0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, 0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
- { 0.5, 0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
- { 0.5, -0.5, 0.5, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, -0.5, -0.5, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
// bottom
{-0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f},
{-0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f},
- { 0.5, -0.5, 0.5, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f},
- {-0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, -0.5, -0.5, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f},
// top
{-0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
{-0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
- { 0.5, 0.5, -0.5, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
- {-0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},
{ 0.5, 0.5, 0.5, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f},
// back
{ 0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
{ 0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f},
{-0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
- {-0.5, 0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
- { 0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f},
{-0.5, -0.5, -0.5, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f},
// front
{-0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
{-0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{ 0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f},
- { 0.5, 0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f},
- {-0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
{ 0.5, -0.5, 0.5, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f},
};
// clang-format on
@@ -513,9 +626,17 @@ void initWebGPU(AppData& app)
// === Create the index buffer ===
- std::vector indexData = {};
- for (std::uint16_t index = 0; index < 36; index++)
- indexData.push_back(index);
+ // clang-format off
+ std::vector indexData =
+ {
+ 0, 1, 2, 2, 1, 3, // left
+ 4, 5, 6, 6, 5, 7, // right
+ 8, 9, 10, 10, 9, 11, // bottom
+ 12, 13, 14, 14, 13, 15, // top
+ 16, 17, 18, 18, 17, 19, // back
+ 20, 21, 22, 22, 21, 23, // front
+ };
+ // clang-format on
app.indexCount = indexData.size();
app.indexDataSize = indexData.size() * sizeof(std::uint16_t);
@@ -626,25 +747,6 @@ void initWebGPU(AppData& app)
for (unsigned mipLevel = 0; mipLevel < textureDesc.mipLevelCount; mipLevel++)
{
- // === Test colors ===
- //
- // std::uint64_t mipLevelColors[] =
- // {
- // 0xFF0000FF,
- // 0xFFFF00FF,
- // 0x00FF00FF,
- // 0x0000FFFF
- // };
- //
- // for (unsigned y = 0; y < mipLevelSize.height; y++)
- // {
- // for (unsigned x = 0; x < mipLevelSize.width; x++)
- // {
- // unsigned pixelIndex = x + y * mipLevelSize.width;
- // std::memcpy(&mipLevelData[4ull * pixelIndex], &mipLevelColors[mipLevel], 4);
- // }
- // }
-
cv::Mat mipLevelImage;
cv::Size cvSize(static_cast(mipLevelSize.width), static_cast(mipLevelSize.height));
cv::resize(image, mipLevelImage, cvSize);
@@ -881,7 +983,7 @@ void initWebGPU(AppData& app)
primitiveState.topology = WGPUPrimitiveTopology_TriangleList;
primitiveState.stripIndexFormat = WGPUIndexFormat_Undefined;
primitiveState.frontFace = WGPUFrontFace_CCW;
- primitiveState.cullMode = WGPUCullMode_None;
+ primitiveState.cullMode = WGPUCullMode_Back;
// Configuration for depth testing and stencil buffer
WGPUDepthStencilState depthStencilState = {};
@@ -929,7 +1031,7 @@ void initWebGPU(AppData& app)
WEBGPU_DEMO_LOG("[WebGPU] Render pipeline created");
}
-void deinitWebGPU(AppData& app)
+void deinitWebGPU(App& app)
{
// === Release all WebGPU resources ===
@@ -960,7 +1062,7 @@ void deinitWebGPU(AppData& app)
WEBGPU_DEMO_LOG("[WebGPU] Resources released");
}
-void deinitGLFW(AppData& app)
+void deinitGLFW(App& app)
{
// === Destroy the window and terminate GLFW ===
@@ -971,7 +1073,7 @@ void deinitGLFW(AppData& app)
int main(int argc, const char* argv[])
{
- AppData app;
+ App app;
initGLFW(app);
initWebGPU(app);
From e664fef40905a78f37581e24658b95c09181e89d Mon Sep 17 00:00:00 2001
From: luc
Date: Mon, 13 Nov 2023 17:51:13 +0100
Subject: [PATCH 051/108] Rename (renderInstanced, instanced,
instancedRendering) boolean to only renderInstanced for consistancy
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 6 +++---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 8 ++++----
modules/sl/source/gl/SLGLProgramGenerated.h | 4 ++--
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 120b4584..32abad82 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -3774,10 +3774,10 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
ps->isGenerated(false);
}
- bool instanced = ps->renderInstanced();
- if (ImGui::Checkbox("Instanced draw", &instanced))
+ bool renderInstanced = ps->renderInstanced();
+ if (ImGui::Checkbox("Instanced draw", &renderInstanced))
{
- ps->drawInstanced(instanced);
+ ps->drawInstanced(renderInstanced);
ps->isGenerated(false);
}
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 9ca65363..f191d48f 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -1856,7 +1856,7 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
string& programName,
bool isDrawProg,
- bool instancedRendering)
+ bool renderInstanced)
{
assert(mat && "No material pointer passed!");
programName = "gen";
@@ -1871,7 +1871,7 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
{
programName += "-Draw";
- if (instancedRendering)
+ if (renderInstanced)
programName += "-Inst";
programName += mat->texturesString();
@@ -1976,7 +1976,7 @@ void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
* @param mat Parent material pointer
* @param isDrawProg Flag if program is for drawing instead of update
*/
-void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool isRenderInstanced)
+void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool renderInstanced)
{
if (mat->name() == "IBLMat")
{
@@ -1989,7 +1989,7 @@ void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg,
if (isDrawProg)
{
- if (isRenderInstanced)
+ if (renderInstanced)
buildPerPixParticleInstanced(mat);
else
buildPerPixParticle(mat);
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index bd2fe05b..39738407 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -99,9 +99,9 @@ class SLGLProgramGenerated : public SLGLProgram
static void buildProgramNamePS(SLMaterial* mat,
string& programName,
bool isDrawProg,
- bool instancedRendering);
+ bool renderInstanced);
- void buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool isRenderInstanced = false);
+ void buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool renderInstanced = false);
void buildProgramCode(SLMaterial* mat,
SLVLight* lights);
void beginShader(SLCamera* cam,
From 32f7b049e0941bf4338b01f2962ea8056f089ce5 Mon Sep 17 00:00:00 2001
From: luc
Date: Mon, 13 Nov 2023 18:03:27 +0100
Subject: [PATCH 052/108] If geometry shader not supported, particle system
automatically use draw instanced
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 46 +-
.../app_demo_slproject/source/AppDemoLoad.cpp | 722 +++++++++---------
modules/sl/source/mesh/SLParticleSystem.cpp | 10 +-
3 files changed, 379 insertions(+), 399 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 32abad82..7f18410b 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -1775,27 +1775,20 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
if (ImGui::BeginMenu("Particle Systems"))
{
- if (stateGL->glHasGeometryShaders())
- {
- if (ImGui::MenuItem("First Particle System", nullptr, sid == SID_ParticleSystem_First))
- s->onLoad(am, s, sv, SID_ParticleSystem_First);
- if (ImGui::MenuItem("Demo Particle System", nullptr, sid == SID_ParticleSystem_Demo))
- s->onLoad(am, s, sv, SID_ParticleSystem_Demo);
- if (ImGui::MenuItem("Dust Storm Particle System", nullptr, sid == SID_ParticleSystem_DustStorm))
- s->onLoad(am, s, sv, SID_ParticleSystem_DustStorm);
- if (ImGui::MenuItem("Fountain Particle System", nullptr, sid == SID_ParticleSystem_Fountain))
- s->onLoad(am, s, sv, SID_ParticleSystem_Fountain);
- if (ImGui::MenuItem("Sun Particle System", nullptr, sid == SID_ParticleSystem_Sun))
- s->onLoad(am, s, sv, SID_ParticleSystem_Sun);
- if (ImGui::MenuItem("Ring of Fire Particle System", nullptr, sid == SID_ParticleSystem_RingOfFire))
- s->onLoad(am, s, sv, SID_ParticleSystem_RingOfFire);
- if (ImGui::MenuItem("Complex Fire Particle System", nullptr, sid == SID_ParticleSystem_FireComplex))
- s->onLoad(am, s, sv, SID_ParticleSystem_FireComplex);
- }
- else
- {
- ImGui::MenuItem("Particles need OpenGL >= 4.0 or OpenGLES >= 3.1", nullptr, false, false);
- }
+ if (ImGui::MenuItem("First Particle System", nullptr, sid == SID_ParticleSystem_First))
+ s->onLoad(am, s, sv, SID_ParticleSystem_First);
+ if (ImGui::MenuItem("Demo Particle System", nullptr, sid == SID_ParticleSystem_Demo))
+ s->onLoad(am, s, sv, SID_ParticleSystem_Demo);
+ if (ImGui::MenuItem("Dust Storm Particle System", nullptr, sid == SID_ParticleSystem_DustStorm))
+ s->onLoad(am, s, sv, SID_ParticleSystem_DustStorm);
+ if (ImGui::MenuItem("Fountain Particle System", nullptr, sid == SID_ParticleSystem_Fountain))
+ s->onLoad(am, s, sv, SID_ParticleSystem_Fountain);
+ if (ImGui::MenuItem("Sun Particle System", nullptr, sid == SID_ParticleSystem_Sun))
+ s->onLoad(am, s, sv, SID_ParticleSystem_Sun);
+ if (ImGui::MenuItem("Ring of Fire Particle System", nullptr, sid == SID_ParticleSystem_RingOfFire))
+ s->onLoad(am, s, sv, SID_ParticleSystem_RingOfFire);
+ if (ImGui::MenuItem("Complex Fire Particle System", nullptr, sid == SID_ParticleSystem_FireComplex))
+ s->onLoad(am, s, sv, SID_ParticleSystem_FireComplex);
ImGui::EndMenu();
}
@@ -1964,13 +1957,10 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
s->onLoad(am, s, sv, SID_Benchmark6_ColumnsLOD);
if (ImGui::MenuItem("Jan's Universe", nullptr, sid == SID_Benchmark7_JansUniverse))
s->onLoad(am, s, sv, SID_Benchmark7_JansUniverse);
- if (stateGL->glHasGeometryShaders())
- {
- if (ImGui::MenuItem("Particle System lot of fire complex", nullptr, sid == SID_Benchmark8_ParticleSystemFireComplex))
- s->onLoad(am, s, sv, SID_Benchmark8_ParticleSystemFireComplex);
- if (ImGui::MenuItem("Particle System lot of particle", nullptr, sid == SID_Benchmark9_ParticleSystemManyParticles))
- s->onLoad(am, s, sv, SID_Benchmark9_ParticleSystemManyParticles);
- }
+ if (ImGui::MenuItem("Particle System lot of fire complex", nullptr, sid == SID_Benchmark8_ParticleSystemFireComplex))
+ s->onLoad(am, s, sv, SID_Benchmark8_ParticleSystemFireComplex);
+ if (ImGui::MenuItem("Particle System lot of particle", nullptr, sid == SID_Benchmark9_ParticleSystemManyParticles))
+ s->onLoad(am, s, sv, SID_Benchmark9_ParticleSystemManyParticles);
ImGui::EndMenu();
}
diff --git a/apps/app_demo_slproject/source/AppDemoLoad.cpp b/apps/app_demo_slproject/source/AppDemoLoad.cpp
index 34390c1b..d65088ca 100644
--- a/apps/app_demo_slproject/source/AppDemoLoad.cpp
+++ b/apps/app_demo_slproject/source/AppDemoLoad.cpp
@@ -5868,419 +5868,401 @@ resolution shadows near the camera and lower resolution shadows further away.");
}
else if (sceneID == SID_ParticleSystem_Demo) //................................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Simple Demo Particle System");
- s->info("This most simple single particle system is meant to be improved by adding more and more features in the properties list.");
+ // Set scene name and info string
+ s->name("Simple Demo Particle System");
+ s->info("This most simple single particle system is meant to be improved by adding more and more features in the properties list.");
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 1,
- SLVec3f(0.04f, 0.4f, 0.1f),
- SLVec3f(-0.11f, 0.7f, -0.1f),
- 4.0f,
- texC,
- "Particle System",
- texFlipbook);
- ps->doAlphaOverLT(false);
- ps->doSizeOverLT(false);
- ps->doRotation(false);
- ps->doColor(false);
- ps->acceleration(-0.5, 0.0, 0.0);
- ps->timeToLive(2.0f);
- SLMesh* pSMesh = ps;
- SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
- scene->addChild(pSNode);
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 1,
+ SLVec3f(0.04f, 0.4f, 0.1f),
+ SLVec3f(-0.11f, 0.7f, -0.1f),
+ 4.0f,
+ texC,
+ "Particle System",
+ texFlipbook);
+ ps->doAlphaOverLT(false);
+ ps->doSizeOverLT(false);
+ ps->doRotation(false);
+ ps->doColor(false);
+ ps->acceleration(-0.5, 0.0, 0.0);
+ ps->timeToLive(2.0f);
+ SLMesh* pSMesh = ps;
+ SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
+ scene->addChild(pSNode);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_DustStorm) //...........................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Dust storm particle system");
- s->info("This dust storm particle system uses the box shape type for distribution.\n"
- "See the properties window for the detailed settings of the particles system");
-
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
-
- // Create and add camera
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->translation(0, 0, 55);
- cam1->lookAt(0, 0, 0);
- cam1->focalDist(55);
- scene->addChild(cam1);
- sv->camera(cam1);
+ // Set scene name and info string
+ s->name("Dust storm particle system");
+ s->info("This dust storm particle system uses the box shape type for distribution.\n"
+ "See the properties window for the detailed settings of the particles system");
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbookSmoke = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- // Create meshes and nodes
- // Dust storm
- SLParticleSystem* ps = new SLParticleSystem(am,
- 500,
- SLVec3f(-0.1f, -0.5f, -5.0f),
- SLVec3f(0.1f, 0.5f, -2.5f),
- 3.5f,
- texC,
- "DustStorm",
- texFlipbookSmoke);
- ps->doShape(true);
- ps->shapeType(ST_Box);
- ps->shapeScale(50.0f, 1.0f, 50.0f);
- ps->scale(15.0f);
- ps->doSizeOverLT(false);
- ps->doAlphaOverLT(true);
- ps->doAlphaOverLTCurve(true);
- ps->bezierStartEndPointAlpha()[1] = 0.0f;
- ps->bezierControlPointAlpha()[1] = 0.5f;
- ps->bezierControlPointAlpha()[2] = 0.5f;
- ps->generateBernsteinPAlpha();
- ps->doRotRange(true);
- ps->color(SLCol4f(1.0f, 1.0f, 1.0f, 1.0f));
- ps->doBlendBrightness(false);
- ps->frameRateFB(16);
+ // Create and add camera
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->translation(0, 0, 55);
+ cam1->lookAt(0, 0, 0);
+ cam1->focalDist(55);
+ scene->addChild(cam1);
+ sv->camera(cam1);
- SLMesh* pSMesh = ps;
- SLNode* pSNode = new SLNode(pSMesh, "Particle system node fire2");
- pSNode->translate(3.0f, -0.8f, 0.0f, TS_object);
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbookSmoke = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- scene->addChild(pSNode);
+ // Create meshes and nodes
+ // Dust storm
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 500,
+ SLVec3f(-0.1f, -0.5f, -5.0f),
+ SLVec3f(0.1f, 0.5f, -2.5f),
+ 3.5f,
+ texC,
+ "DustStorm",
+ texFlipbookSmoke);
+ ps->doShape(true);
+ ps->shapeType(ST_Box);
+ ps->shapeScale(50.0f, 1.0f, 50.0f);
+ ps->scale(15.0f);
+ ps->doSizeOverLT(false);
+ ps->doAlphaOverLT(true);
+ ps->doAlphaOverLTCurve(true);
+ ps->bezierStartEndPointAlpha()[1] = 0.0f;
+ ps->bezierControlPointAlpha()[1] = 0.5f;
+ ps->bezierControlPointAlpha()[2] = 0.5f;
+ ps->generateBernsteinPAlpha();
+ ps->doRotRange(true);
+ ps->color(SLCol4f(1.0f, 1.0f, 1.0f, 1.0f));
+ ps->doBlendBrightness(false);
+ ps->frameRateFB(16);
+
+ SLMesh* pSMesh = ps;
+ SLNode* pSNode = new SLNode(pSMesh, "Particle system node fire2");
+ pSNode->translate(3.0f, -0.8f, 0.0f, TS_object);
+
+ scene->addChild(pSNode);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_Fountain) //............................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Fountain particle system");
- s->info("This fountain particle system uses acceleration and gravity.\n"
- "See the properties window for the detailed settings of the particles system");
+ // Set scene name and info string
+ s->name("Fountain particle system");
+ s->info("This fountain particle system uses acceleration and gravity.\n"
+ "See the properties window for the detailed settings of the particles system");
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- // Create and add camera
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->translation(0, -1, 55);
- cam1->lookAt(0, -1, 0);
- cam1->focalDist(55);
- scene->addChild(cam1);
- sv->camera(cam1);
+ // Create and add camera
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->translation(0, -1, 55);
+ cam1->lookAt(0, -1, 0);
+ cam1->focalDist(55);
+ scene->addChild(cam1);
+ sv->camera(cam1);
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- // SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_04_8x8_C.png");
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_04_8x8_C.png");
- // Create a light source node
- SLLightSpot* light1 = new SLLightSpot(am, s, 0.3f);
- light1->translation(0, -1, 2);
- light1->name("light node");
- scene->addChild(light1);
+ // Create a light source node
+ SLLightSpot* light1 = new SLLightSpot(am, s, 0.3f);
+ light1->translation(0, -1, 2);
+ light1->name("light node");
+ scene->addChild(light1);
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 5000,
- SLVec3f(5.0f, 15.0f, 5.0f),
- SLVec3f(-5.0f, 17.0f, -5.0f),
- 5.0f,
- texC,
- "Fountain",
- texFlipbook);
- SLMesh* pSMesh = ps;
- ps->doGravity(true);
- ps->color(SLCol4f(0.0039f, 0.14f, 0.86f, 0.33f));
- ps->doSizeOverLT(false);
- ps->doAlphaOverLT(false);
- SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
- scene->addChild(pSNode);
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 5000,
+ SLVec3f(5.0f, 15.0f, 5.0f),
+ SLVec3f(-5.0f, 17.0f, -5.0f),
+ 5.0f,
+ texC,
+ "Fountain",
+ texFlipbook);
+ SLMesh* pSMesh = ps;
+ ps->doGravity(true);
+ ps->color(SLCol4f(0.0039f, 0.14f, 0.86f, 0.33f));
+ ps->doSizeOverLT(false);
+ ps->doAlphaOverLT(false);
+ SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
+ scene->addChild(pSNode);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_Sun) //.................................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Sun particle system");
- s->info("This sun particle system uses the sphere shape type for distribution.\n"
- "See the properties window for the detailed settings of the particles system");
-
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
-
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // Set scene name and info string
+ s->name("Sun particle system");
+ s->info("This sun particle system uses the sphere shape type for distribution.\n"
+ "See the properties window for the detailed settings of the particles system");
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 10000,
- SLVec3f(0.0f, 0.0f, 0.0f),
- SLVec3f(0.0f, 0.0f, 0.0f),
- 4.0f,
- texC,
- "Sun Particle System",
- texFlipbook);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- ps->doShape(true);
- ps->shapeType(ST_Sphere);
- ps->shapeRadius(3.0f);
- ps->doBlendBrightness(true);
- ps->color(SLCol4f(0.925f, 0.238f, 0.097f, 0.199f));
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- SLMesh* pSMesh = ps;
- SLNode* pSNode = new SLNode(pSMesh, "Particle Sun node");
- scene->addChild(pSNode);
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 10000,
+ SLVec3f(0.0f, 0.0f, 0.0f),
+ SLVec3f(0.0f, 0.0f, 0.0f),
+ 4.0f,
+ texC,
+ "Sun Particle System",
+ texFlipbook);
+
+ ps->doShape(true);
+ ps->shapeType(ST_Sphere);
+ ps->shapeRadius(3.0f);
+ ps->doBlendBrightness(true);
+ ps->color(SLCol4f(0.925f, 0.238f, 0.097f, 0.199f));
+
+ SLMesh* pSMesh = ps;
+ SLNode* pSNode = new SLNode(pSMesh, "Particle Sun node");
+ scene->addChild(pSNode);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_RingOfFire) //..........................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Ring of fire particle system");
- s->info("This ring particle system uses the cone shape type for distribution.\n"
- "See the properties window for the settings of the particles system");
-
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
-
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // Set scene name and info string
+ s->name("Ring of fire particle system");
+ s->info("This ring particle system uses the cone shape type for distribution.\n"
+ "See the properties window for the settings of the particles system");
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 1000,
- SLVec3f(0.0f, 0.0f, 0.0f),
- SLVec3f(0.0f, 0.0f, 0.0f),
- 4.0f,
- texC,
- "Ring of fire Particle System",
- texFlipbook);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- ps->doShape(true);
- ps->shapeType(ST_Cone);
- ps->doShapeSpawnBase(true);
- ps->doShapeSurface(true);
- ps->shapeRadius(1.0f);
- ps->doBlendBrightness(true);
- ps->color(SLCol4f(0.925f, 0.238f, 0.097f, 0.503f));
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- SLMesh* pSMesh = ps;
- SLNode* pSNode = new SLNode(pSMesh, "Particle Ring Fire node");
- pSNode->rotate(90, 1, 0, 0);
- scene->addChild(pSNode);
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 1000,
+ SLVec3f(0.0f, 0.0f, 0.0f),
+ SLVec3f(0.0f, 0.0f, 0.0f),
+ 4.0f,
+ texC,
+ "Ring of fire Particle System",
+ texFlipbook);
+
+ ps->doShape(true);
+ ps->shapeType(ST_Cone);
+ ps->doShapeSpawnBase(true);
+ ps->doShapeSurface(true);
+ ps->shapeRadius(1.0f);
+ ps->doBlendBrightness(true);
+ ps->color(SLCol4f(0.925f, 0.238f, 0.097f, 0.503f));
+
+ SLMesh* pSMesh = ps;
+ SLNode* pSNode = new SLNode(pSMesh, "Particle Ring Fire node");
+ pSNode->rotate(90, 1, 0, 0);
+ scene->addChild(pSNode);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_FireComplex) //.........................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("Fire Complex particle system");
- s->info("The fire particle systems contain each multiple sub particle systems.\n"
- "See the scenegraph window for the sub particles systems. "
- "See the properties window for the settings of the particles systems");
+ // Set scene name and info string
+ s->name("Fire Complex particle system");
+ s->info("The fire particle systems contain each multiple sub particle systems.\n"
+ "See the scenegraph window for the sub particles systems. "
+ "See the properties window for the settings of the particles systems");
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- // Create and add camera
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->translation(0, 1.2f, 4.0f);
- cam1->lookAt(0, 1.2f, 0);
- cam1->focalDist(4.5f);
- cam1->setInitialState();
- scene->addChild(cam1);
- sv->camera(cam1);
+ // Create and add camera
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->translation(0, 1.2f, 4.0f);
+ cam1->lookAt(0, 1.2f, 0);
+ cam1->focalDist(4.5f);
+ cam1->setInitialState();
+ scene->addChild(cam1);
+ sv->camera(cam1);
- // Create textures and materials
- SLGLTexture* texFireCld = new SLGLTexture(am, texPath + "ParticleFirecloudTransparent_C.png");
- SLGLTexture* texFireFlm = new SLGLTexture(am, texPath + "ParticleFlames_06_8x8_C.png");
- SLGLTexture* texCircle = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
- SLGLTexture* texSmokeB = new SLGLTexture(am, texPath + "ParticleCloudBlack_C.png");
- SLGLTexture* texSmokeW = new SLGLTexture(am, texPath + "ParticleCloudWhite_C.png");
- SLGLTexture* texTorchFlm = new SLGLTexture(am, texPath + "ParticleFlames_04_16x4_C.png");
- SLGLTexture* texTorchSmk = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
-
- SLNode* complexFire = createComplexFire(am,
- s,
- true,
- texTorchSmk,
- texFireFlm,
- 8,
- 8,
- texCircle,
- texSmokeB,
- texSmokeW);
- scene->addChild(complexFire);
-
- // Room around
- {
- // Room parent node
- SLNode* room = new SLNode("Room");
- scene->addChild(room);
-
- // Back wall material
- SLGLTexture* texWallDIF = new SLGLTexture(am, texPath + "BrickLimestoneGray_1K_DIF.jpg", SL_ANISOTROPY_MAX, GL_LINEAR);
- SLGLTexture* texWallNRM = new SLGLTexture(am, texPath + "BrickLimestoneGray_1K_NRM.jpg", SL_ANISOTROPY_MAX, GL_LINEAR);
- SLMaterial* matWall = new SLMaterial(am, "mat3", texWallDIF, texWallNRM);
- matWall->specular(SLCol4f::BLACK);
- matWall->metalness(0);
- matWall->roughness(1);
- matWall->reflectionModel(RM_CookTorrance);
-
- // Room dimensions
- SLfloat pL = -2.0f, pR = 2.0f; // left/right
- SLfloat pB = -0.01f, pT = 4.0f; // bottom/top
- SLfloat pN = 2.0f, pF = -2.0f; // near/far
-
- // bottom rectangle
- SLNode* b = new SLNode(new SLRectangle(am, SLVec2f(pL, -pN), SLVec2f(pR, -pF), 10, 10, "Floor", matWall));
- b->rotate(90, -1, 0, 0);
- b->translate(0, 0, pB, TS_object);
- room->addChild(b);
-
- // far rectangle
- SLNode* f = new SLNode(new SLRectangle(am, SLVec2f(pL, pB), SLVec2f(pR, pT), 10, 10, "Wall far", matWall));
- f->translate(0, 0, pF, TS_object);
- room->addChild(f);
-
- // near rectangle
- SLNode* n = new SLNode(new SLRectangle(am, SLVec2f(pL, pB), SLVec2f(pR, pT), 10, 10, "Wall near", matWall));
- n->rotate(180, 0, 1, 0);
- n->translate(0, 0, pF, TS_object);
- room->addChild(n);
-
- // left rectangle
- SLNode* l = new SLNode(new SLRectangle(am, SLVec2f(-pN, pB), SLVec2f(-pF, pT), 10, 10, "Wall left", matWall));
- l->rotate(90, 0, 1, 0);
- l->translate(0, 0, pL, TS_object);
- room->addChild(l);
-
- // right rectangle
- SLNode* r = new SLNode(new SLRectangle(am, SLVec2f(pF, pB), SLVec2f(pN, pT), 10, 10, "Wall right", matWall));
- r->rotate(90, 0, -1, 0);
- r->translate(0, 0, -pR, TS_object);
- room->addChild(r);
- }
+ // Create textures and materials
+ SLGLTexture* texFireCld = new SLGLTexture(am, texPath + "ParticleFirecloudTransparent_C.png");
+ SLGLTexture* texFireFlm = new SLGLTexture(am, texPath + "ParticleFlames_06_8x8_C.png");
+ SLGLTexture* texCircle = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
+ SLGLTexture* texSmokeB = new SLGLTexture(am, texPath + "ParticleCloudBlack_C.png");
+ SLGLTexture* texSmokeW = new SLGLTexture(am, texPath + "ParticleCloudWhite_C.png");
+ SLGLTexture* texTorchFlm = new SLGLTexture(am, texPath + "ParticleFlames_04_16x4_C.png");
+ SLGLTexture* texTorchSmk = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+
+ SLNode* complexFire = createComplexFire(am,
+ s,
+ true,
+ texTorchSmk,
+ texFireFlm,
+ 8,
+ 8,
+ texCircle,
+ texSmokeB,
+ texSmokeW);
+ scene->addChild(complexFire);
+
+ // Room around
+ {
+ // Room parent node
+ SLNode* room = new SLNode("Room");
+ scene->addChild(room);
+
+ // Back wall material
+ SLGLTexture* texWallDIF = new SLGLTexture(am, texPath + "BrickLimestoneGray_1K_DIF.jpg", SL_ANISOTROPY_MAX, GL_LINEAR);
+ SLGLTexture* texWallNRM = new SLGLTexture(am, texPath + "BrickLimestoneGray_1K_NRM.jpg", SL_ANISOTROPY_MAX, GL_LINEAR);
+ SLMaterial* matWall = new SLMaterial(am, "mat3", texWallDIF, texWallNRM);
+ matWall->specular(SLCol4f::BLACK);
+ matWall->metalness(0);
+ matWall->roughness(1);
+ matWall->reflectionModel(RM_CookTorrance);
+
+ // Room dimensions
+ SLfloat pL = -2.0f, pR = 2.0f; // left/right
+ SLfloat pB = -0.01f, pT = 4.0f; // bottom/top
+ SLfloat pN = 2.0f, pF = -2.0f; // near/far
+
+ // bottom rectangle
+ SLNode* b = new SLNode(new SLRectangle(am, SLVec2f(pL, -pN), SLVec2f(pR, -pF), 10, 10, "Floor", matWall));
+ b->rotate(90, -1, 0, 0);
+ b->translate(0, 0, pB, TS_object);
+ room->addChild(b);
+
+ // far rectangle
+ SLNode* f = new SLNode(new SLRectangle(am, SLVec2f(pL, pB), SLVec2f(pR, pT), 10, 10, "Wall far", matWall));
+ f->translate(0, 0, pF, TS_object);
+ room->addChild(f);
+
+ // near rectangle
+ SLNode* n = new SLNode(new SLRectangle(am, SLVec2f(pL, pB), SLVec2f(pR, pT), 10, 10, "Wall near", matWall));
+ n->rotate(180, 0, 1, 0);
+ n->translate(0, 0, pF, TS_object);
+ room->addChild(n);
+
+ // left rectangle
+ SLNode* l = new SLNode(new SLRectangle(am, SLVec2f(-pN, pB), SLVec2f(-pF, pT), 10, 10, "Wall left", matWall));
+ l->rotate(90, 0, 1, 0);
+ l->translate(0, 0, pL, TS_object);
+ room->addChild(l);
+
+ // right rectangle
+ SLNode* r = new SLNode(new SLRectangle(am, SLVec2f(pF, pB), SLVec2f(pN, pT), 10, 10, "Wall right", matWall));
+ r->rotate(90, 0, -1, 0);
+ r->translate(0, 0, -pR, TS_object);
+ room->addChild(r);
+ }
- // Firewood
- SLAssimpImporter importer;
- SLNode* firewood = importer.load(s->animManager(),
- am,
- modelPath + "GLTF/Firewood/Firewood1.gltf",
- texPath,
- nullptr,
- false,
- true,
- nullptr,
- 0.3f,
- true);
- firewood->scale(2);
- scene->addChild(firewood);
-
- // Torch
- SLNode* torchL = importer.load(s->animManager(),
- am,
- modelPath + "GLTF/Torch/Torch.gltf",
- texPath,
- nullptr,
- false,
- true,
- nullptr,
- 0.3f,
- true);
- torchL->name("Torch Left");
- SLNode* torchR = torchL->copyRec();
- torchR->name("Torch Right");
- torchL->translate(-2, 1.5f, 0);
- torchL->rotate(90, 0, 1, 0);
- torchL->scale(2);
- scene->addChild(torchL);
- torchR->translate(2, 1.5f, 0);
- torchR->rotate(-90, 0, 1, 0);
- torchR->scale(2);
- scene->addChild(torchR);
-
- // Torch flame left
- SLNode* torchFlameNodeL = createTorchFire(am,
- s,
- true,
- texTorchSmk,
- texTorchFlm,
- 16,
- 4);
- torchFlameNodeL->translate(-1.6f, 2.25f, 0);
- torchFlameNodeL->name("Torch Fire Left");
- scene->addChild(torchFlameNodeL);
-
- // Torch flame right
- SLNode* torchFlameNodeR = createTorchFire(am,
- s,
- true,
- texTorchSmk,
- texTorchFlm,
- 16,
- 4);
- torchFlameNodeR->translate(1.6f, 2.25f, 0);
- torchFlameNodeR->name("Torch Fire Right");
- scene->addChild(torchFlameNodeR);
+ // Firewood
+ SLAssimpImporter importer;
+ SLNode* firewood = importer.load(s->animManager(),
+ am,
+ modelPath + "GLTF/Firewood/Firewood1.gltf",
+ texPath,
+ nullptr,
+ false,
+ true,
+ nullptr,
+ 0.3f,
+ true);
+ firewood->scale(2);
+ scene->addChild(firewood);
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- // Save energy
- sv->doWaitOnIdle(false);
- }
+ // Torch
+ SLNode* torchL = importer.load(s->animManager(),
+ am,
+ modelPath + "GLTF/Torch/Torch.gltf",
+ texPath,
+ nullptr,
+ false,
+ true,
+ nullptr,
+ 0.3f,
+ true);
+ torchL->name("Torch Left");
+ SLNode* torchR = torchL->copyRec();
+ torchR->name("Torch Right");
+ torchL->translate(-2, 1.5f, 0);
+ torchL->rotate(90, 0, 1, 0);
+ torchL->scale(2);
+ scene->addChild(torchL);
+ torchR->translate(2, 1.5f, 0);
+ torchR->rotate(-90, 0, 1, 0);
+ torchR->scale(2);
+ scene->addChild(torchR);
+
+ // Torch flame left
+ SLNode* torchFlameNodeL = createTorchFire(am,
+ s,
+ true,
+ texTorchSmk,
+ texTorchFlm,
+ 16,
+ 4);
+ torchFlameNodeL->translate(-1.6f, 2.25f, 0);
+ torchFlameNodeL->name("Torch Fire Left");
+ scene->addChild(torchFlameNodeL);
+
+ // Torch flame right
+ SLNode* torchFlameNodeR = createTorchFire(am,
+ s,
+ true,
+ texTorchSmk,
+ texTorchFlm,
+ 16,
+ 4);
+ torchFlameNodeR->translate(1.6f, 2.25f, 0);
+ torchFlameNodeR->name("Torch Fire Right");
+ scene->addChild(torchFlameNodeR);
+
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ // Save energy
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_Benchmark1_LargeModel) //..............................................
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index bef75869..bc8a2886 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -35,7 +35,15 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
assert(!name.empty());
// To be added to constructor
- _renderInstanced = renderInstanced;
+
+ if (SLGLState::instance()->glHasGeometryShaders())
+ {
+ _renderInstanced = renderInstanced;
+ }
+ else
+ {
+ _renderInstanced = true;
+ }
_primitive = PT_points;
P.push_back(SLVec3f(0, 0, 0)); // Trick SL project because it want mesh to have vertex
From d21a4e174da68fd7b7b2e5508a297f6ecbc68ea9 Mon Sep 17 00:00:00 2001
From: luc
Date: Mon, 13 Nov 2023 19:11:56 +0100
Subject: [PATCH 053/108] fix particle system error with material destruction
---
.../app_demo_slproject/source/AppDemoLoad.cpp | 2 -
modules/sl/source/mesh/SLParticleSystem.cpp | 67 +++++++++++--------
modules/sl/source/mesh/SLParticleSystem.h | 3 +
3 files changed, 42 insertions(+), 30 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoLoad.cpp b/apps/app_demo_slproject/source/AppDemoLoad.cpp
index d65088ca..bcc9f6ff 100644
--- a/apps/app_demo_slproject/source/AppDemoLoad.cpp
+++ b/apps/app_demo_slproject/source/AppDemoLoad.cpp
@@ -499,7 +499,6 @@ SLNode* createComplexFire(SLAssetManager* am,
fireFlameMesh->flipbookRows(flipbookRows);
fireFlameMesh->doFlipBookTexture(true);
fireFlameMesh->doCounterGap(false); // We don't want to have flickering
- fireFlameMesh->changeTexture(); // Switch texture, need to be done, to have flipbook texture as active
fireFlameMesh->doAlphaOverLT(false);
fireFlameMesh->doSizeOverLT(false);
@@ -708,7 +707,6 @@ SLNode* createTorchFire(SLAssetManager* am,
torchFlame->flipbookRows(flipbookRows);
torchFlame->doFlipBookTexture(true);
torchFlame->doCounterGap(false); // We don't want to have flickering
- torchFlame->changeTexture(); // Switch texture, need to be done, to have flipbook texture as active
torchFlame->doAlphaOverLT(false);
torchFlame->doSizeOverLT(false);
torchFlame->doRotation(false);
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index bc8a2886..07bcb9a5 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -36,6 +36,8 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
// To be added to constructor
+ _assetManager = assetMgr;
+
if (SLGLState::instance()->glHasGeometryShaders())
{
_renderInstanced = renderInstanced;
@@ -60,10 +62,6 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
_textureFirst = texC;
_textureFlipbook = texFlipbook;
- // Initialize the drawing:
- SLMaterial* mDraw = new SLMaterial(assetMgr, "Drawing-Material", this, texC);
- mat(mDraw);
-
_updateTime.init(60, 0.0f);
_drawTime.init(60, 0.0f);
@@ -328,6 +326,18 @@ void SLParticleSystem::generate()
deleteDataGpu();
+ // Initialize the drawing:
+ if (_doFlipBookTexture)
+ {
+ SLMaterial* mDraw = new SLMaterial(_assetManager, "Drawing-Material", this, _textureFlipbook);
+ mat(mDraw);
+ }
+ else
+ {
+ SLMaterial* mDraw = new SLMaterial(_assetManager, "Drawing-Material", this, _textureFirst);
+ mat(mDraw);
+ }
+
tempP.resize(_amount);
tempV.resize(_amount);
tempST.resize(_amount);
@@ -484,6 +494,9 @@ void SLParticleSystem::generate()
I32.push_back(3);
I32.push_back(0);
+
+ _renderVao1.deleteGL();
+ _renderVao2.deleteGL();
/* Generate vao for rendering with draw instanced */
_renderVao1.setAttrib(AT_custom0, AT_custom0, &P);
_renderVao1.setIndices(&I32);
@@ -539,24 +552,7 @@ void SLParticleSystem::generateBernsteinPSize()
// 1
_bernsteinPYSize.w = StaEnd[1];
}
-//-----------------------------------------------------------------------------
-/*!
-Change the current use texture, this will switch between the normal texture and
-the flipbook texture (and vice versa)
-*/
-void SLParticleSystem::changeTexture()
-{
- if (_doFlipBookTexture)
- {
- mat()->removeTextureType(TT_diffuse);
- mat()->addTexture(_textureFlipbook);
- }
- else
- {
- mat()->removeTextureType(TT_diffuse);
- mat()->addTexture(_textureFirst);
- }
-}
+
//-----------------------------------------------------------------------------
/*! Function called inside SLNode cull3DRec(..) which flags the particle system
to be not visible in the view frustum. This is needed to correct later the
@@ -597,7 +593,6 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
/////////////////////////////////////
// Init particles vector and init VAO
/////////////////////////////////////
-
if (!_isGenerated)
generate();
@@ -908,6 +903,27 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
// Swap buffer
_drawBuf = 1 - _drawBuf;
}
+
+
+/*!
+Change the current use texture, this will switch between the normal texture and
+the flipbook texture (and vice versa)
+*/
+void SLParticleSystem::changeTexture()
+{
+ if (_doFlipBookTexture)
+ {
+ mat()->removeTextureType(TT_diffuse);
+ mat()->addTexture(_textureFlipbook);
+ }
+ else
+ {
+ mat()->removeTextureType(TT_diffuse);
+ mat()->addTexture(_textureFirst);
+ }
+}
+
+
//-----------------------------------------------------------------------------
//! deleteData deletes all mesh data and VAOs
void SLParticleSystem::deleteData()
@@ -918,12 +934,7 @@ void SLParticleSystem::deleteData()
//! deleteData deletes all mesh data and VAOs
void SLParticleSystem::deleteDataGpu()
{
- _vao1.deleteGL();
- _vao2.deleteGL();
- _renderVao1.deleteGL();
- _renderVao2.deleteGL();
SLMesh::deleteDataGpu();
- _mat->deleteDataGpu();
}
//-----------------------------------------------------------------------------
/*! SLParticleSystem::buildAABB builds the passed axis-aligned bounding box in
diff --git a/modules/sl/source/mesh/SLParticleSystem.h b/modules/sl/source/mesh/SLParticleSystem.h
index d856e62f..17fcb340 100644
--- a/modules/sl/source/mesh/SLParticleSystem.h
+++ b/modules/sl/source/mesh/SLParticleSystem.h
@@ -273,6 +273,9 @@ class SLParticleSystem : public SLMesh
SLVec3f getPointOnPyramid();
SLVec3f getDirectionPyramid(SLVec3f position);
+ // Use to recreate material (the shader change depending if the PS is instanced or not)
+ SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
+
// Core values
SLint _amount; //!< Amount of a particle
SLVec3f _emitterPos; //!< Position of the particle emitter
From 79b7ebee5061c4b39a60d5cded7cebec37050e84 Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 16 Nov 2023 11:30:14 +0100
Subject: [PATCH 054/108] [WebGPU] Update demo docs
---
apps/webgpu/CMakeLists.txt | 2 +-
apps/webgpu/{main.cpp => webgpu_demo.cpp} | 139 ++++++++++++++++------
2 files changed, 104 insertions(+), 37 deletions(-)
rename apps/webgpu/{main.cpp => webgpu_demo.cpp} (92%)
diff --git a/apps/webgpu/CMakeLists.txt b/apps/webgpu/CMakeLists.txt
index fff48076..564ea90b 100644
--- a/apps/webgpu/CMakeLists.txt
+++ b/apps/webgpu/CMakeLists.txt
@@ -60,7 +60,7 @@ if (SYSTEM_NAME_UPPER MATCHES "DARWIN")
set(TARGET_SPECIFIC_SOURCES metal_layer.mm)
endif ()
-add_executable(webgpu-demo main.cpp ${TARGET_SPECIFIC_SOURCES})
+add_executable(webgpu-demo webgpu_demo.cpp ${TARGET_SPECIFIC_SOURCES})
target_link_libraries(webgpu-demo PRIVATE wgpu sl_cv sl_math ${glfw_LIBS})
if (SYSTEM_NAME_UPPER MATCHES "LINUX")
diff --git a/apps/webgpu/main.cpp b/apps/webgpu/webgpu_demo.cpp
similarity index 92%
rename from apps/webgpu/main.cpp
rename to apps/webgpu/webgpu_demo.cpp
index 93f9b41c..64a97a4a 100644
--- a/apps/webgpu/main.cpp
+++ b/apps/webgpu/webgpu_demo.cpp
@@ -1,47 +1,45 @@
-#if defined(_WIN32)
-# define SYSTEM_WINDOWS
-# define GLFW_EXPOSE_NATIVE_WIN32
-# define WIN32_LEAN_AND_MEAN
-# include
-#elif defined(__linux__)
-# define SYSTEM_LINUX
-# define GLFW_EXPOSE_NATIVE_X11
-#elif defined(__APPLE__)
-# ifndef SYSTEM_DARWIN
-# define SYSTEM_DARWIN
-# endif
-# define GLFW_EXPOSE_NATIVE_COCOA
-#endif
+/*
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+-- Overview
-#include
-#include
-#include
-#include
-#include
+WebGPU is a graphics API standard developed by the World Wide Web Consortium (W3C). It is an abstraction layer
+over modern graphics APIs like Vulkan, D3D12 and Metal and thus uses modern concepts such as queues, command buffers
+or pipelines. WebGPU is supposed to be 'safe' API and is generally simpler to use than Vulkan. Both graphics and
+compute functionality is available.
-#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
-
-#define WEBGPU_DEMO_CHECK(condition, errorMsg) \
- if (!(condition)) \
- { \
- std::cerr << (errorMsg) << std::endl; \
- std::exit(1); \
- }
+The primary target for WebGPU was the Web as a replacement for the old WebGL API. This means that
+the specification is written for a JavaScript API. However, Google and Mozilla have decided to provide their in-browser
+implementations as native libraries, so we can use WebGPU in native apps written in C, C++ or Rust. The implementers
+have agreed on a common interface for their libraries in form of a header called `webgpu.h`
+(https://github.com/webgpu-native/webgpu-headers/).
-/*
-To interact with WebGPU, we create objects with a call to wgpu*Create*. This function normally takes the parent
+There are currently three implementations of this header:
+ - wgpu-native: Mozilla's implementation for Firefox, written in Rust
+ - Dawn: Google's implementation for Chromium, written in C++
+ - Emscripten: Translates the webgpu.h calls to JavaScript calls in the browser
+
+WebGPU uses its own shader language called WGSL (WebGPU Shader Language). This is the only shader language supported
+in the browsers even though the native implementations also support SPIR-V.
+
+To make porting to WebGPU easier, the two browser vendors provide tools for translating other shader languages to WGSL:
+ - Naga: Mozilla's shader translator, can be used only as an executable
+ - Tint: Google's shader translator, can be used as both a C++ library and an executable
+
+This demo uses the wgpu-native implementation because Mozilla releases pre-built binaries that can easily be
+downloaded from CMake. Since wgpu-native uses the same interface header as Dawn, it would also be possible to
+link Dawn instead of wgpu-native, but we would have to build and distribute it ourselves.
+
+
+-- Usage
+
+WebGPU follows a stateless design as opposed to OpenGL, where much state has to be set globally before making a
+draw call. To use WebGPU, we create objects with a call to wgpu*Create*. This function generally takes the parent
object as a parameter and a WGPU*Descriptor that contains the specification for the object. The returned object
is released after usage with a call to wgpuRelease*. An object can have a label that is used when reporting errors.
+We can now call functions on the object to interact with them.
WebGPU concepts:
+
- WGPUInstance
The core interface through which all other objects are created.
@@ -161,8 +159,77 @@ WebGPU concepts:
specialized object called a render pass encoder. It is created from a command encoder using
wgpuCommandEncoderBeginRenderPass.
+
+-- WebGPU vs. Vulkan
+
+Here's a list of things I've noticed are handled differently from Vulkan (as of 2023-11-26):
+
+ - There is no multithreading
+ Unlike Vukan, WebGPU is currently single-threaded and doesn't allow encoding command buffers on
+ multiple threads.
+ Status: https://gpuweb.github.io/gpuweb/explainer/#multithreading
+
+ - There is only one queue
+ Vulkan allows you to create multiple queues from different families. For example, you can create a
+ graphics and a compute queue and submit commands to them that are processed in parallel on some GPUs.
+ In WebGPU, there is only one queue that is acquired using wgpuDeviceGetQueue.
+ Discussion: https://github.com/gpuweb/gpuweb/issues/1065
+
+ - There is no manual memory allocation
+ In WebGPU, buffers take care of memory allocation internally. Awesome!
+
+ - There is no swap chain
+ The swap chain configuration is part of the surface configuration.
+
+ - Error handling is very different
+ In Vulkan, there is by default no validation and programs just silently crash and burn. It is possible
+ to enable validation layers that print errors with references to the spec. The reason for this is that
+ Vulkan wants to avoid validation overhead in release builds. In WebGPU, validation seems mostly up to the
+ implementations. We currently use the wgpu-native implementation, which seems to catch all errors and prints
+ most of the time a nice error message with a human-readable error message including the labels of the
+ problematic objects, suggests fixes and even generates a stack trace. I'm not sure what the overhead of
+ this validation is, but I excpect there to be an option to turn it off in the future.
+
*/
+#if defined(_WIN32)
+# define SYSTEM_WINDOWS
+# define GLFW_EXPOSE_NATIVE_WIN32
+# define WIN32_LEAN_AND_MEAN
+# include
+#elif defined(__linux__)
+# define SYSTEM_LINUX
+# define GLFW_EXPOSE_NATIVE_X11
+#elif defined(__APPLE__)
+# ifndef SYSTEM_DARWIN
+# define SYSTEM_DARWIN
+# endif
+# define GLFW_EXPOSE_NATIVE_COCOA
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
+
+#define WEBGPU_DEMO_CHECK(condition, errorMsg) \
+ if (!(condition)) \
+ { \
+ std::cerr << (errorMsg) << std::endl; \
+ std::exit(1); \
+ }
+
struct App
{
GLFWwindow* window = nullptr;
From ce1ae04729d79269025ae2694205ac23e3218a72 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 20 Nov 2023 10:25:02 +0100
Subject: [PATCH 055/108] Update SLGLState.cpp
---
modules/sl/source/gl/SLGLState.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/sl/source/gl/SLGLState.cpp b/modules/sl/source/gl/SLGLState.cpp
index 724bcdcd..d50cb31f 100644
--- a/modules/sl/source/gl/SLGLState.cpp
+++ b/modules/sl/source/gl/SLGLState.cpp
@@ -409,10 +409,10 @@ void SLGLState::useProgram(SLuint progID)
*/
void SLGLState::bindTexture(SLenum target, SLuint textureID)
{
- // (luc) If there we call glActiveTexture and glBindTexture from outside,
+ // (luc) If we call glActiveTexture and glBindTexture from outside,
// This will lead to problems as the global state in SLGLState will not be
// equivalent to the OpenGL state.
- // We should solve this by querying opengl for the last binded texture.
+ // We should solve this by querying opengl for the last bound texture.
// glGetIntegeriv(GL_ACTIVE_TEXTURE, active_texture)
// glGetIntegeriv(GL_TEXTURE_BINDING_2D, textureID)
From 72c4cdf192fc35354daaddd8194b293a998a6d24 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 20 Nov 2023 16:59:34 +0100
Subject: [PATCH 056/108] Cosmetics
---
modules/sl/source/SLAssetManager.cpp | 2 +-
modules/sl/source/SLMaterial.cpp | 18 ++++++++++--------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/modules/sl/source/SLAssetManager.cpp b/modules/sl/source/SLAssetManager.cpp
index 1fedf31f..05498ce2 100644
--- a/modules/sl/source/SLAssetManager.cpp
+++ b/modules/sl/source/SLAssetManager.cpp
@@ -95,7 +95,7 @@ bool SLAssetManager::removeMesh(SLMesh* mesh)
}
return false;
}
-
+//-----------------------------------------------------------------------------
//! Removes the specified program from the meshes resource vector.
bool SLAssetManager::removeProgram(SLGLProgram* program)
{
diff --git a/modules/sl/source/SLMaterial.cpp b/modules/sl/source/SLMaterial.cpp
index 3f8c0bab..25674510 100644
--- a/modules/sl/source/SLMaterial.cpp
+++ b/modules/sl/source/SLMaterial.cpp
@@ -150,7 +150,7 @@ SLMaterial::SLMaterial(SLAssetManager* am,
SLGLProgram* program) : SLObject(name)
{
_assetManager = am;
- _ambient.set(0, 0, 0); // not used in Cook-Torrance
+ _ambient.set(0, 0, 0); // not used in Cook-Torrance
_diffuse = diffuse;
_specular.set(1, 1, 1); // not used in Cook-Torrance
_emissive.set(0, 0, 0, 0); // not used in Cook-Torrance
@@ -372,8 +372,7 @@ SLMaterial::~SLMaterial()
_errorTexture = nullptr;
}
}
-
-
+//------------------------------------------------------------------------------
void SLMaterial::deleteDataGpu()
{
if (_program)
@@ -384,8 +383,6 @@ void SLMaterial::deleteDataGpu()
_program = nullptr;
}
}
-
-
//-----------------------------------------------------------------------------
/*!
If this material has not yet a shader program assigned (SLMaterial::_program)
@@ -403,7 +400,10 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
// Check first the asset manager if the requested program type already exists
string programNameDraw;
- SLGLProgramGenerated::buildProgramNamePS(this, programNameDraw, true, renderInstanced);
+ SLGLProgramGenerated::buildProgramNamePS(this,
+ programNameDraw,
+ true,
+ renderInstanced);
_program = _assetManager->getProgramByName(programNameDraw);
// If the program was not found by name generate a new one
@@ -478,7 +478,8 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
for (int i = 0; i < TT_numTextureType; i++)
_textures[i].clear();
if (!_errorTexture && !_compileErrorTexFilePath.empty())
- _errorTexture = new SLGLTexture(nullptr, _compileErrorTexFilePath);
+ _errorTexture = new SLGLTexture(nullptr,
+ _compileErrorTexFilePath);
_textures[TT_diffuse].push_back(_errorTexture);
}
@@ -487,7 +488,8 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
for (int i = 0; i < TT_numTextureType; i++)
_textures[i].clear();
if (!_errorTexture && !_compileErrorTexFilePath.empty())
- _errorTexture = new SLGLTexture(nullptr, _compileErrorTexFilePath);
+ _errorTexture = new SLGLTexture(nullptr,
+ _compileErrorTexFilePath);
_textures[TT_diffuse].push_back(_errorTexture);
}
}
From 373ea04fea7889b3d9747095f7582b5d11fad0e5 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Tue, 21 Nov 2023 09:23:01 +0100
Subject: [PATCH 057/108] Fixed SL_EXIT_MSG again
No we see shader compile errors again.
---
modules/sl/source/SL.h | 2 +-
modules/sl/source/gl/SLGLShader.cpp | 1 +
modules/utils/source/Utils.cpp | 6 +++---
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/modules/sl/source/SL.h b/modules/sl/source/SL.h
index 8165192f..48708e1a 100644
--- a/modules/sl/source/SL.h
+++ b/modules/sl/source/SL.h
@@ -235,7 +235,7 @@ SL_sizeOfVector(const T& vector)
//-----------------------------------------------------------------------------
// Some debugging and error handling macros
#define SL_LOG(...) Utils::log("SLProject", __VA_ARGS__)
-#define SL_EXIT_MSG(message) Utils::log("SLProject Error", (message))
+#define SL_EXIT_MSG(message) Utils::exitMsg("SLProject", (message), __LINE__, __FILE__)
#define SL_WARN_MSG(message) Utils::warnMsg("SLProject", (message), __LINE__, __FILE__)
//-----------------------------------------------------------------------------
#endif
diff --git a/modules/sl/source/gl/SLGLShader.cpp b/modules/sl/source/gl/SLGLShader.cpp
index eaa87438..7602a311 100644
--- a/modules/sl/source/gl/SLGLShader.cpp
+++ b/modules/sl/source/gl/SLGLShader.cpp
@@ -149,6 +149,7 @@ SLbool SLGLShader::createAndCompile(SLVLight* lights)
SLint lineNum = 1;
for (string& line : lines)
SL_LOG("%4d: %s", lineNum++, line.c_str());
+ SL_LOG("\n");
return false;
}
diff --git a/modules/utils/source/Utils.cpp b/modules/utils/source/Utils.cpp
index 80889202..2f06388b 100644
--- a/modules/utils/source/Utils.cpp
+++ b/modules/utils/source/Utils.cpp
@@ -201,10 +201,10 @@ vector getStringLines(const string& multiLineString)
{
std::string line;
std::getline(stream, line);
- if (!stream.good())
- break;
line = Utils::trimString(line, "\r");
res.push_back(line);
+ if (!stream.good())
+ break;
}
return res;
}
@@ -1391,7 +1391,7 @@ std::string ComputerInfos::get()
// model = model;
# endif
-#elif defined(ANDROID) //................................................
+#elif defined(ANDROID) //................................................
os = "Android";
From 28df38ba5cd3d1331b5bcfa0e0dcc4516679b2e6 Mon Sep 17 00:00:00 2001
From: luc
Date: Mon, 27 Nov 2023 10:11:45 +0100
Subject: [PATCH 058/108] remove useless and non GLSL compilant texNum in
fragshader
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index f191d48f..2eee9230 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -168,15 +168,11 @@ const string vertOutput_PS_struct_texNum = R"(
const string vertOutput_PS_struct_End = R"(
} vert; )";
-const string vertOutput_PS_instanced_texNum = R"(
-out uint texNum; // Num of texture in flipbook)";
const string vertOutput_PS_instanced_transparency = R"(
out float transparency; // transparency of a particle )";
const string fragInput_PS_instanced_transparency = R"(
in float transparency; // transparency of a particle )";
-const string fragInput_PS_instanced_texNum = R"(
-in uint texNum; // Num of texture in flipbook)";
const string fragMain_PS_v_c = R"(
vec4 color = u_color; // Particle color)";
@@ -2336,7 +2332,6 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
fragCode += shaderHeader();
// Fragment shader inputs
- if (FlBoTex) fragCode += fragInput_PS_instanced_texNum;
fragCode += fragInput_PS_v_tC;
if (Co && !CoOvLi) fragCode += fragInput_PS_u_c;
if (CoOvLi)
From 7122373bc7fe221bb9e0866b3105238bc4a1c1bb Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 10:51:46 +0100
Subject: [PATCH 059/108] Update AppDemoGui.cpp
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 7f18410b..55d5f5bd 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -4370,8 +4370,6 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
}
}
- ImGui::Text("Supports GPU skinning: %s", m->supportsGPUSkinning() ? "Yes" : "No");
-
ImGui::TreePop();
}
}
From 67fcfeb2feec4b98cdeaa86f9e568ae722cc127f Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 11:18:58 +0100
Subject: [PATCH 060/108] Version 4.1 for development
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 28 -------------------
apps/source/AppDemo.cpp | 2 +-
docs/Doxyfile | 2 +-
3 files changed, 2 insertions(+), 30 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 55d5f5bd..c9f40bbf 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -1577,38 +1577,14 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
{
SLstring zip = "glTF-Sample-Models.zip";
- /*if (ImGui::MenuItem("Clear Coat Test", nullptr, sid == SID_glTF_ClearCoatTest))
- {
- SLstring fileToLoad = AppDemo::configPath + "models/glTF-Sample-Models/2.0/ClearCoatTest/glTF/ClearCoatTest.gltf";
- if (Utils::fileExists(fileToLoad))
- s->onLoad(am, s, sv, SID_glTF_ClearCoatTest);
- else
- downloadModelAndLoadScene(s, sv, zip, pathSrc, pathDst, fileToLoad, SID_glTF_ClearCoatTest);
- }*/
if (ImGui::MenuItem("Damaged Helmet", nullptr, sid == SID_glTF_DamagedHelmet))
- {
s->onLoad(am, s, sv, SID_glTF_DamagedHelmet);
- // SLstring fileToLoad = AppDemo::configPath + "models/glTF-Sample-Models/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf";
- // loadSceneWithLargeModel(s, sv, zip, fileToLoad, SID_glTF_DamagedHelmet);
- }
if (ImGui::MenuItem("Flight Helmet", nullptr, sid == SID_glTF_FlightHelmet))
- {
s->onLoad(am, s, sv, SID_glTF_FlightHelmet);
- // SLstring fileToLoad = AppDemo::configPath + "models/glTF-Sample-Models/2.0/FlightHelmet/glTF/FlightHelmet.gltf";
- // loadSceneWithLargeModel(s, sv, zip, fileToLoad, SID_glTF_FlightHelmet);
- }
if (ImGui::MenuItem("Sponza Palace", nullptr, sid == SID_glTF_Sponza))
- {
s->onLoad(am, s, sv, SID_glTF_Sponza);
- // SLstring fileToLoad = AppDemo::configPath + "models/glTF-Sample-Models/2.0/Sponza/glTF/Sponza.gltf";
- // loadSceneWithLargeModel(s, sv, zip, fileToLoad, SID_glTF_Sponza);
- }
if (ImGui::MenuItem("Water Bottle", nullptr, sid == SID_glTF_WaterBottle))
- {
s->onLoad(am, s, sv, SID_glTF_WaterBottle);
- // SLstring fileToLoad = AppDemo::configPath + "models/glTF-Sample-Models/2.0/WaterBottle/glTF/WaterBottle.gltf";
- // loadSceneWithLargeModel(s, sv, zip, fileToLoad, SID_glTF_WaterBottle);
- }
ImGui::EndMenu();
}
@@ -1618,11 +1594,7 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
SLstring zip = "GLTF-FanucCRX.zip";
if (ImGui::MenuItem("Fanuc-CRX", nullptr, sid == SID_Robotics_FanucCRX_FK))
- {
s->onLoad(am, s, sv, SID_Robotics_FanucCRX_FK);
- // SLstring fileToLoad = AppDemo::configPath + "models/GLTF-FanucCRX/Fanuc-CRX.gltf";
- // loadSceneWithLargeModel(s, sv, zip, fileToLoad, SID_Robotics_FanucCRX_FK);
- }
ImGui::EndMenu();
}
diff --git a/apps/source/AppDemo.cpp b/apps/source/AppDemo.cpp
index a8efbca9..14d8a1ae 100644
--- a/apps/source/AppDemo.cpp
+++ b/apps/source/AppDemo.cpp
@@ -29,7 +29,7 @@ SLDeviceRotation AppDemo::devRot;
SLDeviceLocation AppDemo::devLoc;
SLstring AppDemo::name = "SLProjectApp";
SLstring AppDemo::appTag = "SLProject";
-SLstring AppDemo::version = "4.0.000";
+SLstring AppDemo::version = "4.1.000";
#ifdef _DEBUG
SLstring AppDemo::configuration = "Debug";
#else
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 414bd717..a435f3f7 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -47,7 +47,7 @@ PROJECT_NAME = SLProject
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 4.0.000
+PROJECT_NUMBER = 4.1.000
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
From bd6a7030806fe6c02bb7eed1d6693fa9e201e197 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 11:26:37 +0100
Subject: [PATCH 061/108] Update deploy-wasm-emscripten.yml
---
.github/workflows/deploy-wasm-emscripten.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/deploy-wasm-emscripten.yml b/.github/workflows/deploy-wasm-emscripten.yml
index 4372e6bd..9228fde5 100644
--- a/.github/workflows/deploy-wasm-emscripten.yml
+++ b/.github/workflows/deploy-wasm-emscripten.yml
@@ -5,6 +5,7 @@ on:
push:
branches:
- main
+ - develop
jobs:
deploy:
From f6c3c9fc4d35cc828c682a9ad9cb98e84344e641 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 14:29:46 +0100
Subject: [PATCH 062/108] Cosmetics
Crashes on MacOS on wgpuAdapterGetLimits
---
apps/webgpu/webgpu_demo.cpp | 41 +++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 18 deletions(-)
diff --git a/apps/webgpu/webgpu_demo.cpp b/apps/webgpu/webgpu_demo.cpp
index 64a97a4a..d8059660 100644
--- a/apps/webgpu/webgpu_demo.cpp
+++ b/apps/webgpu/webgpu_demo.cpp
@@ -42,47 +42,47 @@ WebGPU concepts:
- WGPUInstance
The core interface through which all other objects are created.
-
+
- WGPUAdapter
Represents a physical device and is used to query its capabilities and limits.
-
+
- WGPUDevice
Represents a logical device we interact with. It is created by specifying the capabilities we require
and fails if the adapter does not support them. We cannot create more resources than specified in the
limits at creation. This is done to prevent a function from working on one device but not on another.
-
+
- WGPUQueue
The queue is where we submit the commands for the GPU to. Everything that is executed on the GPU goes
through the queue. Examples are executing rendering or compute pipelines, writing to or reading from buffers.
-
+
- WGPUSurface
The surface we draw onto. How it is acquired depends on the OS so we have to manually convert window handles
from the different platforms to surfaces. The surface has to be reconfigured every time the window size
changes.
-
+
- WGPUBuffer
Represents a chunk of memory on the GPU. They can be used for example as vertex buffers, uniforms buffers or
storage buffers. Buffers are created with a fixed size and usage flags that specify e.g. whether we can copy
to this buffer or whether it is used as an index buffer. The memory for the buffer is automatically allocated
at creation but has to be deallocated manually using wgpuBufferDestroy. wgpuQueueWriteBuffer is used to upload
buffer data to the GPU.
-
+
- WGPUTexture
Represents pixel data in the memory of the GPU. It is similar to a buffer in that memory for it is allocated at
creation, that it has usage flags and that the memory is deallocated using wgpuTextureDestroy. Data is uploaded
using wgpuQueueWriteTexture. A texture additionally has a size, a format, a mip level count and a sample count.
Textures can be used in shaders or as a render attachment (e.g. the depth buffer). Mip maps have to be created
manually.
-
+
- WGPUTextureView
To use a texture, a texture view has to be created. It specifies which part of the texture is accessed
(which base array layer, how many array layers, which base mip level, which format, ...).
-
+
- WGPUTextureSampler
To read a texture in a shader, a sampler is commonly used. Textures can also be accessed directly without a
sampler by specifying texel coordinates, which is more like reading the data from a buffer. To get access to
features like filtering, mipmapping or clamping, a sampler is used.
-
+
- WGPURenderPipeline
Represents a configuration of the GPU pipeline. It specifies completely how input data is transformed into
output pixels by settings the configuration for the GPU pipeline stages.
@@ -107,14 +107,14 @@ WebGPU concepts:
A vertex buffer is specified using a WGPUVertexBufferLayout structure that contains a list of
attributes (WGPUVertexAttribute) along with the stride and step mode (per vertex or per instance).
Attributes are specified through a format, an offset in the data and a location in the shader.
- The location is a number hard-coded for the attribute in the shader code.
+ The location is a number hard-coded for the attribute in the shader code.
- primitive: WGPUPrimitiveState
Configuration for the primitive assembly and rasterization stages.
Specifies the topology (triangles, triangle strips, lines, ...), what index format
is used, how the face orientation of triangles is defined and the cull mode.
- depthStencil: WGPUDepthStencilState
Configuration for the depth test and stencil test stages.
- Specifies the format of the depth/stencil buffer and how depth and stencil testing are performed.
+ Specifies the format of the depth/stencil buffer and how depth and stencil testing are performed.
- multisample: WGPUMultisampleState
Configuration for multisampling.
Specifies the number of samples per pixel as well as additional parameters for muiltisampling.
@@ -139,15 +139,15 @@ WebGPU concepts:
A list of layouts for bind groups. A bind group references its layout and they both have to have the same
number of entries. The entries describe the binding, which shader stages can access it as well as additional
info depending on the type. For example, buffer bind group layout entries specify whether they are a uniform
- buffer, a storage buffer or read-only storage.
+ buffer, a storage buffer or read-only storage.
- WGPUPipelineLayout
Specifies the bind groups used in the pipeline.
-
+
- WGPUCommandEncoder
Work for the GPU has to be recorded into a command buffer. This is done using a command encoder. We call
functions on the encoder (wgpuCommandEncoder*) to encode the commands into a buffer that can be accessed by
- calling wgpuCommandEncoderFinish.
+ calling wgpuCommandEncoderFinish.
- WGPUCommandBuffer
When all the GPU commands are recorded, wgpuCommandEncoderFinish is called on the queue which returns a
@@ -157,7 +157,7 @@ WebGPU concepts:
Specifies how a render pipeline is executed. It encodes the pipeline used along with the required vertex
buffers, index buffers, bind groups, drawing commands, etc. Accessing these render commands is done using a
specialized object called a render pass encoder. It is created from a command encoder using
- wgpuCommandEncoderBeginRenderPass.
+ wgpuCommandEncoderBeginRenderPass.
-- WebGPU vs. Vulkan
@@ -188,7 +188,7 @@ Here's a list of things I've noticed are handled differently from Vulkan (as of
implementations. We currently use the wgpu-native implementation, which seems to catch all errors and prints
most of the time a nice error message with a human-readable error message including the labels of the
problematic objects, suggests fixes and even generates a stack trace. I'm not sure what the overhead of
- this validation is, but I excpect there to be an option to turn it off in the future.
+ this validation is, but I excpect there to be an option to turn it off in the future.
*/
@@ -222,7 +222,7 @@ Here's a list of things I've noticed are handled differently from Vulkan (as of
#include
#define WEBGPU_DEMO_LOG(msg) std::cout << (msg) << std::endl
-
+
#define WEBGPU_DEMO_CHECK(condition, errorMsg) \
if (!(condition)) \
{ \
@@ -540,7 +540,12 @@ void initWebGPU(App& app)
WGPURequestAdapterOptions adapterOptions = {};
- wgpuInstanceRequestAdapter(app.instance, &adapterOptions, handleAdapterRequest, &app.adapter);
+ wgpuInstanceRequestAdapter(app.instance,
+ &adapterOptions,
+ handleAdapterRequest,
+ &app.adapter);
+ WEBGPU_DEMO_CHECK(app.adapter, "[WebGPU] Failed to create adapter");
+ WEBGPU_DEMO_LOG("[WebGPU] Adapter created");
WGPUSupportedLimits adapterLimits;
wgpuAdapterGetLimits(app.adapter, &adapterLimits);
From fb17c6dd2c8ef6914c1d7e7ac1915bd0ad02f46a Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Mon, 27 Nov 2023 15:48:13 +0100
Subject: [PATCH 063/108] [Emscripten] Print fatal errors to console
---
modules/utils/source/Utils.cpp | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/modules/utils/source/Utils.cpp b/modules/utils/source/Utils.cpp
index 2f06388b..3376cc1b 100644
--- a/modules/utils/source/Utils.cpp
+++ b/modules/utils/source/Utils.cpp
@@ -67,14 +67,6 @@ namespace fs = std::experimental::filesystem;
using asio::ip::tcp;
#endif
-#ifdef __EMSCRIPTEN__
-// clang-format off
-EM_JS(void, alert, (const char* string), {
- alert(UTF8ToString(string));
-})
-// clang-format on
-#endif
-
using std::fstream;
namespace Utils
@@ -1144,8 +1136,12 @@ void exitMsg(const char* tag,
line,
file);
#elif defined(__EMSCRIPTEN__)
- std::string message = "SLProject error";
- alert(message.c_str());
+ std::cerr << "--------------------------------\n"
+ << "Fatal Error\n"
+ << "Tag: " << tag << '\n'
+ << "Location: " << file << ":" << line << '\n'
+ << "Message: " << msg << '\n'
+ << "--------------------------------" << std::endl;
#else
log(tag,
"Exit %s at line %d in %s\n",
From dc00d3def29c4618fcef50b877c4675e6aa7bb21 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 17:18:34 +0100
Subject: [PATCH 064/108] Update SLTexFont.cpp
---
modules/sl/source/SLTexFont.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/modules/sl/source/SLTexFont.cpp b/modules/sl/source/SLTexFont.cpp
index e6ed18ac..cf4d3c73 100644
--- a/modules/sl/source/SLTexFont.cpp
+++ b/modules/sl/source/SLTexFont.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
@@ -82,7 +83,7 @@ according texture coordinate.
void SLTexFont::create(SLstring fontFilename)
{
// Check the font filename with path
- if (!Utils::fileExists(fontFilename))
+ if (!SLFileStorage::exists(fontFilename, IOK_font))
{
SLstring msg = "SLTexFont::create: File not found: " + fontFilename;
SL_EXIT_MSG(msg.c_str());
From 379b3cf9eff4336f2c02622b3251ab731c2969df Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Mon, 27 Nov 2023 18:25:16 +0100
Subject: [PATCH 065/108] Removed some warnings
---
apps/source/CVCapture.cpp | 2 +-
modules/utils/source/AverageTiming.cpp | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/apps/source/CVCapture.cpp b/apps/source/CVCapture.cpp
index 8b2e0d16..289483d4 100644
--- a/apps/source/CVCapture.cpp
+++ b/apps/source/CVCapture.cpp
@@ -101,7 +101,7 @@ CVSize2i CVCapture::open(int deviceNum)
Utils::log("SLProject", "Exception during OpenCV video capture creation: %s", e.what());
}
#else
- WebCameraFacing facing;
+ WebCameraFacing facing = WebCameraFacing::FRONT;
if (_videoType == VT_MAIN)
facing = WebCameraFacing::BACK;
else if (_videoType == VT_SCND)
diff --git a/modules/utils/source/AverageTiming.cpp b/modules/utils/source/AverageTiming.cpp
index f0ec90aa..8929ec9f 100644
--- a/modules/utils/source/AverageTiming.cpp
+++ b/modules/utils/source/AverageTiming.cpp
@@ -133,7 +133,9 @@ void AverageTiming::doGetTimingMessage(char* m)
{
blocks.push_back(block.second);
}
- std::sort(blocks.begin(), blocks.end(), [](AverageTimingBlock* lhs, AverageTimingBlock* rhs) -> bool
+ std::sort(blocks.begin(),
+ blocks.end(),
+ [](AverageTimingBlock* lhs, AverageTimingBlock* rhs) -> bool
{ return lhs->posV < rhs->posV; });
// find reference time
@@ -142,7 +144,8 @@ void AverageTiming::doGetTimingMessage(char* m)
{
refTime = (*blocks.begin())->val.average();
// insert number of measurement calls
- snprintf(m + strlen(m), sizeof(m), "Num. calls: %i\n", (int)(*blocks.begin())->nCalls);
+ volatile int sizeofm = sizeof(m); // workaround against a warning in the next line
+ snprintf(m + strlen(m), sizeofm, "Num. calls: %i\n", (int)(*blocks.begin())->nCalls);
}
// calculate longest blockname
From 824d4548ea68994ede998297403e9bf23695e2b0 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Tue, 28 Nov 2023 14:42:48 +0100
Subject: [PATCH 066/108] Improved cmake for ios
---
apps/app_demo_slproject/ios/CMakeLists.txt | 6 ++----
scripts/generate_xcode_project_ios.sh | 0
scripts/generate_xcode_project_ios_hsm4.sh | 0
3 files changed, 2 insertions(+), 4 deletions(-)
mode change 100644 => 100755 scripts/generate_xcode_project_ios.sh
mode change 100644 => 100755 scripts/generate_xcode_project_ios_hsm4.sh
diff --git a/apps/app_demo_slproject/ios/CMakeLists.txt b/apps/app_demo_slproject/ios/CMakeLists.txt
index b406f078..8f41ab93 100644
--- a/apps/app_demo_slproject/ios/CMakeLists.txt
+++ b/apps/app_demo_slproject/ios/CMakeLists.txt
@@ -13,19 +13,17 @@ find_library(OPENGLES OpenGLES required)
find_library(GLKIT GLKit required)
find_library(CORELOCATION CoreLocation required)
-set(target Demo-SL)
+set(target AppDemoSLProject)
#if this variable is not defined, we make automatic signing with "iPhone Developer"
if(XCODE_CODESIGNIDENTITY)
message(STATUS "manual signing")
set(APP_BUNDLE_IDENTIFIER "ch.bfh.ti.cpvrlab.demo-sl") # <== Set to your app's bundle identifier (Attention the erlebar one is with "cpvr")
-
set(XCODE_PROVISIONINGPROFILE "Demo SL Development")
set(XCODE_DEVELOPMENTTEAM "858Y9EWZ4B")
else()
message(STATUS "automatic signing")
- #set(APP_BUNDLE_IDENTIFIER "com.${target}") # <== Set to your app's bundle identifier
-
+ set(APP_BUNDLE_IDENTIFIER "com.${target}") # <== Set to your app's bundle identifier
set(XCODE_CODESIGNIDENTITY "iPhone Developer")
set(XCODE_DEVELOPMENTTEAM ${XCODE_DEVELOPMENTTEAM})
endif()
diff --git a/scripts/generate_xcode_project_ios.sh b/scripts/generate_xcode_project_ios.sh
old mode 100644
new mode 100755
diff --git a/scripts/generate_xcode_project_ios_hsm4.sh b/scripts/generate_xcode_project_ios_hsm4.sh
old mode 100644
new mode 100755
From c6072b059ed1c463a3636976c7fc7905eb7193fb Mon Sep 17 00:00:00 2001
From: Marino von Wattenwyl
Date: Thu, 30 Nov 2023 14:59:34 +0100
Subject: [PATCH 067/108] [WebGPU Demo] Fix crash in wgpuAdapterGetLimits
---
apps/webgpu/webgpu_demo.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/webgpu/webgpu_demo.cpp b/apps/webgpu/webgpu_demo.cpp
index d8059660..07db8f2f 100644
--- a/apps/webgpu/webgpu_demo.cpp
+++ b/apps/webgpu/webgpu_demo.cpp
@@ -547,7 +547,7 @@ void initWebGPU(App& app)
WEBGPU_DEMO_CHECK(app.adapter, "[WebGPU] Failed to create adapter");
WEBGPU_DEMO_LOG("[WebGPU] Adapter created");
- WGPUSupportedLimits adapterLimits;
+ WGPUSupportedLimits adapterLimits = {};
wgpuAdapterGetLimits(app.adapter, &adapterLimits);
// === Acquire a WebGPU device ===
From be31261f7ab3c2832e2e8b509a1420211dc81938 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Fri, 1 Dec 2023 13:56:30 +0100
Subject: [PATCH 068/108] Excluded WebGPU for Emscripten
---
apps/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index d4889f7a..5f9a5172 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -10,7 +10,7 @@ else()
add_subdirectory(app_demo_node)
add_subdirectory(app_demo_slproject)
- if (SL_BUILD_WEBGPU_DEMO)
+ if (SL_BUILD_WEBGPU_DEMO AND NOT ("${SYSTEM_NAME_UPPER}" MATCHES "EMSCRIPTEN"))
add_subdirectory(webgpu)
endif ()
endif()
\ No newline at end of file
From 37681e1aae8144047b7b3de2d4e333fb607f2fc8 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Thu, 7 Dec 2023 13:53:49 +0100
Subject: [PATCH 069/108] Fixed particle shaders for iOS
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 11 +-
modules/sl/source/gl/SLGLProgramGenerated.cpp | 396 ++++++++----------
modules/sl/source/mesh/SLMesh.cpp | 4 +-
modules/sl/source/mesh/SLParticleSystem.cpp | 100 ++---
modules/sl/source/mesh/SLParticleSystem.h | 21 +-
modules/utils/externals/CMakeLists.txt | 42 ++
6 files changed, 271 insertions(+), 303 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index c9f40bbf..d74b83c1 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -3736,11 +3736,14 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
ps->isGenerated(false);
}
- bool renderInstanced = ps->renderInstanced();
- if (ImGui::Checkbox("Instanced draw", &renderInstanced))
+ if (SLGLState::instance()->glHasGeometryShaders())
{
- ps->drawInstanced(renderInstanced);
- ps->isGenerated(false);
+ bool drawInstanced = ps->drawInstanced();
+ if (ImGui::Checkbox("Instanced draw", &drawInstanced))
+ {
+ ps->drawInstanced(drawInstanced);
+ ps->isGenerated(false);
+ }
}
// TTL (Time to live)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index 2eee9230..b86f0973 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -44,8 +44,8 @@ const string vertInput_PS_a_texNum = R"(
layout (location = 6) in uint a_texNum; // Particle rotation attribute)";
const string vertInput_PS_a_initP = R"(
layout (location = 7) in vec3 a_initialPosition;// Particle initial position attribute)";
-const string vertInput_PS_a_positionP = R"(
-layout (location = 8) in vec3 a_positionP; // Particle position attribute)";
+const string vertInput_PS_a_positionP = R"(
+layout (location = 8) in vec3 a_positionP; // Particle position attribute)";
const string vertInput_a_uv0 = R"(
layout (location = 2) in vec2 a_uv0; // Vertex tex.coord. 1 for diffuse color)";
const string vertInput_a_uv1 = R"(
@@ -53,22 +53,21 @@ layout (location = 3) in vec2 a_uv1; // Vertex tex.coord. 2 for AO)"
const string vertInput_a_tangent = R"(
layout (location = 5) in vec4 a_tangent; // Vertex tangent attribute)";
const string vertInput_a_skinning = R"(
-
layout (location = 6) in ivec4 a_jointIds; // Vertex joint indices attributes
layout (location = 7) in vec4 a_jointWeights; // Vertex joint weights attributes)";
//-----------------------------------------------------------------------------
const string vertInput_u_matrices_all = R"(
-uniform mat4 u_mMatrix; // Model matrix (object to world transform)
-uniform mat4 u_vMatrix; // View matrix (world to camera transform)
-uniform mat4 u_pMatrix; // Projection matrix (camera to normalize device coords.))";
+uniform mat4 u_mMatrix; // Model matrix (object to world transform)
+uniform mat4 u_vMatrix; // View matrix (world to camera transform)
+uniform mat4 u_pMatrix; // Projection matrix (camera to normalize device coords.))";
const string vertInput_u_matrix_vOmv = R"(
-uniform mat4 u_vOmvMatrix; // view or modelview matrix)";
+uniform mat4 u_vOmvMatrix; // view or modelview matrix)";
//-----------------------------------------------------------------------------
const string vertInput_u_skinning = R"(
-uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning
-uniform bool u_skinningEnabled; // Flag if the shader should perform skinning
+uniform mat4 u_jointMatrices[100]; // Joint matrices for skinning
+uniform bool u_skinningEnabled; // Flag if the shader should perform skinning
)";
//-----------------------------------------------------------------------------
const string vertInput_u_lightNm = R"(
@@ -87,8 +86,8 @@ const string vertInput_PS_u_time = R"(
uniform float u_time; // Simulation time
uniform float u_difTime; // Simulation delta time after frustum culling
uniform float u_tTL; // Time to live of a particle)";
-const string fragInput_PS_u_tTL = R"(
-uniform float u_tTL; // Time to live of a particle)";
+const string fragInput_PS_u_tTL = R"(
+uniform float u_tTL; // Time to live of a particle)";
const string vertInput_PS_u_al_bernstein_alpha = R"(
uniform vec4 u_al_bernstein; // Bernstein polynomial for alpha over time)";
const string vertInput_PS_u_al_bernstein_size = R"(
@@ -141,7 +140,7 @@ vec3 colorByAge(float age)
vec3 color = vec3(u_colorArr[cachePos], u_colorArr[cachePos + 1], u_colorArr[cachePos + 2]);
return color;
})";
-
+//-----------------------------------------------------------------------------
const string fragFunction_PS_ColorOverLT = R"(
vec3 colorByAge(float age)
{
@@ -149,7 +148,6 @@ vec3 colorByAge(float age)
vec3 color = vec3(u_colorArr[cachePos], u_colorArr[cachePos + 1], u_colorArr[cachePos + 2]);
return color;
})";
-
//-----------------------------------------------------------------------------
const string vertOutput_PS_struct_Begin = R"(
@@ -168,41 +166,27 @@ const string vertOutput_PS_struct_texNum = R"(
const string vertOutput_PS_struct_End = R"(
} vert; )";
-const string vertOutput_PS_instanced_transparency = R"(
-out float transparency; // transparency of a particle )";
-
-const string fragInput_PS_instanced_transparency = R"(
-in float transparency; // transparency of a particle )";
+const string vertOutput_PS_instanced_transparency = R"(
+out float transparency; // transparency of a particle )";
+const string fragInput_PS_instanced_transparency = R"(
+in float transparency; // transparency of a particle )";
-const string fragMain_PS_v_c = R"(
- vec4 color = u_color; // Particle color)";
-const string fragMain_PS_v_doColorOverLT = R"(
- vec4 color = vec4(vert[0].color, 1.0); // Particle color)";
-const string fragMain_PS_instanced_v_doColorOverLT = R"(
+const string fragMain_PS_instanced_v_doColorOverLT = R"(
vec4 color = vec4(colorByAge(v_age/u_tTL), 1.0); // Particle color)";
-const string fragMain_PS_v_withoutColor = R"(
- vec4 color = vec4( 0.0, 0.0, 0.0, 1.0); // Particle color)";
-const string fragMain_PS_instanced_c = R"(
+const string fragMain_PS_instanced_c = R"(
vec4 color = u_color; // Particle color)";
-const string fragMain_PS_instanced_transparency = R"(
+const string fragMain_PS_instanced_transparency = R"(
color.w *= transparency; // Apply transparency)";
-const string vertInput_u_matrix_p = R"(
-uniform mat4 u_pMatrix; // Projection matrix)";
-const string vertInput_u_matrix_vertBillboard = R"(
-uniform mat4 u_vYawPMatrix; // Projection matrix)";
-const string fragInput_PS_u_c = R"(
-uniform vec4 u_color; // Particle color)";
-const string vertInput_PS_u_ScaRa = R"(
-uniform float u_scale; // Particle scale
-uniform float u_radiusW; // Particle width radius)
-uniform float u_radiusH; // Particle height radius)";
-//-----------------------------------------------------------------------------
-
-const string vertOutput_PS_color = R"(
-out vec4 v_particleColor; // Size of a particle )";
-
-const string vertOutput_PS_texCoord = R"(
-out vec2 v_texCoord; // interpolated texture coordinateA)";
+const string vertInput_u_matrix_p = R"(
+uniform mat4 u_pMatrix; // Projection matrix)";
+const string vertInput_u_matrix_vertBillboard = R"(
+uniform mat4 u_vYawPMatrix; // Projection matrix)";
+const string fragInput_PS_u_c = R"(
+uniform vec4 u_color; // Particle color)";
+const string vertInput_PS_u_ScaRa = R"(
+uniform float u_scale; // Particle scale
+uniform float u_radiusW; // Particle width radius)
+uniform float u_radiusH; // Particle height radius)";
//-----------------------------------------------------------------------------
const string vertOutput_PS_tf_p = R"(
@@ -224,34 +208,29 @@ const string vertOutput_PS_tf_initP = R"(
out vec3 tf_initialPosition; // To transform feedback)";
//-----------------------------------------------------------------------------
-const string vertMain_Begin = R"(
+const string main_Begin = R"(
+//-----------------------------------------------------------------------------
void main()
{)";
-
-const string vertMain_instanced_Begin = R"(
-void main()
-{
- vec3 position = a_positionP;
-)";
-
-const string vertMain_v_P_VS = R"(
+//-----------------------------------------------------------------------------
+const string vertMain_v_P_VS = R"(
mat4 mvMatrix = u_vMatrix * u_mMatrix;
v_P_VS = vec3(mvMatrix * ${localPosition}); // vertex position in view space)";
-const string vertMain_v_P_WS_Sm = R"(
+const string vertMain_v_P_WS_Sm = R"(
v_P_WS = vec3(u_mMatrix * ${localPosition}); // vertex position in world space)";
-const string vertMain_v_N_VS = R"(
+const string vertMain_v_N_VS = R"(
mat3 invMvMatrix = mat3(inverse(mvMatrix));
mat3 nMatrix = transpose(invMvMatrix);
v_N_VS = vec3(nMatrix * ${localNormal}); // vertex normal in view space)";
-const string vertMain_v_R_OS = R"(
+const string vertMain_v_R_OS = R"(
vec3 I = normalize(v_P_VS);
vec3 N = normalize(v_N_VS);
v_R_OS = invMvMatrix * reflect(I, N); // R = I-2.0*dot(N,I)*N;)";
-const string vertMain_v_uv0 = R"(
+const string vertMain_v_uv0 = R"(
v_uv0 = a_uv0; // pass diffuse color tex.coord. 1 for interpolation)";
-const string vertMain_v_uv1 = R"(
+const string vertMain_v_uv1 = R"(
v_uv1 = a_uv1; // pass diffuse color tex.coord. 1 for interpolation)";
-const string vertMain_skinning = R"(
+const string vertMain_skinning = R"(
vec4 skinnedPosition;
vec3 skinnedNormal;
@@ -275,7 +254,7 @@ const string vertMain_skinning = R"(
skinnedNormal = a_normal;
}
)";
-const string vertMain_skinning_Nm = R"(
+const string vertMain_skinning_Nm = R"(
vec4 skinnedPosition;
vec3 skinnedNormal;
vec4 skinnedTangent;
@@ -302,7 +281,7 @@ const string vertMain_skinning_Nm = R"(
skinnedTangent = a_tangent;
}
)";
-const string vertMain_TBN_Nm = R"(
+const string vertMain_TBN_Nm = R"(
// Building the matrix Eye Space -> Tangent Space
// See the math behind at: http://www.terathon.com/code/tangent.html
@@ -330,144 +309,124 @@ const string vertMain_TBN_Nm = R"(
//-----------------------------------------------------------------------------
// Things that goes directly to geometry shader
-const string vertMain_PS_v_t_default = R"(
+const string vertMain_PS_v_t_default = R"(
if(age < 0.0)
vert.transparency = 0.0; // To be discard, because the particle is to be born
else
vert.transparency = 1.0;)";
-const string vertMain_PS_v_t_begin = R"(
+const string vertMain_PS_v_t_begin = R"(
if(age < 0.0)
vert.transparency = 0.0; // To be discard, because the particle is to be born
else
{
vert.transparency = age / u_tTL; // Get by the ratio age:lifetime)";
-const string vertMain_PS_v_t_linear = R"(
+const string vertMain_PS_v_t_linear = R"(
vert.transparency = 1.0 - vert.transparency; // Linear)";
-const string vertMain_PS_v_t_curve = R"(
+const string vertMain_PS_v_t_curve = R"(
vert.transparency = pow(vert.transparency,3.0) * u_al_bernstein.x +
pow(vert.transparency,2.0) * u_al_bernstein.y +
vert.transparency * u_al_bernstein.z +
u_al_bernstein.w; // Get transparency by bezier curve)";
-const string vertMain_PS_v_t_end = R"(
+const string vertMain_PS_v_t_end = R"(
})";
-const string vertMain_PS_v_r = R"(
+const string vertMain_PS_v_r = R"(
vert.rotation = a_rotation;)";
-const string vertMain_PS_v_s = R"(
+const string vertMain_PS_v_s = R"(
vert.size = age / u_tTL;)";
-const string vertMain_PS_v_s_curve = R"(
+const string vertMain_PS_v_s_curve = R"(
vert.size = pow(vert.size,3.0) * u_si_bernstein.x +
pow(vert.size,2.0) * u_si_bernstein.y +
vert.size * u_si_bernstein.z +
u_si_bernstein.w; // Get transparency by bezier curve)";
-const string vertMain_PS_instanced_v_r = R"(
- float rotation = a_rotation;)";
-
-const string vertMain_PS_instanced_v_s = R"(
- float size = age / u_tTL;)";
-const string vertMain_PS_instanced_v_s_curve = R"(
- size = pow(size,3.0) * u_si_bernstein.x +
- pow(size,2.0) * u_si_bernstein.y +
- size * u_si_bernstein.z +
- u_si_bernstein.w; // Get transparency by bezier curve)";
-
-const string vertMain_PS_instanced_v_sS = R"(
- position = size * position;
- )";
-
-const string vertMain_PS_v_doColorOverLT = R"(
+const string vertMain_PS_v_doColorOverLT = R"(
vert.color = colorByAge(age/u_tTL);)";
-
-const string vertOutput_PS_age = R"(
+const string vertOutput_PS_age = R"(
out float v_age; // Age of a particle)";
-
-const string fragInput_PS_age = R"(
+const string fragInput_PS_age = R"(
in float v_age; // Age of a particle)";
-
-const string vertMain_PS_v_color = R"(
- vert.color = u_color.rgb;)";
-
-const string vertMain_PS_v_texNum = R"(
+const string vertMain_PS_v_texNum = R"(
vert.texNum = a_texNum;)";
-
-const string vertMain_PS_v_a = R"(
+const string vertMain_PS_v_a = R"(
float age = u_time - a_startTime; // Get the age of the particle)";
-
-const string vertMain_PS_v_tC = R"(
+const string vertMain_PS_v_tC = R"(
v_texCoord = 0.5 * (a_positionP.xy + vec2(1.0));)";
-
-const string vertMain_PS_v_age = R"(
+const string vertMain_PS_v_age = R"(
v_age = age;)";
-
-const string vertMain_PS_v_tC_flipbook = R"(
- uint actCI = uint(mod(float(a_texNum), float(u_col)));
- uint actRI = (a_texNum - actCI) / u_col;
+const string vertMain_PS_v_tC_flipbook = R"(
+ int actCI = int(mod(float(a_texNum), float(u_col)));
float actC = float(actCI);
- float actR = float(actRI);
+ float actR = floor(float(int(a_texNum) - actCI) / float(u_col));
vec2 p = 0.5 * (a_positionP.xy + vec2(1.0));
v_texCoord = vec2((actC + p.x)/float(u_col), 1.0 - (actR - p.y)/float(u_row));
)";
-const string vertMain_PS_instanced_v_t_default = R"(
+const string vertMain_PS_instanced_position = R"(
+ vec3 position = a_positionP;
+)";
+const string vertMain_PS_instanced_v_s = R"(
+ float size = age / u_tTL;)";
+const string vertMain_PS_instanced_v_s_curve = R"(
+ size = pow(size,3.0) * u_si_bernstein.x +
+ pow(size,2.0) * u_si_bernstein.y +
+ size * u_si_bernstein.z +
+ u_si_bernstein.w; // Get transparency by bezier curve)";
+const string vertMain_PS_instanced_v_sS = R"(
+ position = size * position;
+ )";
+const string vertMain_PS_instanced_v_t_default = R"(
if(age < 0.0)
transparency = 0.0; // To be discard, because the particle is to be born
else
transparency = 1.0;)";
-const string vertMain_PS_instanced_v_t_begin = R"(
+const string vertMain_PS_instanced_v_t_begin = R"(
if(age < 0.0)
transparency = 0.0; // To be discard, because the particle is to be born
else
{
transparency = age / u_tTL; // Get by the ratio age:lifetime)";
-const string vertMain_PS_instanced_v_t_linear = R"(
+const string vertMain_PS_instanced_v_t_linear = R"(
transparency = 1.0 - transparency; // Linear)";
-const string vertMain_PS_instanced_v_t_curve = R"(
+const string vertMain_PS_instanced_v_t_curve = R"(
transparency = pow(transparency,3.0) * u_al_bernstein.x +
pow(transparency,2.0) * u_al_bernstein.y +
transparency * u_al_bernstein.z +
u_al_bernstein.w; // Get transparency by bezier curve)";
-
-const string vertMain_PS_instanced_scale = R"(
+const string vertMain_PS_instanced_scale = R"(
position = vec3(u_radiusW * position.x, u_radiusH * position.y, position.z);
position = u_scale * position;
)";
-
-const string vertMain_PS_instanced_rotate = R"(
+const string vertMain_PS_instanced_rotate = R"(
mat2 rot = mat2(cos(a_rotation),-sin(a_rotation),
sin(a_rotation), cos(a_rotation)); // Matrix of rotation
position = vec3(rot * position.xy, position.z);
)";
-
-const string vertMain_PS_instanced_EndAll = R"(
+const string vertMain_PS_instanced_EndAll = R"(
// Modelview matrix multiplication with (particle position + particle generator position)
// Calculate position in view space
gl_Position = u_pMatrix * (u_vOmvMatrix * vec4(a_position, 1) + vec4(position, 0.0));
}
)";
-
const string vertMain_PS_instanced_EndAll_VertBillboard = R"(
//gl_Position = vec4(a_position + a_positionP, 1);
gl_Position = u_pMatrix * u_vYawPMatrix * vec4(a_position + position, 1.0);
}
)";
-
-const string vertMain_PS_EndAll = R"(
+const string vertMain_PS_EndAll = R"(
// Modelview matrix multiplication with (particle position + particle generator position)
// Calculate position in view space
gl_Position = u_vOmvMatrix * vec4(a_position, 1);
}
)";
-
const string vertMain_PS_EndAll_VertBillboard = R"(
gl_Position = vec4(a_position, 1);
}
)";
-
-const string vertMain_EndAll = R"(
+const string vertMain_EndAll = R"(
// pass the vertex w. the fix-function transform
gl_Position = u_pMatrix * mvMatrix * ${localPosition};
@@ -475,9 +434,6 @@ const string vertMain_EndAll = R"(
)";
//-----------------------------------------------------------------------------
const string vertMain_PS_U_Begin = R"(
-
-void main()
-{
vec4 P = vec4(a_position.xyz, 1.0); // Need to be here for the compilation
gl_Position = P; // Need to be here for the compilation)";
const string vertMain_PS_U_v_init_p = R"(
@@ -496,8 +452,7 @@ const string vertMain_PS_U_v_init_texNum = R"(
tf_texNum = a_texNum; // Init the output variable)";
const string vertMain_PS_U_v_init_initP = R"(
tf_initialPosition = a_initialPosition; // Init the output variable)";
-
-const string vertMain_PS_U_bornDead = R"(
+const string vertMain_PS_U_bornDead = R"(
tf_startTime += u_difTime; // Add time to resume after frustum culling
if( u_time >= tf_startTime )
@@ -505,51 +460,48 @@ const string vertMain_PS_U_bornDead = R"(
float age = u_time - tf_startTime; // Get the age of the particle
if( age > u_tTL)
{ )";
-const string vertMain_PS_U_reset_p = R"(
+const string vertMain_PS_U_reset_p = R"(
// The particle is past its lifetime, recycle.
tf_position = u_pGPosition; // Reset position)";
-const string vertMain_PS_U_reset_shape_p = R"(
+const string vertMain_PS_U_reset_shape_p = R"(
// The particle is past its lifetime, recycle.
tf_position = a_initialPosition + u_pGPosition; // Reset position)";
-const string vertMain_PS_U_reset_v = R"(
+const string vertMain_PS_U_reset_v = R"(
tf_velocity = a_initialVelocity; // Reset velocity)";
-const string vertMain_PS_U_reset_st_counterGap = R"(
+const string vertMain_PS_U_reset_st_counterGap = R"(
tf_startTime = u_time + (age - u_tTL); // Reset start time to actual time with counter gap)";
-const string vertMain_PS_U_reset_st = R"(
+const string vertMain_PS_U_reset_st = R"(
tf_startTime = u_time; // Reset start time to actual time)";
-const string vertMain_PS_U_alive_p = R"(
+const string vertMain_PS_U_alive_p = R"(
} else
{
// The particle is alive, update.
tf_position += tf_velocity * u_deltaTime; // Scale the translation by the delta time)";
-const string vertMain_PS_U_v_rConst = R"(
+const string vertMain_PS_U_v_rConst = R"(
tf_rotation = mod(tf_rotation + (u_angularVelo*u_deltaTime), TWOPI);)";
-const string vertMain_PS_U_v_rRange = R"(
+const string vertMain_PS_U_v_rRange = R"(
tf_rotation = mod(tf_rotation + (tf_angularVelo*u_deltaTime), TWOPI);)";
-const string vertMain_PS_U_alive_a_const = R"(
+const string vertMain_PS_U_alive_a_const = R"(
tf_velocity += tf_initialVelocity * u_deltaTime * u_accConst; // Amplify the velocity)";
-const string vertMain_PS_U_alive_a_diffDir = R"(
+const string vertMain_PS_U_alive_a_diffDir = R"(
tf_velocity += u_deltaTime * u_acceleration; // Amplify the velocity)";
-const string vertMain_PS_U_alive_g = R"(
+const string vertMain_PS_U_alive_g = R"(
tf_velocity += u_deltaTime * u_gravity; // Apply gravity)";
-const string vertMain_PS_U_alive_texNum = R"(
+const string vertMain_PS_U_alive_texNum = R"(
if(u_condFB == 1)
{
tf_texNum++; // Increment to draw next texture (flipbook)
tf_texNum = uint(mod(float(tf_texNum), float(u_col * u_row))); // Modulo to not exceed the max and reset
})";
-const string vertMain_PS_U_EndAll = R"(
+const string vertMain_PS_U_EndAll = R"(
}
}
})";
-
-
//-----------------------------------------------------------------------------
-const string geomConfig_PS = R"(
+const string geomConfig_PS = R"(
layout (points) in; // Primitives that we received from vertex shader
layout (triangle_strip, max_vertices = 4) out; // Primitives that we will output and number of vertex that will be output)";
-
const string geomInput_PS_struct_Begin = R"(
in vertex { )";
const string geomInput_PS_struct_t = R"(
@@ -566,33 +518,27 @@ const string geomInput_PS_struct_End = R"(
} vert[]; )";
//-----------------------------------------------------------------------------
const string geomInput_u_matrix_p = R"(
-uniform mat4 u_pMatrix; // Projection matrix)";
+uniform mat4 u_pMatrix; // Projection matrix)";
const string geomInput_u_matrix_vertBillboard = R"(
-uniform mat4 u_vYawPMatrix; // Projection matrix)";
+uniform mat4 u_vYawPMatrix; // Projection matrix)";
const string geomInput_PS_u_ScaRa = R"(
-uniform float u_scale; // Particle scale
-uniform float u_radiusW; // Particle width radius)
-uniform float u_radiusH; // Particle height radius)";
+uniform float u_scale; // Particle scale
+uniform float u_radiusW; // Particle width radius)
+uniform float u_radiusH; // Particle height radius)";
const string geomInput_PS_u_c = R"(
-uniform vec4 u_color; // Particle color)";
+uniform vec4 u_color; // Particle color)";
const string geomInput_PS_u_col = R"(
-uniform int u_col; // Number of column of flipbook texture)";
+uniform int u_col; // Number of column of flipbook texture)";
const string geomInput_PS_u_row = R"(
-uniform int u_row; // Number of row of flipbook texture)";
+uniform int u_row; // Number of row of flipbook texture)";
//-----------------------------------------------------------------------------
const string geomOutput_PS_v_pC = R"(
-out vec4 v_particleColor; // The resulting color per vertex)";
+out vec4 v_particleColor; // The resulting color per vertex)";
const string geomOutput_PS_v_tC = R"(
-out vec2 v_texCoord; // Texture coordinate at vertex)";
-
+out vec2 v_texCoord; // Texture coordinate at vertex)";
const string vertOutput_PS_v_tC = R"(
-out vec2 v_texCoord; // Texture coordinate at vertex)";
+out vec2 v_texCoord; // Texture coordinate at vertex)";
//-----------------------------------------------------------------------------
-const string geomMain_PS_Begin = R"(
-
-void main()
-{)";
-
const string geomMain_PS_v_s = R"(
float scale = u_scale;)";
const string geomMain_PS_v_sS = R"(
@@ -816,42 +762,38 @@ const string geomMain_PS_EndAll = R"(
} )";
//-----------------------------------------------------------------------------
const string fragInput_v_P_VS = R"(
-in vec3 v_P_VS; // Interpol. point of illumination in view space (VS))";
+in vec3 v_P_VS; // Interpol. point of illumination in view space (VS))";
const string fragInput_v_P_WS = R"(
-in vec3 v_P_WS; // Interpol. point of illumination in world space (WS))";
+in vec3 v_P_WS; // Interpol. point of illumination in world space (WS))";
const string fragInput_v_N_VS = R"(
-in vec3 v_N_VS; // Interpol. normal at v_P_VS in view space)";
+in vec3 v_N_VS; // Interpol. normal at v_P_VS in view space)";
const string fragInput_v_R_OS = R"(
-in vec3 v_R_OS; // Interpol. reflect in object space)";
+in vec3 v_R_OS; // Interpol. reflect in object space)";
const string fragInput_v_uv0 = R"(
-in vec2 v_uv0; // Texture coordinate varying)";
+in vec2 v_uv0; // Texture coordinate varying)";
const string fragInput_v_uv1 = R"(
-in vec2 v_uv1; // Texture coordinate varying)";
+in vec2 v_uv1; // Texture coordinate varying)";
const string fragInput_v_lightVecTS = R"(
in vec3 v_eyeDirTS; // Vector to the eye in tangent space
in vec3 v_lightDirTS[NUM_LIGHTS]; // Vector to light 0 in tangent space
in vec3 v_spotDirTS[NUM_LIGHTS]; // Spot direction in tangent space)";
//-----------------------------------------------------------------------------
const string fragInput_PS_v_pC = R"(
-in vec4 v_particleColor; // interpolated color from the geometry shader)";
+in vec4 v_particleColor; // interpolated color from the geometry shader)";
const string fragInput_PS_v_tC = R"(
-in vec2 v_texCoord; // interpolated texture coordinate)";
+in vec2 v_texCoord; // interpolated texture coordinate)";
//-----------------------------------------------------------------------------
const string fragInput_PS_u_overG = R"(
-uniform float u_oneOverGamma; // 1.0f / Gamma correction value)";
+uniform float u_oneOverGamma; // 1.0f / Gamma correction value)";
const string fragInput_PS_u_wireFrame = R"(
-uniform bool u_doWireFrame; // Boolean for wireFrame)";
+uniform bool u_doWireFrame; // Boolean for wireFrame)";
//-----------------------------------------------------------------------------
const string fragMain_PS_TF = R"(
-out vec4 o_fragColor; // output fragment color
-
-void main()
-{
o_fragColor = vec4(0,0,0,0); // Need to be here for the compilation
}
)";
//-----------------------------------------------------------------------------
-const string fragMain_PS = R"(
+const string fragMain_PS = R"(
// Just set the interpolated color from the vertex shader
o_fragColor = v_particleColor;
@@ -862,13 +804,7 @@ const string fragMain_PS = R"(
if(o_fragColor.a < 0.001)
discard;
)";
-
-const string fragMain_PS_begin = R"(
-void main()
-{
-)";
-
-const string fragMain_PS_withoutColor = R"(
+const string fragMain_PS_withoutColor = R"(
// componentwise multiply w. texture color
if(!u_doWireFrame)
o_fragColor = texture(u_matTextureDiffuse0, v_texCoord);
@@ -880,7 +816,6 @@ const string fragMain_PS_withoutColor = R"(
if(o_fragColor.a < 0.001)
discard;
)";
-
const string fragMain_PS_instanced_withoutColor = R"(
// componentwise multiply w. texture color
if(!u_doWireFrame)
@@ -893,8 +828,7 @@ const string fragMain_PS_instanced_withoutColor = R"(
if(o_fragColor.a < 0.001)
discard;
)";
-
-const string fragMain_instanced_PS_end = R"(
+const string fragMain_instanced_PS_end = R"(
// Just set the interpolated color from the vertex shader
o_fragColor = color;
// componentwise multiply w. texture color
@@ -904,8 +838,7 @@ const string fragMain_instanced_PS_end = R"(
if(o_fragColor.a < 0.001)
discard;
)";
-
-const string fragMain_PS_endAll = R"(
+const string fragMain_PS_endAll = R"(
//Same color for each wireframe
if(u_doWireFrame)
o_fragColor = vec4(0,0,0,1.0);
@@ -913,7 +846,7 @@ const string fragMain_PS_endAll = R"(
o_fragColor.rgb = pow(o_fragColor.rgb, vec3(u_oneOverGamma));
})";
//-----------------------------------------------------------------------------
-const string fragInput_u_lightAll = R"(
+const string fragInput_u_lightAll = R"(
uniform bool u_lightIsOn[NUM_LIGHTS]; // flag if light is on
uniform vec4 u_lightPosVS[NUM_LIGHTS]; // position of light in view space
@@ -929,52 +862,52 @@ uniform bool u_lightDoAtt[NUM_LIGHTS]; // flag if att. must be calc
uniform vec4 u_globalAmbi; // Global ambient scene color
uniform float u_oneOverGamma; // 1.0f / Gamma correction value
)";
-const string fragInput_u_matBlinnAll = R"(
+const string fragInput_u_matBlinnAll = R"(
uniform vec4 u_matAmbi; // ambient color reflection coefficient (ka)
uniform vec4 u_matDiff; // diffuse color reflection coefficient (kd)
uniform vec4 u_matSpec; // specular color reflection coefficient (ks)
uniform vec4 u_matEmis; // emissive color for self-shining materials
uniform float u_matShin; // shininess exponent
)";
-const string fragInput_u_matAmbi = R"(
+const string fragInput_u_matAmbi = R"(
uniform vec4 u_matAmbi; // ambient color reflection coefficient (ka))";
-const string fragInput_u_matDiff = R"(
+const string fragInput_u_matDiff = R"(
uniform vec4 u_matDiff; // diffuse color reflection coefficient (kd))";
-const string fragInput_u_matEmis = R"(
+const string fragInput_u_matEmis = R"(
uniform vec4 u_matEmis; // emissive color (ke))";
-const string fragInput_u_matRough = R"(
+const string fragInput_u_matRough = R"(
uniform float u_matRough; // roughness factor (0-1))";
-const string fragInput_u_matMetal = R"(
+const string fragInput_u_matMetal = R"(
uniform float u_matMetal; // metalness factor (0-1)";
//-----------------------------------------------------------------------------
-const string fragInput_u_matTexDm = R"(
+const string fragInput_u_matTexDm = R"(
uniform sampler2D u_matTextureDiffuse0; // Diffuse color map)";
-const string fragInput_u_matTexNm = R"(
+const string fragInput_u_matTexNm = R"(
uniform sampler2D u_matTextureNormal0; // Normal bump map)";
-const string fragInput_u_matTexEm = R"(
+const string fragInput_u_matTexEm = R"(
uniform sampler2D u_matTextureEmissive0; // PBR material emissive texture)";
-const string fragInput_u_matTexOm = R"(
+const string fragInput_u_matTexOm = R"(
uniform sampler2D u_matTextureOcclusion0; // Ambient occlusion map)";
-const string fragInput_u_matTexRm = R"(
+const string fragInput_u_matTexRm = R"(
uniform sampler2D u_matTextureRoughness0; // PBR material roughness texture)";
-const string fragInput_u_matTexMm = R"(
+const string fragInput_u_matTexMm = R"(
uniform sampler2D u_matTextureMetallic0; // PBR material metallic texture)";
-const string fragInput_u_matTexRmMm = R"(
+const string fragInput_u_matTexRmMm = R"(
uniform sampler2D u_matTextureRoughMetal0; // PBR material roughness-metallic texture)";
-const string fragInput_u_matTexOmRmMm = R"(
+const string fragInput_u_matTexOmRmMm = R"(
uniform sampler2D u_matTextureOccluRoughMetal0; // PBR material occlusion-roughness-metalic texture)";
-const string fragInput_u_matGetsSm = R"(
+const string fragInput_u_matGetsSm = R"(
uniform bool u_matGetsShadows; // flag if material receives shadows)";
-const string fragInput_u_skyCookEnvMaps = R"(
-uniform samplerCube u_skyIrradianceCubemap; // PBR skybox irradiance light
-uniform samplerCube u_skyRoughnessCubemap; // PBR skybox cubemap for rough reflections
-uniform sampler2D u_skyBrdfLutTexture; // PBR lighting lookup table for BRDF
-uniform float u_skyExposure; // PBR skybox exposure)";
+const string fragInput_u_skyCookEnvMaps = R"(
+uniform samplerCube u_skyIrradianceCubemap; // PBR skybox irradiance light
+uniform samplerCube u_skyRoughnessCubemap; // PBR skybox cubemap for rough reflections
+uniform sampler2D u_skyBrdfLutTexture; // PBR lighting lookup table for BRDF
+uniform float u_skyExposure; // PBR skybox exposure)";
//-----------------------------------------------------------------------------
const string fragInput_u_cam = R"(
-uniform int u_camProjType; // type of stereo
+uniform int u_camProjType; // type of stereo
uniform int u_camStereoEye; // -1=left, 0=center, 1=right
uniform mat3 u_camStereoColors; // color filter matrix
uniform bool u_camFogIsOn; // flag if fog is on
@@ -1318,10 +1251,6 @@ void doColoredShadows(in vec3 N)
}
})";
//-----------------------------------------------------------------------------
-const string fragMain_Begin = R"(
-//-----------------------------------------------------------------------------
-void main()
-{)";
const string fragMain_0_Intensities = R"(
vec4 Ia = vec4(0.0); // Accumulated ambient light intensity at v_P_VS
vec4 Id = vec4(0.0); // Accumulated diffuse light intensity at v_P_VS
@@ -1717,8 +1646,6 @@ const string fragMainCook_3_FragColorSky = R"(
)";
//-----------------------------------------------------------------------------
const string fragMainVideoBkgd = R"(
-void main()
-{
float x = (gl_FragCoord.x - u_camBkgdLeft) / u_camBkgdWidth;
float y = (gl_FragCoord.y - u_camBkgdBottom) / u_camBkgdHeight;
@@ -1972,7 +1899,9 @@ void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
* @param mat Parent material pointer
* @param isDrawProg Flag if program is for drawing instead of update
*/
-void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool renderInstanced)
+void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat,
+ bool isDrawProg,
+ bool renderInstanced)
{
if (mat->name() == "IBLMat")
{
@@ -2045,7 +1974,7 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
if (Nm) vertCode += vertOutput_v_lightVecTS;
// Vertex shader main loop
- vertCode += vertMain_Begin;
+ vertCode += main_Begin;
if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
@@ -2103,7 +2032,7 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
if (Sm) fragCode += fragFunctionDoColoredShadows;
// Fragment shader main loop
- fragCode += fragMain_Begin;
+ fragCode += main_Begin;
fragCode += fragMain_0_Intensities;
fragCode += Nm ? fragMain_1_EN_in_TS : fragMain_1_EN_in_VS;
fragCode += Dm ? fragMainCook_1_matDiff_Dm : fragMainCook_1_matDiff;
@@ -2170,7 +2099,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (Nm) vertCode += vertOutput_v_lightVecTS;
// Vertex shader main loop
- vertCode += vertMain_Begin;
+ vertCode += main_Begin;
if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
@@ -2222,7 +2151,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (Sm) fragCode += fragFunctionDoColoredShadows;
// Fragment shader main loop
- fragCode += fragMain_Begin;
+ fragCode += main_Begin;
fragCode += fragMain_0_Intensities;
fragCode += Nm ? fragMain_1_EN_in_TS : fragMain_1_EN_in_VS;
fragCode += Em ? fragMain_1_matEmis_Em : fragMain_1_matEmis;
@@ -2267,14 +2196,14 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
// Vertex shader inputs
vertCode += vertInput_PS_a_positionP;
- vertCode += vertInput_PS_a_p; //position
- vertCode += vertInput_PS_a_st; // start time
+ vertCode += vertInput_PS_a_p; //position
+ vertCode += vertInput_PS_a_st; // start time
if (rot) vertCode += vertInput_PS_a_r; //rotation as float
if (FlBoTex)
{
+ vertCode += vertInput_PS_a_texNum; // per particle texture number
vertCode += vertInput_PS_u_col;
vertCode += vertInput_PS_u_row;
- vertCode += vertInput_PS_a_texNum; // per particle texture number
}
// Vertex shader uniforms
@@ -2297,7 +2226,8 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
if (CoOvLi) vertCode += vertOutput_PS_age;
// Vertex shader main loop
- vertCode += vertMain_instanced_Begin;
+ vertCode += main_Begin;
+ vertCode += vertMain_PS_instanced_position;
vertCode += vertMain_PS_v_a;
if (FlBoTex)
vertCode += vertMain_PS_v_tC_flipbook;
@@ -2335,7 +2265,8 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
fragCode += fragInput_PS_v_tC;
if (Co && !CoOvLi) fragCode += fragInput_PS_u_c;
if (CoOvLi)
- { fragCode += fragInput_PS_u_tTL;
+ {
+ fragCode += fragInput_PS_u_tTL;
fragCode += fragInput_PS_age;
fragCode += fragInput_PS_u_colorOvLF;
}
@@ -2352,8 +2283,7 @@ void SLGLProgramGenerated::buildPerPixParticleInstanced(SLMaterial* mat)
if (CoOvLi) fragCode += fragFunction_PS_ColorOverLT;
// Fragment shader main loop
- fragCode += fragMain_PS_begin;
-
+ fragCode += main_Begin;
if (Co && !CoOvLi) fragCode += fragMain_PS_instanced_c;
@@ -2424,7 +2354,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
if (Co && CoOvLi) vertCode += vertFunction_PS_ColorOverLT;
// Vertex shader main loop
- vertCode += vertMain_Begin;
+ vertCode += main_Begin;
vertCode += vertMain_PS_v_a;
if (AlOvLi)
vertCode += vertMain_PS_v_t_begin;
@@ -2479,7 +2409,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
geomCode += geomOutput_PS_v_tC;
// geometry shader main loop
- geomCode += geomMain_PS_Begin;
+ geomCode += main_Begin;
geomCode += geomMain_PS_v_s;
if (SiOvLi) geomCode += geomMain_PS_v_sS;
geomCode += geomMain_PS_v_rad;
@@ -2519,7 +2449,7 @@ void SLGLProgramGenerated::buildPerPixParticle(SLMaterial* mat)
fragCode += fragOutputs_o_fragColor;
// Fragment shader main loop
- fragCode += fragMain_PS_begin;
+ fragCode += main_Begin;
fragCode += Co ? fragMain_PS : fragMain_PS_withoutColor;
fragCode += fragMain_PS_endAll;
@@ -2578,6 +2508,7 @@ void SLGLProgramGenerated::buildPerPixParticleUpdate(SLMaterial* mat)
if (rot) vertCode += vertConstant_PS_pi; // Add constant PI
// Vertex shader main loop
+ vertCode += main_Begin;
vertCode += vertMain_PS_U_Begin;
vertCode += vertMain_PS_U_v_init_p;
vertCode += vertMain_PS_U_v_init_v;
@@ -2605,6 +2536,8 @@ void SLGLProgramGenerated::buildPerPixParticleUpdate(SLMaterial* mat)
fragCode += shaderHeader();
// Fragment shader inputs
+ fragCode += fragOutputs_o_fragColor;
+ fragCode += main_Begin;
fragCode += fragMain_PS_TF;
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
@@ -2624,7 +2557,7 @@ void SLGLProgramGenerated::buildPerPixVideoBkgdSm(SLVLight* lights)
vertCode += vertOutput_v_P_VS;
vertCode += vertOutput_v_P_WS;
vertCode += vertOutput_v_N_VS;
- vertCode += vertMain_Begin;
+ vertCode += main_Begin;
vertCode += vertMain_v_P_VS;
vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
@@ -2656,6 +2589,7 @@ in vec3 v_N_VS; // Interpol. normal at v_P_VS in view space
fragCode += fragFunctionDoStereoSeparation;
fragCode += fragFunctionShadowTest(lights);
fragCode += fragFunctionDoColoredShadows;
+ fragCode += main_Begin;
fragCode += fragMainVideoBkgd;
fragCode += fragMain_5_FogGammaStereo;
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 7ebd30b7..22622312 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -454,7 +454,9 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node, SLuint instances)
sp->uniform1i("u_skinningEnabled", skinningEnabled);
if (skinningEnabled && !_jointMatrices.empty())
- sp->uniformMatrix4fv("u_jointMatrices", _jointMatrices.size(), (SLfloat*)&_jointMatrices[0]);
+ sp->uniformMatrix4fv("u_jointMatrices",
+ (SLsizei)_jointMatrices.size(),
+ (SLfloat*)&_jointMatrices[0]);
}
SLint locTM = sp->getUniformLocation("u_tMatrix");
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index 07bcb9a5..37d9d0e7 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -30,25 +30,17 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
SLGLTexture* texC,
const SLstring& name,
SLGLTexture* texFlipbook,
- const bool renderInstanced) : SLMesh(assetMgr, name)
+ const bool drawInstanced) : SLMesh(assetMgr, name)
{
assert(!name.empty());
// To be added to constructor
- _assetManager = assetMgr;
+ _assetManager = assetMgr;
+ _drawInstanced = SLGLState::instance()->glHasGeometryShaders() ? drawInstanced : true;
+ _primitive = PT_points;
- if (SLGLState::instance()->glHasGeometryShaders())
- {
- _renderInstanced = renderInstanced;
- }
- else
- {
- _renderInstanced = true;
- }
- _primitive = PT_points;
-
- P.push_back(SLVec3f(0, 0, 0)); // Trick SL project because it want mesh to have vertex
+ P.push_back(SLVec3f(0, 0, 0)); // Trick SL project because it wants mesh to have vertex
I32.push_back(0);
if (amount > UINT_MAX) // Need to change for number of floats
@@ -64,7 +56,6 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
_updateTime.init(60, 0.0f);
_drawTime.init(60, 0.0f);
-
}
//-----------------------------------------------------------------------------
//! Function which return a position in a sphere
@@ -176,7 +167,7 @@ SLVec3f SLParticleSystem::getPointInCone()
{
float y = 0.0f;
float radius = _shapeRadius;
- if (!_doShapeSpawnBase) // Spawn inside volume
+ if (!_doShapeSpawnBase) // Spawn inside volume
{
y = Utils::random(0.0f, _shapeHeight); // NEED TO HAVE MORE value near 1 when we have smaller base that top
radius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * y;
@@ -194,7 +185,7 @@ SLVec3f SLParticleSystem::getPointOnCone()
{
float y = 0.0f;
float radius = _shapeRadius;
- if (!_doShapeSpawnBase) // Spawn inside volume
+ if (!_doShapeSpawnBase) // Spawn inside volume
{
y = Utils::random(0.0f, _shapeHeight); // NEED TO HAVE MORE value near 1 when we have smaller base that top
radius = _shapeRadius + tan(_shapeAngle * DEG2RAD) * y;
@@ -319,7 +310,7 @@ void SLParticleSystem::generate()
SLVuint tempTexNum;
SLVVec3f tempInitP;
- if (_renderInstanced)
+ if (_drawInstanced)
_primitive = PT_triangles;
else
_primitive = PT_points;
@@ -357,7 +348,7 @@ void SLParticleSystem::generate()
{
if (_doShape && _shapeType == ST_Sphere) // Position in or on sphere
{
- if (!_doShapeSurface) // In volume
+ if (!_doShapeSurface) // In volume
tempP[i] = getPointInSphere(_shapeRadius,
SLVec3f(distribution(generator),
distribution(generator),
@@ -386,19 +377,19 @@ void SLParticleSystem::generate()
else // Position is not a volume, spawn from start point (particle emitter position)
tempP[i] = SLVec3f(0, 0, 0);
- if (!_doDirectionSpeed) // Use normal velocity
+ if (!_doDirectionSpeed) // Use normal velocity
{
- if (_velocityType == 0) // Random value
+ if (_velocityType == 0) // Random value
{
tempV[i].x = Utils::random(_velocityRndMin.x, _velocityRndMax.x); // Random value for x velocity
tempV[i].y = Utils::random(_velocityRndMin.y, _velocityRndMax.y); // Random value for y velocity
tempV[i].z = Utils::random(_velocityRndMin.z, _velocityRndMax.z); // Random value for z velocity
}
- else if (_velocityType == 1) // Constant
+ else if (_velocityType == 1) // Constant
{
- tempV[i].x = _velocityConst.x; // Constant value for x velocity
- tempV[i].y = _velocityConst.y; // Constant value for y velocity
- tempV[i].z = _velocityConst.z; // Constant value for z velocity
+ tempV[i].x = _velocityConst.x; // Constant value for x velocity
+ tempV[i].y = _velocityConst.y; // Constant value for y velocity
+ tempV[i].z = _velocityConst.z; // Constant value for z velocity
}
}
else // DO direction and speed
@@ -427,16 +418,16 @@ void SLParticleSystem::generate()
// When the first particle dies the last one begin to live
tempST[i] = GlobalTimer::timeS() + ((float)i * (_timeToLive / (float)_amount)); // Time to start
- if (_doAcceleration || _doGravity) // Acceleration
+ if (_doAcceleration || _doGravity) // Acceleration
tempInitV[i] = tempV[i];
- if (_doRotation) // Rotation (constant angular velocity)
- tempR[i] = Utils::random(0.0f * DEG2RAD, 360.0f * DEG2RAD); // Start rotation of the particle
- if (_doRotation && _doRotRange) // Random angular velocity for each particle
+ if (_doRotation) // Rotation (constant angular velocity)
+ tempR[i] = Utils::random(0.0f * DEG2RAD, 360.0f * DEG2RAD); // Start rotation of the particle
+ if (_doRotation && _doRotRange) // Random angular velocity for each particle
tempAngulareVelo[i] = Utils::random(_angularVelocityRange.x * DEG2RAD,
- _angularVelocityRange.y * DEG2RAD); // Start rotation of the particle
- if (_doFlipBookTexture) // Flipbook texture
+ _angularVelocityRange.y * DEG2RAD); // Start rotation of the particle
+ if (_doFlipBookTexture) // Flipbook texture
tempTexNum[i] = Utils::random(0, _flipbookRows * _flipbookColumns - 1);
- if (_doShape) // Shape feature
+ if (_doShape) // Shape feature
tempInitP[i] = tempP[i];
}
@@ -477,7 +468,7 @@ void SLParticleSystem::generate()
_vao2.setAttrib(AT_initialPosition, AT_initialPosition, &tempInitP);
_vao2.generateTF((SLuint)tempP.size());
- if (_renderInstanced)
+ if (_drawInstanced)
{
P.clear();
I32.clear();
@@ -494,7 +485,6 @@ void SLParticleSystem::generate()
I32.push_back(3);
I32.push_back(0);
-
_renderVao1.deleteGL();
_renderVao2.deleteGL();
/* Generate vao for rendering with draw instanced */
@@ -600,9 +590,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
// Generate programs
////////////////////
if (!_mat->program() || !_mat->programTF())
- {
- _mat->generateProgramPS(_renderInstanced);
- }
+ _mat->generateProgramPS(_drawInstanced);
////////////////////////////////////////////////
// Calculate time and paused and frustum culling
@@ -621,17 +609,17 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
_notVisibleTimeS = 0.0f; // No more culling, the difference time has been applied, no further need
_lastTimeBeforePauseS = 0.0f; // No more paused, the difference time has been applied, no further need
}
- else if (!_isVisibleInFrustum) // If particle system was not visible, this one is called just once when the particle is draw again (Do nothing if paused, because update call is not done)
+ else if (!_isVisibleInFrustum) // If particle system was not visible, this one is called just once when the particle is draw again (Do nothing if paused, because update call is not done)
{
_isVisibleInFrustum = true;
difTime = GlobalTimer::timeS() - _notVisibleTimeS; // Use time since the particle system was not visible
// maybe add later average delta time (because maybe bug when fast not visible long time, visible, not visible, visible
- deltaTime = _deltaTimeUpdateS; // Last delta time, because when culled draw is not called therefore the actual delta time will be too big
- if (_lastTimeBeforePauseS > _notVisibleTimeS) // If was paused when not visible. Need to take _notVisibleTimeS because it's since this value that the particle system is not drew.
- _lastTimeBeforePauseS = _notVisibleTimeS; // Get the value of since the particle system is not drew
- _notVisibleTimeS = 0.0f; // No more culling, the difference time has been applied, no further need
+ deltaTime = _deltaTimeUpdateS; // Last delta time, because when culled draw is not called therefore the actual delta time will be too big
+ if (_lastTimeBeforePauseS > _notVisibleTimeS) // If was paused when not visible. Need to take _notVisibleTimeS because it's since this value that the particle system is not drew.
+ _lastTimeBeforePauseS = _notVisibleTimeS; // Get the value of since the particle system is not drew
+ _notVisibleTimeS = 0.0f; // No more culling, the difference time has been applied, no further need
}
- else if (!_isPaused && _lastTimeBeforePauseS != 0.0f) // If particle system was resumed
+ else if (!_isPaused && _lastTimeBeforePauseS != 0.0f) // If particle system was resumed
{
difTime = GlobalTimer::timeS() - _lastTimeBeforePauseS; // Use time since the particle system was paused
_lastTimeBeforePauseS = 0.0f; // No more paused, the difference time has been applied, no further need
@@ -726,7 +714,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
_vao1.beginTF(_vao2.tfoID());
_vao1.drawArrayAs(PT_points);
_vao1.endTF();
- if (_renderInstanced)
+ if (_drawInstanced)
_vao = _renderVao1;
else
_vao = _vao2;
@@ -736,7 +724,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
_vao2.beginTF(_vao1.tfoID());
_vao2.drawArrayAs(PT_points);
_vao2.endTF();
- if (_renderInstanced)
+ if (_drawInstanced)
_vao = _renderVao2;
else
_vao = _vao1;
@@ -888,8 +876,8 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
stateGL->blendFunc(GL_SRC_ALPHA, GL_ONE);
///////////////////////
- if (_renderInstanced)
- SLMesh::draw(sv, node, 2*_amount); //2 triangles per particle
+ if (_drawInstanced)
+ SLMesh::draw(sv, node, 2 * _amount); //2 triangles per particle
else
SLMesh::draw(sv, node);
///////////////////////
@@ -904,7 +892,6 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
_drawBuf = 1 - _drawBuf;
}
-
/*!
Change the current use texture, this will switch between the normal texture and
the flipbook texture (and vice versa)
@@ -923,7 +910,6 @@ void SLParticleSystem::changeTexture()
}
}
-
//-----------------------------------------------------------------------------
//! deleteData deletes all mesh data and VAOs
void SLParticleSystem::deleteData()
@@ -996,7 +982,7 @@ void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
minP = SLVec3f(-radius, -0.0, -radius);
if (!_doShapeSpawnBase) // Spawn inside volume
maxP = SLVec3f(radius, _shapeHeight, radius);
- else // Spawn base volume
+ else // Spawn base volume
maxP = SLVec3f(radius, 0.0f, radius);
if (_doDirectionSpeed && _doShapeOverride)
{
@@ -1012,7 +998,7 @@ void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
minP = SLVec3f(-radius, -0.0, -radius);
if (!_doShapeSpawnBase) // Spawn inside volume
maxP = SLVec3f(radius, _shapeHeight, radius);
- else // Spawn base volume
+ else // Spawn base volume
maxP = SLVec3f(radius, 0.0f, radius);
if (_doDirectionSpeed && _doShapeOverride)
@@ -1027,7 +1013,7 @@ void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
if (_doAcceleration || _doGravity) // If acceleration or gravity is enabled
{
- if (!_doDirectionSpeed) // If direction is not enable
+ if (!_doDirectionSpeed) // If direction is not enable
{
if (_velocityType == 0)
{
@@ -1101,13 +1087,13 @@ void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
maxP.x -= maxV.x * (_timeToLive + timeForXGrav); // I remove the position with the velocity that it will not do because it go against the velocity (becareful! here timeForXGrav is negative)
else if (timeForXGrav > 0.0f) // If the gravity go with the velocity
maxP.x += 0.5f * _gravity.x * (_timeToLive * _timeToLive);
- if (timeForYGrav < 0.0f) // If the gravity go against the velocity
+ if (timeForYGrav < 0.0f) // If the gravity go against the velocity
maxP.y -= maxV.y * (_timeToLive + timeForYGrav);
- else if (timeForYGrav > 0.0f) // If the gravity go with the velocity
+ else if (timeForYGrav > 0.0f) // If the gravity go with the velocity
maxP.y += 0.5f * _gravity.y * (_timeToLive * _timeToLive);
- if (timeForZGrav < 0.0f) // If the gravity go against the velocity
+ if (timeForZGrav < 0.0f) // If the gravity go against the velocity
maxP.z -= maxV.z * (_timeToLive + timeForZGrav);
- else if (timeForZGrav > 0.0f) // If the gravity go with the velocity
+ else if (timeForZGrav > 0.0f) // If the gravity go with the velocity
maxP.z += 0.5f * _gravity.z * (_timeToLive * _timeToLive);
// Time remaining after the gravity has nullified the velocity for the particle to die (for each axes)
@@ -1124,11 +1110,11 @@ void SLParticleSystem::buildAABB(SLAABBox& aabb, const SLMat4f& wmNode)
}
// ACCELERATION (Need to rework to work like gravity)
- if (_doAcceleration && _doAccDiffDir) // Need to be rework ( for negative value)
+ if (_doAcceleration && _doAccDiffDir) // Need to be rework ( for negative value)
{
maxP += 0.5f * _acceleration * (_timeToLive * _timeToLive); // Apply acceleration after time
}
- else if (_doAcceleration && !_doAccDiffDir) // Need to be rework
+ else if (_doAcceleration && !_doAccDiffDir) // Need to be rework
{
// minP += 0.5f * _accelerationConst * (_timeToLive * _timeToLive); //Apply constant acceleration
maxP += 0.5f * _accelerationConst * maxV * (_timeToLive * _timeToLive); // Apply constant acceleration //Not good
diff --git a/modules/sl/source/mesh/SLParticleSystem.h b/modules/sl/source/mesh/SLParticleSystem.h
index 17fcb340..fceffcc2 100644
--- a/modules/sl/source/mesh/SLParticleSystem.h
+++ b/modules/sl/source/mesh/SLParticleSystem.h
@@ -24,7 +24,9 @@
* particle vertex and orient them as a billboard to the viewer. Geometry
* shaders are only supported under OpenGL >= 4.0 and OpenGL ES >= 3.2. This is
* the case on most desktop systems and on Android SDK > 24 but not on iOS which
- * has only OpenGL ES 3.0.\n.
+ * has only OpenGL ES 3.0\n.
+ * For all systems that don't support geometry shaders we use an alternative
+ * with instanced drawing\n.
* The particle system supports many options of which many can be turned on the
* do* methods. All options can also be modified in the UI when the mesh is
* selected. See the different demo scenes in the app_demo_slproject under the
@@ -39,9 +41,9 @@ class SLParticleSystem : public SLMesh
const SLVec3f& velocityRandomEnd,
const SLfloat& timeToLive,
SLGLTexture* texC,
- const SLstring& name = "Particle system",
- SLGLTexture* texFlipbook = nullptr,
- const bool renderInstanced = false);
+ const SLstring& name = "Particle system",
+ SLGLTexture* texFlipbook = nullptr,
+ const bool drawInstanced = false);
void draw(SLSceneView* sv, SLNode* node, SLuint instances = 1);
void deleteData();
@@ -55,10 +57,9 @@ class SLParticleSystem : public SLMesh
void pauseOrResume();
void calcNormals() { N.push_back(SLVec3f(0, 1, 0)); };
-
// Getters
- SLbool renderInstanced() { return _renderInstanced; }
+ SLbool drawInstanced() { return _drawInstanced; }
SLVec3f acceleration() { return _acceleration; }
SLfloat accelerationConst() { return _accelerationConst; }
SLint amount() { return _amount; }
@@ -122,7 +123,7 @@ class SLParticleSystem : public SLMesh
SLVec3f velocityRndMax() { return _velocityRndMax; }
// Setters
- void drawInstanced(bool instanced) {_renderInstanced = instanced; }
+ void drawInstanced(bool instanced) { _drawInstanced = instanced; }
void amount(SLint i) { _amount = i; }
void accConst(SLfloat f) { _accelerationConst = f; }
void acceleration(SLVec3f v) { _acceleration = v; }
@@ -273,8 +274,8 @@ class SLParticleSystem : public SLMesh
SLVec3f getPointOnPyramid();
SLVec3f getDirectionPyramid(SLVec3f position);
- // Use to recreate material (the shader change depending if the PS is instanced or not)
- SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
+ // Used to recreate material (the shader changes depending on if the PS is instanced or not)
+ SLAssetManager* _assetManager; //!< pointer to the asset manager (the owner) if available
// Core values
SLint _amount; //!< Amount of a particle
@@ -389,7 +390,7 @@ class SLParticleSystem : public SLMesh
SLbool _doSizeOverLT = true; //!< Boolean for size over life time
SLbool _doSizeOverLTCurve = false; //!< Boolean for size over life time curve
SLbool _doFlipBookTexture = false; //!< Boolean for flipbook texture
- SLbool _renderInstanced = false; //!< Boolean for instanced rendering
+ SLbool _drawInstanced = false; //!< Boolean for instanced rendering
};
//-----------------------------------------------------------------------------
#endif
diff --git a/modules/utils/externals/CMakeLists.txt b/modules/utils/externals/CMakeLists.txt
index 787d8344..a0cac534 100644
--- a/modules/utils/externals/CMakeLists.txt
+++ b/modules/utils/externals/CMakeLists.txt
@@ -1,5 +1,47 @@
if (NOT "${SYSTEM_NAME_UPPER}" STREQUAL "IOS" AND NOT "${SYSTEM_NAME_UPPER}" STREQUAL "EMSCRIPTEN")
add_subdirectory(zlib)
+
+ set(DEFAULT_COMPILE_OPTIONS ${DEFAULT_COMPILE_OPTIONS}
+ -Wno-c++98-compat
+ -Wno-c++98-compat-pedantic
+ -Wno-covered-switch-default
+ -Wno-double-promotion
+ -Wno-exit-time-destructors
+ -Wno-global-constructors
+ -Wno-gnu-zero-variadic-macro-arguments
+ -Wno-documentation
+ -Wno-missing-variable-declarations
+ -Wno-newline-eof
+ -Wno-old-style-cast
+ -Wno-switch-enum
+ -Wno-unused-but-set-variable
+ -Wno-unused-command-line-argument
+ -Wno-unused-function
+ -Wno-unused-macros
+ -Wno-unused-parameter
+ -Wno-unused-private-field
+ -Wno-unused-variable
+ -Wno-unused-value
+ -Wno-used-but-marked-unused
+ -Wno-extra-tokens
+ -Wno-reorder
+ -Wno-switch
+ -Wno-char-subscripts
+ -Wno-injected-class-name
+ -Wno-format-security
+ -Wno-invalid-noreturn
+
+ $<$:
+ >
+
+ $<$:
+
+ >
+
+ $<$:
+ -pthread
+ >
+ )
endif ()
if (NOT "${SYSTEM_NAME_UPPER}" STREQUAL "EMSCRIPTEN")
From 775a5d9f5d14a718d3deb01dffe95ca8f4d078ac Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Thu, 7 Dec 2023 14:31:42 +0100
Subject: [PATCH 070/108] Updated release key for android
---
apps/app_demo_slproject/android/app/build.gradle | 5 +++--
.../android/cpvrlab-release-key | Bin 2180 -> 0 bytes
.../android/slproject-release-key | Bin 0 -> 2742 bytes
3 files changed, 3 insertions(+), 2 deletions(-)
delete mode 100644 apps/app_demo_slproject/android/cpvrlab-release-key
create mode 100644 apps/app_demo_slproject/android/slproject-release-key
diff --git a/apps/app_demo_slproject/android/app/build.gradle b/apps/app_demo_slproject/android/app/build.gradle
index a3faacfa..222d75e5 100644
--- a/apps/app_demo_slproject/android/app/build.gradle
+++ b/apps/app_demo_slproject/android/app/build.gradle
@@ -2,10 +2,11 @@ apply plugin: 'com.android.application'
android {
signingConfigs {
+ // Please create your own release key with Build > Generate Signed Bundle or APK
release {
- keyAlias 'cpvrlab'
+ keyAlias 'slproject-release-key'
keyPassword '?' // Change to your key password
- storeFile file('../cpvrlab-release-key')
+ storeFile file('../slproject-release-key')
storePassword '?' // Change to your store password
}
}
diff --git a/apps/app_demo_slproject/android/cpvrlab-release-key b/apps/app_demo_slproject/android/cpvrlab-release-key
deleted file mode 100644
index cfbb91e66ef2a23a53ac19d900a7fa264555e1e7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2180
zcmb`H=U0=75{L69A(Rk6g0d*tASD91LP8)I0s_(%g&?3PPK-@Nr?{2XZ#F&N;={Y-f2?o2;F)LXu2vsguNe)aYAn9Ah6%-!!?
z){H-@DpdWoo0!?a?tqcbk7S+y1c2xus--AJBRwcPk!MdH7LFODIXWP>G#hFZ`!5ru
zr0*f`pn
zl<51ofB(V8djjm(=jLW~d$B@z;SPB$Y!O
z*uqi=?@_rWlHtuMGd_JT_3JwUIo-U}2?2&VAxMdaqXL!nk+qVb{-cnsH^rVQ8B{>)_{RORe{+^yU+sBpOtE
zppxo%;lZFKv$0=B^yHNfN67MlpHn{Hzds`$%QpNu+(=1Z!g4M@>Q}S}^TMZ{V)?Vy
z!JAL@)`S>tWacqjx|eARIa_m*lRkegU3yF0ZrJ=cZgdM`dwyH}9Gy+lPjnzU$y-d1
z#GgD;-f>FfJ#0wEc5Wf=F1k9vGEa4^s2~=`%FzMOHl-*e%eUah)(dz2GQ031VA@0R
zB8SkxPP4eq;FUa9;;jAiP|pabvW8!eOQeOACkY!MtQI6)$<4QU9vkjv^lYpPPe3a6
zBZjTl7@bfEZ!?=1xm2l=%yc}FGLX(2nz};_Yn(GUN3%w2!JN`Vy;(e
z_R()}a!>|LRg^w0u?0*?awHmlooyzCV~v7W8Q>
zQY*fiG#p;;E$9O4#Ca3#?zxe{tPzrUEwm`6IHR`LO){#H}CjY&f()guJ)oL
zWh!-RjL=s$@QUS}UXc&m-SW&a@0Gfod<&SBjMT)~%lhWm|yidx<*nhi`&t63X
zM*@K$Bpef>fn$PExezb_21C#45j}ATn4of$Y1AeH0N{Ke+&MfPCkTVsKw(I*fhit=
zgZ~8rNaz`AP{2RPe}Gr0et2P=&|h64B;<^-DPHVAwg&`9{v%`D&yooIDV#c96R$=f
zsF55c5$c2k#QzWfzr&b-?7x>ekUfM6h=OoTKnTnP08qRKQPUkII+K{i&~06eG1w8&
zH9w3rhZBv^q=NZYOidE!l3UW+Y=Hb&J#|Lgg(OtFsXukr0j*Xbi&0#2On_|A^?J$u#m!geb(M}mGAu*FE8{&WV7t|OtRXfSd$OD
zBwJ1)zYSadNKTk?7iit;y7@@QD6*OFwwJ~C7-J2SNTI@d@4z@_OxL^Ei(7>HsG!6_
z2v2W(UXc90;DaEi%{5{z7fzGqRg1-SJ}&w4yMo*2hQ?M%oXg91oZgPru2g@QFM|}~
z?6AS_qq-9!6K{W7acL{>uu$|TK3%d3s2Xu83TCBuQBYFv=%nEF0LzA>J}=8k_8Fz}
z7H>LlJzTus7?k}H>&2ww|C?T9yl=LGEWlfhPjpn*UAux=l`U51cr~RcnpCej5XrC-
rt$JPA?iQoAL+LsEe8s-4XKWpy&T`wwDw)?DotlH$$ommI%H-6aQGC8c
diff --git a/apps/app_demo_slproject/android/slproject-release-key b/apps/app_demo_slproject/android/slproject-release-key
new file mode 100644
index 0000000000000000000000000000000000000000..79046abc33513406a59a691391093960f46d0bcc
GIT binary patch
literal 2742
zcma);X*d+@9>!Dy6^jcKOcYBgC)Z&K|nB;40nLB$wcc%Z*Txv
zfVpJ2F@y{^IJ9-JWay{=ilDC{WN7`NU43{eVC?^C9f1Quxn!uup{a^>`_q7OU@u__
z|Hva)SqPH#5v@z1le;_#IcJCV=@ojeb5alllH>*fMX*O;tp9!y#0CXm1z~JgqV<79
zFa#(A;Z~Iy*mb2U{i@bJj^dsfvxbl%pDnZPHQ6!I1*k-XS|ZBaNavXb9;9B;&!nfX
zNnaH0HfBNEq!X5ZN3^oLZn`^V1@f(<+C+Y6Y&7Kfad_r+e;>CybKS?btLyEE^ns8S
zGfi;zn-+P;Jq-Vgr`A>O%(nAd#ESr!4vJvN8}P!BV5!(^CV;12yrNMMe7irxOhAyT
zBq_bjxdwG6wktg2>k8HC&vF$i1k<|Lr(M5N)K04(TW_q{d^?I^!S(%42))7?cj49*+S6IgP6$YQIDO3iNBB&fLm+YsUADI1)(Fl{
zGfLfKV|}d5K;bL3SGhKjPW|iR?&iHuQj5ozmms=>`d%bDCTEKu@Ut4z@`6uX}EY==)8xf3d^ceI~ar%hAJ>
zrM{Ar^-5Ta1(kRQxbDI$w})a@!{p9LoHdXDBg#MTKT4pLN^RyMLO37X{A+p0t0#Rb
zKDfFeJ>S=hpRc_ww1Z#xo{NIEmt9abemI+QEmxxEROk8Mlv)
zpExdsB+=}p+h54z$`X2vS0GbcdC7@lgQ+fS%9%$+SM13;GgpizKdcXYJ!|S$TijlA
zlcd)4Q7S`5t5210spZ$z^!@2M)0M)&Qw?ICE~ho@s5G(G-rm4ld;}w!RW_{3fZ|46
z33!>A@&-F0P%yr3AlE_d+lfZli_|V5#!^D)?&s^mkv-QFgCSeIdt+4700Z5O{Mv#1
z*9?TWOx<(sm4uUfQKya*eryX_?#*kWcT{)>G?U_VRm{3vK2=&3R8|U?SV26p_v5GX
z%@{eQU#vE{dc|I&HKR=gKb*0sF5=?rL5d!K5+yy}V$ZX=y1@CcVycfwHH6g;p{}ku
zi^#47-7k#3b#P(>^Pz$_DEMn4<9l0qUW8Ze*JQ6Ts<@(Fdc54&uLFjNP>Q3p;P7M)M%
z_7YGEUZGc2vo%LQ{`#dmD&>7g%1SI)OHy)}U;X5qu4-|P%Tp!Wto#K;h_!JGYRvCg
zmh$EOXD=_*$EzJ(oJk$u+%J0?>LW=4>#z4P*!U9Y0P`~VD$i}kHB>g?Mzgr@;3rc~
z&NDhVuKs*;+t))oH{JXbAIc{!t@(3?zdDBdX>B^7YsM%Od(d?1_xC`5srsl)vCcx5
z=b4C!s*i+(&Lu@BtnwdRvLO{QLNWk6C
zFoB$)mTNVG9d*L8++ipn&Q>`zPe8!^4L{WA{_cR!#JL$BrO%(!a$FRSwdD&-%{?th
z63U9?uvI?MNH;Nmtp^^Z_~%I$S=fO`XIoZ10G{_a0;QyWBI85Fvaau|ZQ_yrRlDJA
zXOHswXH+#@{k9=3<)>DlyO(Y|H7U=yN#SwYKs{G}pMz7BIoehzm;CZcWth+|9%=ok
z*Sm2eX3;9m?Zs~F>2U_DIh}e+#2G4LbH8-CBa`;?$qQ$C=;(LTut)GP_3+@5!28dh
zhrOGIC3ZexZfsEp)!Pl;>RI;{l3QkyO*=eCL~$7rVT16T-jT_9Zv36PMcCYt+n0Hg
zMJB~d74-WYlaMa@;mwIrAS(*H1B}`m7>8H+IoRjwG#Z1eV(j05Rj2NfMko7Yd7{4K
z9OY=f?0(`k+(S(Pj_2jIv4+3~tIFU9PUe1~Z2tK>QNK>2OOfoSIkBC1(y~ESiXrR*
znN(s{EYC8cSC#Al^D!%jm(w%+orM!F95e=nyY1v!-cEm(8)LzQmEZq=~5yk~B2$
z8{&0;wCF~nS%Vd!;nk^}d=nYZok5o3BZy=ka`1xDPd=sWVCUWjq8hskDU}PPS78#>8u|ZeNSvc1SE($tlnb9kI~bOApB2syPvvI=`llnEJkuFEcvUL`(=*kI`D{zsIA-s4W{i!VtAzHbMY~ABU)bA+xvH(Y8C%P
zbn9;&+$O4jWC1L#Zm;3>uC0rsjXatw37?PC3&^4j<8JRzrXKFBYkFp6!ed*R_Br@M
zWbU2#z#4ux&+|WGqKWK=5Nn?(oEo^Hd7K7B#0-n8Q}$1JpASj|J5@Nq0Nb7_n*`5Zv=2bz-
QAoEQzcip~
Date: Thu, 7 Dec 2023 14:59:50 +0100
Subject: [PATCH 071/108] Update SLGLProgramGenerated.cpp
---
modules/sl/source/gl/SLGLProgramGenerated.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index b86f0973..b93846da 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -203,7 +203,7 @@ out float tf_rotation; // To transform feedback)";
const string vertOutput_PS_tf_r_angularVelo = R"(
out float tf_angularVelo; // To transform feedback)";
const string vertOutput_PS_tf_texNum = R"(
-out uint tf_texNum; // To transform feedback)";
+flat out uint tf_texNum; // To transform feedback)";
const string vertOutput_PS_tf_initP = R"(
out vec3 tf_initialPosition; // To transform feedback)";
From 8b8695daa9de99cb7b99bb27c3c10de663e801f7 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Fri, 8 Dec 2023 17:29:14 +0100
Subject: [PATCH 072/108] Fixed supportGPUSkinning problem
I removed mat->supportsGPUSkinning and replaced it by passing this information at the shader creation moment in SLMesh::draw when the material gets activated
---
modules/sl/source/SLMaterial.cpp | 17 ++++--
modules/sl/source/SLMaterial.h | 8 +--
modules/sl/source/gl/SLGLProgramGenerated.cpp | 53 ++++++++++---------
modules/sl/source/gl/SLGLProgramGenerated.h | 17 +++---
modules/sl/source/input/SLAssimpImporter.cpp | 13 +++--
modules/sl/source/mesh/SLMesh.cpp | 40 +++++++-------
modules/sl/source/node/SLNode.cpp | 8 +--
7 files changed, 85 insertions(+), 71 deletions(-)
diff --git a/modules/sl/source/SLMaterial.cpp b/modules/sl/source/SLMaterial.cpp
index 25674510..283a95ed 100644
--- a/modules/sl/source/SLMaterial.cpp
+++ b/modules/sl/source/SLMaterial.cpp
@@ -502,9 +502,11 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
At the end the shader program will begin its usage with SLGLProgram::beginUse.
@param cam Pointer to the active camera
@param lights Pointer to the scene vector of lights
- @param skybox Pointer to the skybox
+ @param supportsSkinning flag if skinning in shader should be supported
*/
-void SLMaterial::activate(SLCamera* cam, SLVLight* lights, SLSkybox* skybox)
+void SLMaterial::activate(SLCamera* cam,
+ SLVLight* lights,
+ SLbool supportGPUSkinning)
{
SLGLState* stateGL = SLGLState::instance();
@@ -525,12 +527,19 @@ void SLMaterial::activate(SLCamera* cam, SLVLight* lights, SLSkybox* skybox)
{
// Check first the asset manager if the requested program type already exists
string programName;
- SLGLProgramGenerated::buildProgramName(this, lights, programName);
+ SLGLProgramGenerated::buildProgramName(this,
+ lights,
+ supportGPUSkinning,
+ programName);
_program = _assetManager->getProgramByName(programName);
// If the program was not found by name generate a new one
if (!_program)
- _program = new SLGLProgramGenerated(_assetManager, programName, this, lights);
+ _program = new SLGLProgramGenerated(_assetManager,
+ programName,
+ this,
+ lights,
+ supportGPUSkinning);
}
// Check if shader had a compile error and the error texture should be shown
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index d1f4cf90..a1a55fc3 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -109,12 +109,9 @@ class SLMaterial : public SLObject
~SLMaterial() override;
void generateProgramPS(bool renderInstanced = false);
- void activate(SLCamera* cam,
- SLVLight* lights,
- SLSkybox* skybox = nullptr);
+ void activate(SLCamera* cam, SLVLight* lights, SLbool supportGPUSkinning);
SLint passToUniforms(SLGLProgram* program, SLint nextTexUnit);
-
void deleteDataGpu();
//! Returns true if there is any transparency in diffuse alpha or textures
@@ -201,7 +198,6 @@ class SLMaterial : public SLObject
void program(SLGLProgram* sp) { _program = sp; }
void programTF(SLGLProgram* sp) { _programTF = sp; }
void skybox(SLSkybox* sb) { _skybox = sb; }
- void supportsGPUSkinning(SLbool supportsGPUSkinning) { _supportsGPUSkinning = supportsGPUSkinning; }
void ps(SLParticleSystem* ps) { _ps = ps; }
// Getters
@@ -224,7 +220,6 @@ class SLMaterial : public SLObject
SLGLProgram* program() { return _program; }
SLGLProgram* programTF() { return _programTF; }
SLSkybox* skybox() { return _skybox; }
- SLbool supportsGPUSkinning() { return _supportsGPUSkinning; }
SLParticleSystem* ps() { return _ps; }
SLVNode& nodesVisible2D() { return _nodesVisible2D; }
SLVNode& nodesVisible3D() { return _nodesVisible3D; }
@@ -255,7 +250,6 @@ class SLMaterial : public SLObject
SLGLProgram* _programTF{}; //!< pointer to a GLSL shader program for transformFeedback
SLint _numTextures; //!< number of textures in all _textures vectors array
SLSkybox* _skybox; //!< pointer to the skybox
- bool _supportsGPUSkinning = false; //!< whether skinning is performed on the GPU or on the CPU
// For particle system
SLParticleSystem* _ps; //!< pointer to a particle system
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index b93846da..bb0cc546 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -1715,10 +1715,12 @@ const string fragMainVideoBkgd = R"(
*/
void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
SLVLight* lights,
+ SLbool supportGPUSkinning,
string& programName)
{
assert(mat && "No material pointer passed!");
assert(lights && !lights->empty() && "No lights passed!");
+
programName = "gen";
if (mat->hasTextureType(TT_videoBkgd))
@@ -1744,14 +1746,14 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
programName += "D"; // Directional light
}
else if (light->spotCutOffDEG() < 180.0f)
- programName += "S"; // Spot light
+ programName += "S"; // Spotlight
else
- programName += "P"; // Point light
+ programName += "P"; // Pointlight
if (light->createsShadows())
programName += "s"; // Creates shadows
}
- if (mat->supportsGPUSkinning())
+ if (supportGPUSkinning)
programName += "-S";
}
//-----------------------------------------------------------------------------
@@ -1851,7 +1853,8 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
* @param lights Pointer of vector of lights
*/
void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
- SLVLight* lights)
+ SLVLight* lights,
+ SLbool supportGPUSkinning)
{
if (mat->name() == "IBLMat")
{
@@ -1876,11 +1879,11 @@ void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
if (mat->reflectionModel() == RM_BlinnPhong)
{
- buildPerPixBlinn(mat, lights);
+ buildPerPixBlinn(mat, lights, supportGPUSkinning);
}
else if (mat->reflectionModel() == RM_CookTorrance)
{
- buildPerPixCook(mat, lights);
+ buildPerPixCook(mat, lights, supportGPUSkinning);
}
else if (mat->reflectionModel() == RM_Custom)
{
@@ -1925,7 +1928,9 @@ void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat,
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
-void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
+void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat,
+ SLVLight* lights,
+ SLbool supportGPUSkinning)
{
assert(mat && lights);
assert(_shaders.size() > 1 &&
@@ -1948,9 +1953,6 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
bool uv1 = mat->usesUVIndex(1);
bool sky = mat->skybox() != nullptr;
- // Check if the shader has to support skinning
- bool skinning = mat->supportsGPUSkinning();
-
// Assemble vertex shader code
string vertCode;
vertCode += shaderHeader((int)lights->size());
@@ -1959,11 +1961,11 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
vertCode += vertInput_a_pn;
if (uv0) vertCode += vertInput_a_uv0;
if (Nm) vertCode += vertInput_a_tangent;
- if (skinning) vertCode += vertInput_a_skinning;
+ if (supportGPUSkinning) vertCode += vertInput_a_skinning;
vertCode += vertInput_u_matrices_all;
// if (sky) vertCode += vertInput_u_matrix_invMv;
if (Nm) vertCode += vertInput_u_lightNm;
- if (skinning) vertCode += vertInput_u_skinning;
+ if (supportGPUSkinning) vertCode += vertInput_u_skinning;
// Vertex shader outputs
vertCode += vertOutput_v_P_VS;
@@ -1975,7 +1977,7 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
// Vertex shader main loop
vertCode += main_Begin;
- if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
+ if (supportGPUSkinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
@@ -1985,9 +1987,9 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
vertCode += vertMain_EndAll;
// Vertex shader variables
- setVariable(vertCode, "localPosition", skinning ? "skinnedPosition" : "a_position");
- setVariable(vertCode, "localNormal", skinning ? "skinnedNormal" : "a_normal");
- if (Nm) setVariable(vertCode, "localTangent", skinning ? "skinnedTangent" : "a_tangent");
+ setVariable(vertCode, "localPosition", supportGPUSkinning ? "skinnedPosition" : "a_position");
+ setVariable(vertCode, "localNormal", supportGPUSkinning ? "skinnedNormal" : "a_normal");
+ if (Nm) setVariable(vertCode, "localTangent", supportGPUSkinning ? "skinnedTangent" : "a_tangent");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
@@ -2055,7 +2057,9 @@ void SLGLProgramGenerated::buildPerPixCook(SLMaterial* mat, SLVLight* lights)
addCodeToShader(_shaders[1], fragCode, _name + ".frag");
}
//-----------------------------------------------------------------------------
-void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
+void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat,
+ SLVLight* lights,
+ SLbool supportGPUSkinning)
{
assert(mat && lights);
assert(_shaders.size() > 1 &&
@@ -2073,9 +2077,6 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
bool uv0 = mat->usesUVIndex(0);
bool uv1 = mat->usesUVIndex(1);
- // Check if the shader has to support skinning
- bool skinning = mat->supportsGPUSkinning();
-
// Assemble vertex shader code
string vertCode;
vertCode += shaderHeader((int)lights->size());
@@ -2085,10 +2086,10 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
if (uv0) vertCode += vertInput_a_uv0;
if (uv1) vertCode += vertInput_a_uv1;
if (Nm) vertCode += vertInput_a_tangent;
- if (skinning) vertCode += vertInput_a_skinning;
+ if (supportGPUSkinning) vertCode += vertInput_a_skinning;
vertCode += vertInput_u_matrices_all;
if (Nm) vertCode += vertInput_u_lightNm;
- if (skinning) vertCode += vertInput_u_skinning;
+ if (supportGPUSkinning) vertCode += vertInput_u_skinning;
// Vertex shader outputs
vertCode += vertOutput_v_P_VS;
@@ -2100,7 +2101,7 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
// Vertex shader main loop
vertCode += main_Begin;
- if (skinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
+ if (supportGPUSkinning) vertCode += Nm ? vertMain_skinning_Nm : vertMain_skinning;
vertCode += vertMain_v_P_VS;
if (Sm) vertCode += vertMain_v_P_WS_Sm;
vertCode += vertMain_v_N_VS;
@@ -2110,9 +2111,9 @@ void SLGLProgramGenerated::buildPerPixBlinn(SLMaterial* mat, SLVLight* lights)
vertCode += vertMain_EndAll;
// Vertex shader variables
- setVariable(vertCode, "localPosition", skinning ? "skinnedPosition" : "a_position");
- setVariable(vertCode, "localNormal", skinning ? "skinnedNormal" : "a_normal");
- if (Nm) setVariable(vertCode, "localTangent", skinning ? "skinnedTangent" : "a_tangent");
+ setVariable(vertCode, "localPosition", supportGPUSkinning ? "skinnedPosition" : "a_position");
+ setVariable(vertCode, "localNormal", supportGPUSkinning ? "skinnedNormal" : "a_normal");
+ if (Nm) setVariable(vertCode, "localTangent", supportGPUSkinning ? "skinnedTangent" : "a_tangent");
addCodeToShader(_shaders[0], vertCode, _name + ".vert");
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index 39738407..48a40bd4 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -59,14 +59,15 @@ class SLGLProgramGenerated : public SLGLProgram
SLGLProgramGenerated(SLAssetManager* am,
const string& programName,
SLMaterial* mat,
- SLVLight* lights)
+ SLVLight* lights,
+ SLbool supportGPUSkinning)
: SLGLProgram(am,
"",
"",
"",
programName)
{
- buildProgramCode(mat, lights);
+ buildProgramCode(mat, lights, supportGPUSkinning);
}
//! ctor for generated shader program PS
@@ -95,23 +96,27 @@ class SLGLProgramGenerated : public SLGLProgram
static bool lightsDoShadowMapping(SLVLight* lights);
static void buildProgramName(SLMaterial* mat,
SLVLight* lights,
+ SLbool supportGPUSkinning,
string& programName);
static void buildProgramNamePS(SLMaterial* mat,
string& programName,
bool isDrawProg,
bool renderInstanced);
- void buildProgramCodePS(SLMaterial* mat, bool isDrawProg, bool renderInstanced = false);
+ void buildProgramCodePS(SLMaterial* mat,
+ bool isDrawProg,
+ bool renderInstanced = false);
void buildProgramCode(SLMaterial* mat,
- SLVLight* lights);
+ SLVLight* lights,
+ SLbool supportGPUSkinning);
void beginShader(SLCamera* cam,
SLMaterial* mat,
SLVLight* lights) override { beginUse(cam, mat, lights); }
void endShader() override { endUse(); }
private:
- void buildPerPixCook(SLMaterial* mat, SLVLight* lights);
- void buildPerPixBlinn(SLMaterial* mat, SLVLight* lights);
+ void buildPerPixCook(SLMaterial* mat, SLVLight* lights, SLbool supportGPUSkinning);
+ void buildPerPixBlinn(SLMaterial* mat, SLVLight* lights, SLbool supportGPUSkinning);
void buildPerPixParticle(SLMaterial* mat);
void buildPerPixParticleInstanced(SLMaterial* mat);
void buildPerPixParticleUpdate(SLMaterial* mat);
diff --git a/modules/sl/source/input/SLAssimpImporter.cpp b/modules/sl/source/input/SLAssimpImporter.cpp
index a05de729..0ff14f31 100644
--- a/modules/sl/source/input/SLAssimpImporter.cpp
+++ b/modules/sl/source/input/SLAssimpImporter.cpp
@@ -691,7 +691,6 @@ SLMaterial* SLAssimpImporter::loadMaterial(SLAssetManager* am,
// Create SLMaterial instance. It is also added to the SLScene::_materials vector
SLMaterial* slMat = new SLMaterial(am, name.c_str());
- slMat->supportsGPUSkinning(true);
// load all the textures for this aiMat and add it to the aiMat vector
for (int tt = aiTextureType_NONE; tt <= aiTextureType_UNKNOWN; ++tt)
@@ -841,7 +840,6 @@ SLMaterial* SLAssimpImporter::loadMaterial(SLAssetManager* am,
aiMat->Get(AI_MATKEY_OPACITY, opacity);
aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metalness);
aiMat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughness);
- aiString texRoughnessMetallic;
// increase shininess if specular color is not low.
// The aiMat will otherwise be too bright
@@ -1297,10 +1295,11 @@ SLAnimation* SLAssimpImporter::loadAnimation(SLAnimManager& animManager, aiAnima
SLuint id = 0;
SLbool isJointNode = (affectedNode == nullptr);
- // @todo: this is currently a work around but it can happen that we receive normal node animationtracks and joint animationtracks
- // we don't allow node animation tracks in a skeleton animation, so we should split an animation in two seperate
- // animations if this happens. for now we just ignore node animation tracks if we already have joint tracks
- // ofc this will crash if the first track is a node anim but its just temporary
+ // @todo: this is currently a work around but it can happen that we receive normal node animation tracks
+ // and joint animation tracks we don't allow node animation tracks in a skeleton animation, so we
+ // should split an animation in two separate animations if this happens. for now we just ignore node
+ // animation tracks if we already have joint tracks ofc this will crash if the first track is a node
+ // anim but its just temporary
if (!isJointNode && isSkeletonAnim)
continue;
@@ -1444,7 +1443,7 @@ children has a mesh. aiNode can contain only transform or joint nodes without
any visuals.
@todo this function doesn't look well optimized. It's currently used if the option to
- only load nodes containing meshes somewhere in their heirarchy is enabled.
+ only load nodes containing meshes somewhere in their hierarchy is enabled.
This means we call it on ancestor nodes first. This also means that we will
redundantly traverse the same exact nodes multiple times. This isn't a pressing
issue at the moment but should be tackled when this importer is being optimized
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 22622312..1b8c75d8 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -20,8 +20,8 @@
using std::set;
#ifdef __clang__
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Weverything"
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Weverything"
#endif
#include
#include
@@ -438,7 +438,10 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node, SLuint instances)
/////////////////////////////
// 3.a) Apply mesh material if exists & differs from current
- _mat->activate(sv->camera(), &sv->s()->lights());
+ // If a material is not created so far, it will be created here
+ _mat->activate(sv->camera(),
+ &sv->s()->lights(),
+ (!Ji.empty() && !Jw.empty()));
// 3.b) Pass the standard matrices to the shader program
SLGLProgram* sp = _mat->program();
@@ -447,14 +450,14 @@ void SLMesh::draw(SLSceneView* sv, SLNode* node, SLuint instances)
sp->uniformMatrix4fv("u_pMatrix", 1, (SLfloat*)&stateGL->projectionMatrix);
// Pass skeleton joint matrices to the shader program
- if (_mat->supportsGPUSkinning())
+ if (!Ji.empty() && !Jw.empty())
{
// Only perform skinning in the shader if we haven't performed CPU skinning and if there are joint IDs
- SLbool skinningEnabled = !_isCPUSkinned && !Ji.empty();
+ SLbool skinningEnabled = !_isCPUSkinned;
sp->uniform1i("u_skinningEnabled", skinningEnabled);
if (skinningEnabled && !_jointMatrices.empty())
- sp->uniformMatrix4fv("u_jointMatrices",
+ sp->uniformMatrix4fv("u_jointMatrices",
(SLsizei)_jointMatrices.size(),
(SLfloat*)&_jointMatrices[0]);
}
@@ -758,7 +761,7 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
SLVVec4i jointIndicesData; // indices are passed to the shader as ivec4s
SLVVec4f jointWeightsData; // weights are passed to the shader as vec4s
- if (!Ji.empty() && _mat->supportsGPUSkinning())
+ if (!Ji.empty() && !Jw.empty())
{
assert(Ji.size() == P.size());
assert(Jw.size() == P.size());
@@ -773,9 +776,9 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
assert(!curIndices.empty());
jointIndicesData[i] = SLVec4i(curIndices.size() >= 1 ? curIndices[0] : 0,
- curIndices.size() >= 2 ? curIndices[1] : 0,
- curIndices.size() >= 3 ? curIndices[2] : 0,
- curIndices.size() >= 4 ? curIndices[3] : 0);
+ curIndices.size() >= 2 ? curIndices[1] : 0,
+ curIndices.size() >= 3 ? curIndices[2] : 0,
+ curIndices.size() >= 4 ? curIndices[3] : 0);
}
// create the vec4 of weights for all points
@@ -785,9 +788,9 @@ void SLMesh::generateVAO(SLGLVertexArray& vao)
assert(curWeights.size() == Ji[i].size());
jointWeightsData[i] = SLVec4f(curWeights.size() >= 1 ? curWeights[0] : 0.0f,
- curWeights.size() >= 2 ? curWeights[1] : 0.0f,
- curWeights.size() >= 3 ? curWeights[2] : 0.0f,
- curWeights.size() >= 4 ? curWeights[3] : 0.0f);
+ curWeights.size() >= 2 ? curWeights[1] : 0.0f,
+ curWeights.size() >= 3 ? curWeights[2] : 0.0f,
+ curWeights.size() >= 4 ? curWeights[3] : 0.0f);
}
vao.setAttrib(AT_jointIndex, AT_jointIndex, &jointIndicesData);
vao.setAttrib(AT_jointWeight, AT_jointWeight, &jointWeightsData);
@@ -909,9 +912,10 @@ SLbool SLMesh::hit(SLRay* ray, SLNode* node)
return true;
}
- // Force the mesh to be skinned in software even if it would be normally skinned on the GPU.
- // We need the results from the skinning on the CPU to perform the ray-triangle intersection.
- if (_skeleton && _mat && _mat->supportsGPUSkinning() && !_isCPUSkinned)
+ // Force the mesh to be skinned in software even if it would be normally
+ // skinned on the GPU. We need the results from the skinning on the CPU to
+ // perform the ray-triangle intersection.
+ if (_skeleton && _mat && (!Ji.empty() && !Jw.empty()) && !_isCPUSkinned)
transformSkin(true, [](SLMesh*) {});
if (_accelStruct)
@@ -1599,8 +1603,8 @@ void SLMesh::transformSkin(bool forceCPUSkinning,
_isCPUSkinned = forceCPUSkinning;
// Perform software skinning if the material doesn't support CPU skinning or
- // if the results of the skinning process are required somewehere else.
- if (!_mat->supportsGPUSkinning() || forceCPUSkinning)
+ // if the results of the skinning process are required somewhere else.
+ if (forceCPUSkinning)
{
_finalP = &skinnedP;
_finalN = &skinnedN;
diff --git a/modules/sl/source/node/SLNode.cpp b/modules/sl/source/node/SLNode.cpp
index cee233cf..ad232a42 100644
--- a/modules/sl/source/node/SLNode.cpp
+++ b/modules/sl/source/node/SLNode.cpp
@@ -1106,10 +1106,12 @@ void SLNode::updateRec()
/*! Do software skinning on all changed skeletons && updateRec any out of date
acceleration structure for RT or if they're being rendered.
*/
-bool SLNode::updateMeshSkins(bool forceCPUSkinning,
- const std::function& cbInformNodes)
+bool SLNode::updateMeshSkins(bool forceCPUSkinning,
+ const function& cbInformNodes)
{
- if (drawBit(SL_DB_WITHEDGES) || drawBit(SL_DB_ONLYEDGES) || drawBit(SL_DB_VOXELS))
+ if (drawBit(SL_DB_WITHEDGES) ||
+ drawBit(SL_DB_ONLYEDGES) ||
+ drawBit(SL_DB_VOXELS))
forceCPUSkinning = true;
bool hasChanges = false;
From 997ecfb2ff414167090792b0f90735c2fc950354 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Fri, 8 Dec 2023 18:00:47 +0100
Subject: [PATCH 073/108] Cosmetics and formating
---
modules/sl/source/gl/SLGLVertexArray.cpp | 57 ++++++---
modules/sl/source/mesh/SLParticleSystem.cpp | 130 ++++++++++++++------
2 files changed, 133 insertions(+), 54 deletions(-)
diff --git a/modules/sl/source/gl/SLGLVertexArray.cpp b/modules/sl/source/gl/SLGLVertexArray.cpp
index 79e4d8c2..ec700a81 100644
--- a/modules/sl/source/gl/SLGLVertexArray.cpp
+++ b/modules/sl/source/gl/SLGLVertexArray.cpp
@@ -89,11 +89,11 @@ void SLGLVertexArray::setAttrib(SLGLAttributeType type,
}
//-----------------------------------------------------------------------------
- void SLGLVertexArray::setExternalVBO(SLGLVertexBuffer* vbo, SLuint divisor)
- {
- _externalVBOf = vbo;
+void SLGLVertexArray::setExternalVBO(SLGLVertexBuffer* vbo, SLuint divisor)
+{
+ _externalVBOf = vbo;
_externalDivisor = divisor;
- }
+}
//-----------------------------------------------------------------------------
/*! Defines the vertex indices for the element drawing. Without indices vertex
@@ -419,9 +419,13 @@ void SLGLVertexArray::drawElementsAs(SLGLPrimitiveType primitiveType,
GET_GL_ERROR;
}
//-----------------------------------------------------------------------------
-/*! Draws the vertex attributes as a specified primitive type as the vertices
-are defined in the attribute arrays.
-*/
+/*!
+ * Draws the vertex attributes as a specified primitive type as the vertices
+ * are defined in the attribute arrays.
+ * @param primitiveType
+ * @param firstVertex
+ * @param countVertices
+ */
void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
SLint firstVertex,
SLsizei countVertices)
@@ -433,9 +437,11 @@ void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
if (countVertices == 0)
countVertices = (SLsizei)_numVertices;
- ////////////////////////////////////////////////////////
- glDrawArrays(primitiveType, firstVertex, countVertices);
- ////////////////////////////////////////////////////////
+ //////////////////////////////////
+ glDrawArrays(primitiveType,
+ firstVertex,
+ countVertices);
+ //////////////////////////////////
// Update statistics
totalDrawCalls++;
@@ -458,14 +464,22 @@ void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
GET_GL_ERROR;
}
-
+//-----------------------------------------------------------------------------
+/*!
+ *
+ * @param primitiveType
+ * @param countInstance
+ * @param numIndexes
+ * @param indexOffset
+ */
void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
SLsizei countInstance,
SLuint numIndexes,
- SLuint indexOffset
- )
+ SLuint indexOffset)
{
- assert(_numIndicesElements && _idVBOIndices && "No index VBO generated for VAO");
+ assert(_numIndicesElements &&
+ _idVBOIndices &&
+ "No index VBO generated for VAO");
// From OpenGL 3.0 on we have the OpenGL Vertex Arrays
// Binding the VAO saves all the commands after the else (per draw call!)
@@ -479,8 +493,11 @@ void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
SLuint indexTypeSize = SLGLVertexBuffer::sizeOfType(_indexDataType);
////////////////////////////////////////////////////////
- glDrawElementsInstanced(primitiveType, (SLsizei)numIndexes ,_indexDataType, (void*)(size_t)(indexOffset * (SLuint)indexTypeSize), countInstance);
- //glDrawElements(primitiveType, (SLsizei)numIndexes ,_indexDataType, (void*)(size_t)(indexOffset * (SLuint)indexTypeSize));
+ glDrawElementsInstanced(primitiveType,
+ (SLsizei)numIndexes,
+ _indexDataType,
+ (void*)(size_t)(indexOffset * (SLuint)indexTypeSize),
+ countInstance);
////////////////////////////////////////////////////////
GET_GL_ERROR;
@@ -534,9 +551,11 @@ void SLGLVertexArray::drawEdges(SLCol4f color,
glLineWidth(lineWidth);
#endif
- //////////////////////////////////////////////////////////////////
- drawElementsAs(PT_lines, _numIndicesEdges, _numIndicesElements);
- //////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////
+ drawElementsAs(PT_lines,
+ _numIndicesEdges,
+ _numIndicesElements);
+ //////////////////////////////////////////////
#ifndef SL_GLES
if (lineWidth != 1.0f)
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index 37d9d0e7..2d1dc253 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -426,7 +426,8 @@ void SLParticleSystem::generate()
tempAngulareVelo[i] = Utils::random(_angularVelocityRange.x * DEG2RAD,
_angularVelocityRange.y * DEG2RAD); // Start rotation of the particle
if (_doFlipBookTexture) // Flipbook texture
- tempTexNum[i] = Utils::random(0, _flipbookRows * _flipbookColumns - 1);
+ tempTexNum[i] = Utils::random(0,
+ _flipbookRows * _flipbookColumns - 1);
if (_doShape) // Shape feature
tempInitP[i] = tempP[i];
}
@@ -439,15 +440,25 @@ void SLParticleSystem::generate()
_vao1.setAttrib(AT_startTime, AT_startTime, &tempST);
if (_doAcceleration || _doGravity)
- _vao1.setAttrib(AT_initialVelocity, AT_initialVelocity, &tempInitV);
+ _vao1.setAttrib(AT_initialVelocity,
+ AT_initialVelocity,
+ &tempInitV);
if (_doRotation)
- _vao1.setAttrib(AT_rotation, AT_rotation, &tempR);
+ _vao1.setAttrib(AT_rotation,
+ AT_rotation,
+ &tempR);
if (_doRotation && _doRotRange)
- _vao1.setAttrib(AT_angularVelo, AT_angularVelo, &tempAngulareVelo);
+ _vao1.setAttrib(AT_angularVelo,
+ AT_angularVelo,
+ &tempAngulareVelo);
if (_doFlipBookTexture)
- _vao1.setAttrib(AT_texNum, AT_texNum, &tempTexNum);
+ _vao1.setAttrib(AT_texNum,
+ AT_texNum,
+ &tempTexNum);
if (_doShape)
- _vao1.setAttrib(AT_initialPosition, AT_initialPosition, &tempInitP);
+ _vao1.setAttrib(AT_initialPosition,
+ AT_initialPosition,
+ &tempInitP);
_vao1.generateTF((SLuint)tempP.size());
// Configure second VAO
@@ -457,11 +468,17 @@ void SLParticleSystem::generate()
_vao2.setAttrib(AT_startTime, AT_startTime, &tempST);
if (_doAcceleration || _doGravity)
- _vao2.setAttrib(AT_initialVelocity, AT_initialVelocity, &tempInitV);
+ _vao2.setAttrib(AT_initialVelocity,
+ AT_initialVelocity,
+ &tempInitV);
if (_doRotation)
- _vao2.setAttrib(AT_rotation, AT_rotation, &tempR);
+ _vao2.setAttrib(AT_rotation,
+ AT_rotation,
+ &tempR);
if (_doRotation && _doRotRange)
- _vao2.setAttrib(AT_angularVelo, AT_angularVelo, &tempAngulareVelo);
+ _vao2.setAttrib(AT_angularVelo,
+ AT_angularVelo,
+ &tempAngulareVelo);
if (_doFlipBookTexture)
_vao2.setAttrib(AT_texNum, AT_texNum, &tempTexNum);
if (_doShape)
@@ -600,34 +617,68 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
float deltaTime = GlobalTimer::timeS() - _startUpdateTimeS; // Actual delta time
// Calculate time difference for frustum culling and paused
- if (!_isVisibleInFrustum && !_isPaused && _lastTimeBeforePauseS != 0.0f) // If particle system was not visible, and was resumed when it was not visible
+ // If particle system was not visible, and was resumed when it was not visible
+ if (!_isVisibleInFrustum && !_isPaused && _lastTimeBeforePauseS != 0.0f)
{
_isVisibleInFrustum = true;
- difTime = GlobalTimer::timeS() - min(_lastTimeBeforePauseS, _notVisibleTimeS); // Paused was set before not visible (will take _lastTimeBeforePauseS), if set after (will take _notVisibleTimeS)
- // maybe add later average delta time (because maybe bug when fast not visible long time, visible, not visible, visible
- deltaTime = _deltaTimeUpdateS; // Last delta time, because when culled draw is not called therefore the actual delta time will be too big
- _notVisibleTimeS = 0.0f; // No more culling, the difference time has been applied, no further need
- _lastTimeBeforePauseS = 0.0f; // No more paused, the difference time has been applied, no further need
+
+ // Paused was set before not visible (will take _lastTimeBeforePauseS),
+ // if set after (will take _notVisibleTimeS)
+ difTime = GlobalTimer::timeS() - min(_lastTimeBeforePauseS, _notVisibleTimeS);
+
+ // maybe add later average delta time
+ // (because maybe bug when fast not visible long time, visible, not visible, visible
+ // Last delta time, because when culled draw is not called therefore
+ // the actual delta time will be too big
+ deltaTime = _deltaTimeUpdateS;
+
+ // No more culling, the difference time has been applied, no further need
+ _notVisibleTimeS = 0.0f;
+
+ // No more paused, the difference time has been applied, no further need
+ _lastTimeBeforePauseS = 0.0f;
}
- else if (!_isVisibleInFrustum) // If particle system was not visible, this one is called just once when the particle is draw again (Do nothing if paused, because update call is not done)
+
+ // If particle system was not visible, this one is called just once when the
+ // particle is draw again (Do nothing if paused, because update call is not done)
+ else if (!_isVisibleInFrustum)
{
_isVisibleInFrustum = true;
- difTime = GlobalTimer::timeS() - _notVisibleTimeS; // Use time since the particle system was not visible
- // maybe add later average delta time (because maybe bug when fast not visible long time, visible, not visible, visible
- deltaTime = _deltaTimeUpdateS; // Last delta time, because when culled draw is not called therefore the actual delta time will be too big
- if (_lastTimeBeforePauseS > _notVisibleTimeS) // If was paused when not visible. Need to take _notVisibleTimeS because it's since this value that the particle system is not drew.
- _lastTimeBeforePauseS = _notVisibleTimeS; // Get the value of since the particle system is not drew
- _notVisibleTimeS = 0.0f; // No more culling, the difference time has been applied, no further need
+
+ // Use time since the particle system was not visible
+ difTime = GlobalTimer::timeS() - _notVisibleTimeS;
+
+ // maybe add later average delta time (because maybe bug when
+ // fast not visible long time, visible, not visible, visible
+ // Last delta time, because when culled draw is not called
+ // therefore the actual delta time will be too big
+ deltaTime = _deltaTimeUpdateS;
+
+ // If was paused when not visible. Need to take _notVisibleTimeS because
+ // it's since this value that the particle system is not drew.
+ if (_lastTimeBeforePauseS > _notVisibleTimeS)
+ // Get the value of since the particle system is not drew
+ _lastTimeBeforePauseS = _notVisibleTimeS;
+
+ // No more culling, the difference time has been applied, no further need
+ _notVisibleTimeS = 0.0f;
}
- else if (!_isPaused && _lastTimeBeforePauseS != 0.0f) // If particle system was resumed
+
+ // If particle system was resumed
+ else if (!_isPaused && _lastTimeBeforePauseS != 0.0f)
{
- difTime = GlobalTimer::timeS() - _lastTimeBeforePauseS; // Use time since the particle system was paused
- _lastTimeBeforePauseS = 0.0f; // No more paused, the difference time has been applied, no further need
+ // Use time since the particle system was paused
+ difTime = GlobalTimer::timeS() - _lastTimeBeforePauseS;
+
+ // No more paused, the difference time has been applied, no further need
+ _lastTimeBeforePauseS = 0.0f;
- // Take default delta time, because when just paused no need to take last delta time, the draw call continue to be called
+ // Take default delta time, because when just paused no need to
+ // take last delta time, the draw call continue to be called
}
- // Calculate the elapsed time for the updating, need to change to use a real profiler (can't measure time like this on the GPU)
+ // Calculate the elapsed time for the updating, need to change to
+ // use a real profiler (can't measure time like this on the GPU)
_startUpdateTimeMS = GlobalTimer::timeMS();
// MS above, S below
@@ -660,13 +711,20 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
if (_doAcceleration)
{
if (_doAccDiffDir)
- spTF->uniform3f("u_acceleration", _acceleration.x, _acceleration.y, _acceleration.z);
+ spTF->uniform3f("u_acceleration",
+ _acceleration.x,
+ _acceleration.y,
+ _acceleration.z);
else
- spTF->uniform1f("u_accConst", _accelerationConst);
+ spTF->uniform1f("u_accConst",
+ _accelerationConst);
}
if (_doGravity)
- spTF->uniform3f("u_gravity", _gravity.x, _gravity.y, _gravity.z);
+ spTF->uniform3f("u_gravity",
+ _gravity.x,
+ _gravity.y,
+ _gravity.z);
spTF->uniform1f("u_tTL", _timeToLive);
@@ -742,7 +800,8 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
SLGLState* stateGL = SLGLState::instance();
- // Start calculation of the elapsed time for the drawing, need to change to use a real profiler (can't measure time like this on the GPU)
+ // Start calculation of the elapsed time for the drawing, need to change
+ // to use a real profiler (can't measure time like this on the GPU)
_startDrawTimeMS = GlobalTimer::timeMS();
// Billboard type
@@ -867,7 +926,8 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
spD->uniform1f("u_oneOverGamma", 1.0f);
// Check wireframe
- if (sv->drawBits()->get(SL_DB_MESHWIRED) || node->drawBits()->get(SL_DB_MESHWIRED))
+ if (sv->drawBits()->get(SL_DB_MESHWIRED) ||
+ node->drawBits()->get(SL_DB_MESHWIRED))
spD->uniform1i("u_doWireFrame", 1);
else
spD->uniform1i("u_doWireFrame", 0);
@@ -883,7 +943,8 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
///////////////////////
if (_doColor && _doBlendBrightness)
- stateGL->blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ stateGL->blendFunc(GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
// End calculation of the elapsed time for the drawing
_drawTime.set(GlobalTimer::timeMS() - _startDrawTimeMS);
@@ -891,7 +952,7 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
// Swap buffer
_drawBuf = 1 - _drawBuf;
}
-
+//-----------------------------------------------------------------------------
/*!
Change the current use texture, this will switch between the normal texture and
the flipbook texture (and vice versa)
@@ -909,7 +970,6 @@ void SLParticleSystem::changeTexture()
mat()->addTexture(_textureFirst);
}
}
-
//-----------------------------------------------------------------------------
//! deleteData deletes all mesh data and VAOs
void SLParticleSystem::deleteData()
From 47bfa2cf54aba3d98014211b46d106dcee75ac90 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Sat, 9 Dec 2023 12:26:41 +0100
Subject: [PATCH 074/108] Multiple Fixes
- Fixed Erleb-AR/Sutz model loading
- clang tidy fixes
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 11 +---
.../app_demo_slproject/source/AppDemoLoad.cpp | 4 +-
modules/sl/source/gl/SLGLVertexArray.cpp | 57 +++++++++----------
modules/sl/source/gl/SLGLVertexArray.h | 32 +++++------
modules/sl/source/gl/SLGLVertexArrayExt.cpp | 6 +-
modules/sl/source/mesh/SLMesh.cpp | 6 +-
6 files changed, 53 insertions(+), 63 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index d74b83c1..6bf7d899 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -1279,7 +1279,6 @@ void AppDemoGui::build(SLScene* s, SLSceneView* sv)
balda_stahl = nullptr;
balda_glas = nullptr;
}
-
if (AppDemo::sceneID == SID_ErlebARAugustaRauricaTmpTht ||
AppDemo::sceneID == SID_ErlebARAugustaRauricaTht ||
AppDemo::sceneID == SID_ErlebARAugustaRauricaTmp)
@@ -1302,7 +1301,6 @@ void AppDemoGui::build(SLScene* s, SLSceneView* sv)
ImGui::End();
}
-
if (AppDemo::sceneID == SID_ErlebARAventicumAmphiteatre)
{
ImGui::Begin("Avenche-Amphitheatre",
@@ -1323,7 +1321,6 @@ void AppDemoGui::build(SLScene* s, SLSceneView* sv)
ImGui::End();
}
-
if (AppDemo::sceneID == SID_ErlebARAventicumCigognier)
{
ImGui::Begin("Avenche-Cigognier",
@@ -1343,7 +1340,6 @@ void AppDemoGui::build(SLScene* s, SLSceneView* sv)
}
ImGui::End();
}
-
if (AppDemo::sceneID == SID_ErlebARAventicumTheatre)
{
ImGui::Begin("Avenche-Theatre",
@@ -1364,7 +1360,6 @@ void AppDemoGui::build(SLScene* s, SLSceneView* sv)
ImGui::End();
}
-
if (AppDemo::sceneID == SID_ErlebARSutzKirchrain18)
{
ImGui::Begin("Sutz-Kirchrain18",
@@ -1774,16 +1769,14 @@ void AppDemoGui::buildMenuBar(SLScene* s, SLSceneView* sv)
SLstring modelAV1_AO = erlebarPath + "avenches/avenches-amphitheater.gltf";
SLstring modelAV2_AO = erlebarPath + "avenches/avenches-cigognier.gltf";
SLstring modelAV3 = erlebarPath + "avenches/avenches-theater.gltf";
- SLstring modelSU1 = erlebarPath + "sutzKirchrain18/Sutz-Kirchrain18.gltf";
- SLstring modelEV1 = erlebarPath + "evilardCheminDuRoc2/EvilardCheminDuRoc2.gltf";
+ SLstring modelSU1 = erlebarPath + "sutz/Sutz-Kirchrain18.gltf";
if (Utils::fileExists(modelAR1) ||
Utils::fileExists(modelAR2) ||
Utils::fileExists(modelAR3) ||
Utils::fileExists(modelAV3) ||
Utils::fileExists(modelBR2) ||
- Utils::fileExists(modelSU1) ||
- Utils::fileExists(modelEV1))
+ Utils::fileExists(modelSU1))
{
if (ImGui::BeginMenu("Erleb-AR"))
{
diff --git a/apps/app_demo_slproject/source/AppDemoLoad.cpp b/apps/app_demo_slproject/source/AppDemoLoad.cpp
index bcc9f6ff..d0565cf2 100644
--- a/apps/app_demo_slproject/source/AppDemoLoad.cpp
+++ b/apps/app_demo_slproject/source/AppDemoLoad.cpp
@@ -5323,7 +5323,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
SLAssimpImporter importer;
SLNode* sutzK18 = importer.load(s->animManager(),
am,
- dataPath + "erleb-AR/models/sutzKirchrain18/Sutz-Kirchrain18.gltf",
+ dataPath + "erleb-AR/models/sutz/Sutz-Kirchrain18.gltf",
texPath,
nullptr,
true, // delete tex images after build
@@ -5375,7 +5375,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
AppDemo::devRot.offsetMode(ROM_oneFingerX);
// This loads the DEM file and overwrites the altitude of originLatLonAlt and defaultLatLonAlt
- SLstring tif = dataPath + "erleb-AR/models/sutzKirchrain18/Sutz-Kirchrain18-DEM-WGS84.tif";
+ SLstring tif = dataPath + "erleb-AR/models/sutz/Sutz-Kirchrain18-DEM-WGS84.tif";
AppDemo::devLoc.loadGeoTiff(tif);
#if defined(SL_OS_MACIOS) || defined(SL_OS_ANDROID)
diff --git a/modules/sl/source/gl/SLGLVertexArray.cpp b/modules/sl/source/gl/SLGLVertexArray.cpp
index ec700a81..2a8cab0b 100644
--- a/modules/sl/source/gl/SLGLVertexArray.cpp
+++ b/modules/sl/source/gl/SLGLVertexArray.cpp
@@ -22,14 +22,14 @@ SLuint SLGLVertexArray::totalPrimitivesRendered = 0;
SLGLVertexArray::SLGLVertexArray()
{
_vaoID = 0;
- _VBOf.clear();
+ _vbo.clear();
_idVBOIndices = 0;
_numIndicesElements = 0;
_numIndicesEdges = 0;
_numVertices = 0;
_indexDataElements = nullptr;
_indexDataEdges = nullptr;
- _externalVBOf = nullptr;
+ _externalVbo = nullptr;
}
//-----------------------------------------------------------------------------
/*! Deletes the OpenGL objects for the vertex array and the vertex buffer.
@@ -41,8 +41,8 @@ void SLGLVertexArray::deleteGL()
glDeleteVertexArrays(1, &_vaoID);
_vaoID = 0;
- if (_VBOf.id())
- _VBOf.clear();
+ if (_vbo.id())
+ _vbo.clear();
if (_idVBOIndices)
{
@@ -74,7 +74,7 @@ void SLGLVertexArray::setAttrib(SLGLAttributeType type,
if (type == AT_position && location == -1)
SL_EXIT_MSG("The position attribute has no variable location.");
- if (_VBOf.attribIndex(type) >= 0)
+ if (_vbo.attribIndex(type) >= 0)
SL_EXIT_MSG("Attribute type already exists.");
SLGLAttribute va;
@@ -85,16 +85,14 @@ void SLGLVertexArray::setAttrib(SLGLAttributeType type,
va.location = location;
va.bufferSizeBytes = 0;
- _VBOf.attribs().push_back(va);
+ _vbo.attribs().push_back(va);
}
-
//-----------------------------------------------------------------------------
void SLGLVertexArray::setExternalVBO(SLGLVertexBuffer* vbo, SLuint divisor)
{
- _externalVBOf = vbo;
+ _externalVbo = vbo;
_externalDivisor = divisor;
}
-
//-----------------------------------------------------------------------------
/*! Defines the vertex indices for the element drawing. Without indices vertex
array can only be drawn with SLGLVertexArray::drawArrayAs.
@@ -134,7 +132,7 @@ void SLGLVertexArray::updateAttrib(SLGLAttributeType type,
assert(elementSize > 0 && elementSize < 5 && "Element size invalid");
// Get attribute index and check element size
- SLint indexf = _VBOf.attribIndex(type);
+ SLint indexf = _vbo.attribIndex(type);
if (indexf == -1)
SL_EXIT_MSG("Attribute type does not exist in VAO.");
@@ -144,7 +142,7 @@ void SLGLVertexArray::updateAttrib(SLGLAttributeType type,
// update the appropriate VBO
if (indexf > -1)
- _VBOf.updateAttrib(type, elementSize, dataPointer);
+ _vbo.updateAttrib(type, elementSize, dataPointer);
glBindVertexArray(0);
GET_GL_ERROR;
@@ -203,15 +201,15 @@ void SLGLVertexArray::generate(SLuint numVertices,
///////////////////////////////
// Generate the vertex buffer object for float attributes
- if (_VBOf.attribs().size())
+ if (_vbo.attribs().size())
{
- _VBOf.generate(numVertices, usage, outputInterleaved);
- _VBOf.bindAndEnableAttrib(divisor);
+ _vbo.generate(numVertices, usage, outputInterleaved);
+ _vbo.bindAndEnableAttrib(divisor);
}
- if (_externalVBOf != nullptr)
+ if (_externalVbo != nullptr)
{
- _externalVBOf->bindAndEnableAttrib(_externalDivisor);
+ _externalVbo->bindAndEnableAttrib(_externalDivisor);
}
/////////////////////////////////////////////////////////////////
@@ -245,7 +243,7 @@ void SLGLVertexArray::generate(SLuint numVertices,
glGenBuffers(1, &_idVBOIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _idVBOIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- _numIndicesElements * (SLuint)typeSize,
+ (GLsizeiptr)_numIndicesElements * (SLuint)typeSize,
_indexDataElements,
GL_STATIC_DRAW);
SLGLVertexBuffer::totalBufferCount++;
@@ -281,15 +279,15 @@ void SLGLVertexArray::generateTF(SLuint numVertices,
///////////////////////////////
// Generate the vertex buffer object for float attributes
- if (_VBOf.attribs().size())
+ if (_vbo.attribs().size())
{
- _VBOf.generate(numVertices, usage, outputInterleaved);
- _VBOf.bindAndEnableAttrib(divisor);
+ _vbo.generate(numVertices, usage, outputInterleaved);
+ _vbo.bindAndEnableAttrib(divisor);
}
- if (_externalVBOf != nullptr)
+ if (_externalVbo != nullptr)
{
- _externalVBOf->bindAndEnableAttrib(_externalDivisor);
+ _externalVbo->bindAndEnableAttrib(_externalDivisor);
}
///////////////////////////////
@@ -297,7 +295,7 @@ void SLGLVertexArray::generateTF(SLuint numVertices,
///////////////////////////////
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _tfoID);
- glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _VBOf.id());
+ glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _vbo.id());
/////////////////////////////////////////////////////////////////
// Create Element Array Buffer for Indices for elements and edges
@@ -330,7 +328,7 @@ void SLGLVertexArray::generateTF(SLuint numVertices,
glGenBuffers(1, &_idVBOIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _idVBOIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
- _numIndicesElements * (SLuint)typeSize,
+ (GLsizeiptr)_numIndicesElements * (SLuint)typeSize,
_indexDataElements,
GL_STATIC_DRAW);
SLGLVertexBuffer::totalBufferCount++;
@@ -430,7 +428,7 @@ void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
SLint firstVertex,
SLsizei countVertices)
{
- assert((_VBOf.id()) && "No VBO generated for VAO.");
+ assert((_vbo.id()) && "No VBO generated for VAO.");
glBindVertexArray(_vaoID);
@@ -473,7 +471,7 @@ void SLGLVertexArray::drawArrayAs(SLGLPrimitiveType primitiveType,
* @param indexOffset
*/
void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
- SLsizei countInstance,
+ SLuint countInstance,
SLuint numIndexes,
SLuint indexOffset)
{
@@ -494,10 +492,10 @@ void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
////////////////////////////////////////////////////////
glDrawElementsInstanced(primitiveType,
- (SLsizei)numIndexes,
+ (GLsizei)numIndexes,
_indexDataType,
(void*)(size_t)(indexOffset * (SLuint)indexTypeSize),
- countInstance);
+ (GLsizei )countInstance);
////////////////////////////////////////////////////////
GET_GL_ERROR;
@@ -520,7 +518,6 @@ void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
GET_GL_ERROR;
}
-
//-----------------------------------------------------------------------------
/*! Draws the hard edges with the specified color.
The VAO has no or one active index buffer. For drawArrayAs no indices are needed.
@@ -530,7 +527,7 @@ void SLGLVertexArray::drawElementsInstanced(SLGLPrimitiveType primitiveType,
void SLGLVertexArray::drawEdges(SLCol4f color,
SLfloat lineWidth)
{
- if (!_VBOf.id())
+ if (!_vbo.id())
SL_EXIT_MSG("No VBO generated for VAO in drawArrayAsColored.");
// Prepare shader
diff --git a/modules/sl/source/gl/SLGLVertexArray.h b/modules/sl/source/gl/SLGLVertexArray.h
index 852e9017..d324a3eb 100644
--- a/modules/sl/source/gl/SLGLVertexArray.h
+++ b/modules/sl/source/gl/SLGLVertexArray.h
@@ -22,7 +22,7 @@
VBO of type SLGLVertexBuffer.\n
VAOs where introduces OpenGL 3.0 and reduce the overhead per draw call.
All vertex attributes (e.g. position, normals, texture coords, etc.) must be
- float at the input. All float attributes will be in one VBO (_VBOf).
+ float at the input. All float attributes will be in one VBO (_vbo).
Vertices can be drawn either directly as in the array (SLGLVertexArray::drawArrayAs)
or by element (SLGLVertexArray::drawElementsAs) with a separate indices buffer.\n
The setup of a VAO has multiple steps:\n
@@ -49,14 +49,14 @@ class SLGLVertexArray
void clearAttribs()
{
deleteGL();
- _VBOf.clear();
+ _vbo.clear();
}
//! Returns either the VAO id or the VBO id
- SLint vaoID() const { return _vaoID; }
+ SLuint vaoID() const { return _vaoID; }
//! Returns the TFO id
- SLint tfoID() const { return _tfoID; }
+ SLuint tfoID() const { return _tfoID; }
//! Adds a vertex attribute with data pointer and an element size
void setAttrib(SLGLAttributeType type,
@@ -136,7 +136,7 @@ class SLGLVertexArray
}
//! Attach a VBO that has been created outside of this VAO
- void setExternalVBO(SLGLVertexBuffer *vbo, SLuint divisor = 0);
+ void setExternalVBO(SLGLVertexBuffer* vbo, SLuint divisor = 0);
//! Updates a specific vertex attribute in the VBO
void updateAttrib(SLGLAttributeType type,
@@ -193,18 +193,18 @@ class SLGLVertexArray
//! Draws the VAO as an array with instance primitive type
void drawElementsInstanced(SLGLPrimitiveType primitiveType,
- SLsizei countInstance = 0,
- SLuint numIndexes = 0,
- SLuint indexOffset = 0);
+ SLuint countInstance = 0,
+ SLuint numIndexes = 0,
+ SLuint indexOffset = 0);
//! Draws the hard edges of the VAO with the edge indices
void drawEdges(SLCol4f color, SLfloat lineWidth = 1.0f);
// Some getters
- SLuint numVertices() const { return _numVertices; }
- SLuint numIndicesElements() const { return _numIndicesElements; }
- SLuint numIndicesEdges() const { return _numIndicesEdges; }
- SLGLVertexBuffer* vbo() { return &_VBOf; }
+ SLuint numVertices() const { return _numVertices; }
+ SLuint numIndicesElements() const { return _numIndicesElements; }
+ SLuint numIndicesEdges() const { return _numIndicesEdges; }
+ SLGLVertexBuffer* vbo() { return &_vbo; }
// Some statistics
static SLuint totalDrawCalls; //! static total no. of draw calls
@@ -215,13 +215,13 @@ class SLGLVertexArray
SLuint _vaoID; //! OpenGL id of vertex array object
SLuint _tfoID; //! OpenGL id of transform feedback object
SLuint _numVertices; //! NO. of vertices in array
- SLGLVertexBuffer _VBOf; //! Vertex buffer object for float attributes
- SLGLVertexBuffer* _externalVBOf; //! Vertex buffer object that has beed created outside of this VAO
+ SLGLVertexBuffer _vbo; //! Vertex buffer object for float attributes
+ SLGLVertexBuffer* _externalVbo; //! Vertex buffer object that has been created outside of this VAO
SLuint _externalDivisor; //! VBO attrib divisor for the external VBO
SLuint _idVBOIndices; //! OpenGL id of index vbo
- SLuint _numIndicesElements; //! NO. of vertex indices in array for triangles, lines or points
+ size_t _numIndicesElements; //! NO. of vertex indices in array for triangles, lines or points
void* _indexDataElements; //! Pointer to index data for elements
- SLuint _numIndicesEdges; //! NO. of vertex indices in array for hard edges
+ size_t _numIndicesEdges; //! NO. of vertex indices in array for hard edges
void* _indexDataEdges; //! Pointer to index data for hard edges
SLGLBufferType _indexDataType; //! index data type (ubyte, ushort, uint)
};
diff --git a/modules/sl/source/gl/SLGLVertexArrayExt.cpp b/modules/sl/source/gl/SLGLVertexArrayExt.cpp
index 16a2b438..290e794f 100644
--- a/modules/sl/source/gl/SLGLVertexArrayExt.cpp
+++ b/modules/sl/source/gl/SLGLVertexArrayExt.cpp
@@ -32,7 +32,7 @@ void SLGLVertexArrayExt::generateVertexPos(SLuint numVertices,
SLint location = AT_position;
// Add attribute if it doesn't exist
- if (_VBOf.attribIndex(AT_position) == -1)
+ if (_vbo.attribIndex(AT_position) == -1)
{
setAttrib(AT_position, elementSize, location, dataPointer);
generate(numVertices, BU_static, false);
@@ -51,7 +51,7 @@ void SLGLVertexArrayExt::drawArrayAsColored(SLGLPrimitiveType primitiveType,
{
assert(countVertices <= _numVertices);
- if (!_VBOf.id())
+ if (!_vbo.id())
SL_EXIT_MSG("No VBO generated for VAO in drawArrayAsColored.");
// Prepare shader
@@ -98,7 +98,7 @@ void SLGLVertexArrayExt::drawElementAsColored(SLGLPrimitiveType primitiveType,
{
assert(countVertices <= _numVertices);
- if (!_VBOf.id())
+ if (!_vbo.id())
SL_EXIT_MSG("No VBO generated for VAO in drawArrayAsColored.");
// Prepare shader
diff --git a/modules/sl/source/mesh/SLMesh.cpp b/modules/sl/source/mesh/SLMesh.cpp
index 1b8c75d8..8ad9d748 100644
--- a/modules/sl/source/mesh/SLMesh.cpp
+++ b/modules/sl/source/mesh/SLMesh.cpp
@@ -846,7 +846,7 @@ void SLMesh::computeHardEdgesIndices(float angleDEG,
{
F.resize((Eigen::Index)I32.size() / 3, 3);
for (int j = 0, i = 0; i < I32.size(); j++, i += 3)
- F.row(j) << I32[i], I32[i + 1], I32[i + 2];
+ F.row(j) << (int)I32[i], (int)I32[i + 1], (int)I32[i + 2];
}
// extract sharp edges
@@ -869,9 +869,9 @@ void SLMesh::computeHardEdgesIndices(float angleDEG,
// ei = fi + |F| * c -> ei % |F| = fi % |F| = fi; fi is the face adjacent to ei
// ej = fj + |F| * c -> ej % |F| = fj % |F| = fj; fj is the face adjacent to ej
const int ei = uE2E[u][i]; // edge i
- const int fi = ei % newF.rows();
+ const int fi = ei % (int)newF.rows();
const int ej = uE2E[u][j]; // edge j
- const int fj = ej % newF.rows();
+ const int fj = ej % (int)newF.rows();
Eigen::Matrix ni = faceN.row(fi);
Eigen::Matrix nj = faceN.row(fj);
Eigen::Matrix ev = (newV.row(edges(ei, 1)) - newV.row(edges(ei, 0))).normalized();
From 3365c243ce2fad28412cfefe7110998b1fa94a3e Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Sat, 9 Dec 2023 12:44:53 +0100
Subject: [PATCH 075/108] Removed most glHasGeometryShader
---
apps/app_demo_slproject/source/AppDemoGui.cpp | 20 +-
.../app_demo_slproject/source/AppDemoLoad.cpp | 267 +++++++++---------
modules/sl/source/SLMaterial.cpp | 8 +-
modules/sl/source/SLMaterial.h | 2 +-
modules/sl/source/gl/SLGLProgramGenerated.cpp | 8 +-
modules/sl/source/gl/SLGLProgramGenerated.h | 4 +-
modules/sl/source/mesh/SLParticleSystem.cpp | 5 +-
7 files changed, 153 insertions(+), 161 deletions(-)
diff --git a/apps/app_demo_slproject/source/AppDemoGui.cpp b/apps/app_demo_slproject/source/AppDemoGui.cpp
index 6bf7d899..2d81b5d2 100644
--- a/apps/app_demo_slproject/source/AppDemoGui.cpp
+++ b/apps/app_demo_slproject/source/AppDemoGui.cpp
@@ -3703,6 +3703,16 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
SLParticleSystem* ps = dynamic_cast(singleFullMesh); // Need to check if good practice
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
+ if (SLGLState::instance()->glHasGeometryShaders())
+ {
+ bool drawInstanced = ps->drawInstanced();
+ if (ImGui::Checkbox("Instanced draw", &drawInstanced))
+ {
+ ps->drawInstanced(drawInstanced);
+ ps->isGenerated(false);
+ }
+ }
+
// Pause and Resume
bool isPaused = ps->isPaused();
if (isPaused)
@@ -3729,16 +3739,6 @@ void AppDemoGui::buildProperties(SLScene* s, SLSceneView* sv)
ps->isGenerated(false);
}
- if (SLGLState::instance()->glHasGeometryShaders())
- {
- bool drawInstanced = ps->drawInstanced();
- if (ImGui::Checkbox("Instanced draw", &drawInstanced))
- {
- ps->drawInstanced(drawInstanced);
- ps->isGenerated(false);
- }
- }
-
// TTL (Time to live)
if (ImGui::CollapsingHeader("Time to live"))
{
diff --git a/apps/app_demo_slproject/source/AppDemoLoad.cpp b/apps/app_demo_slproject/source/AppDemoLoad.cpp
index d0565cf2..d9ae1c45 100644
--- a/apps/app_demo_slproject/source/AppDemoLoad.cpp
+++ b/apps/app_demo_slproject/source/AppDemoLoad.cpp
@@ -3584,7 +3584,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
scene->addChild(cam1);
std::uniform_real_distribution dist(0.0f, 1.0f);
- std::default_random_engine randEngine;
+ std::default_random_engine randEngine;
// create astroboys around the center astroboy
SLint size = 4;
@@ -5628,7 +5628,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
#ifndef SL_GLES
SLuint numSamples = 10;
#else
- SLuint numSamples = 4;
+ SLuint numSamples = 4;
#endif
stringstream ss;
@@ -5720,7 +5720,7 @@ resolution shadows near the camera and lower resolution shadows further away.");
#ifndef APP_USES_GLES
SLuint numSamples = 10;
#else
- SLuint numSamples = 6;
+ SLuint numSamples = 6;
#endif
// Scene
@@ -5817,52 +5817,53 @@ resolution shadows near the camera and lower resolution shadows further away.");
sv->camera(cam1);
}
- if (sceneID == SID_ParticleSystem_First) //...............................................
+
+ else if (sceneID == SID_ParticleSystem_First) //...............................................
{
- if (stateGL->glHasGeometryShaders())
- {
- // Set scene name and info string
- s->name("First particle system");
- s->info("First scene with a particle system");
+ // Set scene name and info string
+ s->name("First particle system");
+ s->info("First scene with a particle system");
- // Create a scene group node
- SLNode* scene = new SLNode("scene node");
- s->root3D(scene);
+ // Create a scene group node
+ SLNode* scene = new SLNode("scene node");
+ s->root3D(scene);
- // Create and add camera
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->translation(0, 1.5f, 4);
- cam1->lookAt(0, 1.5f, 0);
- scene->addChild(cam1);
+ // Create and add camera
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->translation(0, 1.5f, 4);
+ cam1->lookAt(0, 1.5f, 0);
+ scene->addChild(cam1);
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am,
+ texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am,
+ texPath + "ParticleSmoke_03_8x8_C.png");
- // Create a light source node
- SLLightSpot* light1 = new SLLightSpot(am, s, 0.3f);
- light1->translation(5, 5, 5);
- light1->name("light node");
- scene->addChild(light1);
+ // Create a light source node
+ SLLightSpot* light1 = new SLLightSpot(am, s, 0.3f);
+ light1->translation(5, 5, 5);
+ light1->name("light node");
+ scene->addChild(light1);
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 50,
- SLVec3f(0.04f, 0.4f, 0.1f),
- SLVec3f(-0.11f, 0.7f, -0.1f),
- 4.0f,
- texC,
- "Particle System",
- texFlipbook);
- SLNode* pSNode = new SLNode(ps, "Particle system node");
- scene->addChild(pSNode);
-
- // Set background color and the root scene node
- sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
- SLCol4f(0.2f, 0.2f, 0.2f));
- sv->camera(cam1);
- sv->doWaitOnIdle(false);
- }
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 50,
+ SLVec3f(0.04f, 0.4f, 0.1f),
+ SLVec3f(-0.11f, 0.7f, -0.1f),
+ 4.0f,
+ texC,
+ "Particle System",
+ texFlipbook);
+
+ SLNode* pSNode = new SLNode(ps, "Particle system node");
+ scene->addChild(pSNode);
+
+ // Set background color and the root scene node
+ sv->sceneViewCamera()->background().colors(SLCol4f(0.8f, 0.8f, 0.8f),
+ SLCol4f(0.2f, 0.2f, 0.2f));
+ sv->camera(cam1);
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_ParticleSystem_Demo) //................................................
{
@@ -6711,109 +6712,103 @@ resolution shadows near the camera and lower resolution shadows further away.");
}
else if (sceneID == SID_Benchmark8_ParticleSystemFireComplex) //...............................
{
- if (stateGL->glHasGeometryShaders())
- {
- s->name("Fire Complex Test Scene");
- s->info(s->name());
+ s->name("Fire Complex Test Scene");
+ s->info(s->name());
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->clipNear(0.1f);
- cam1->clipFar(1000);
- cam1->translation(0, 10, 40);
- cam1->focalDist(100);
- cam1->lookAt(0, 0, 0);
- cam1->background().colors(SLCol4f(0.3f, 0.3f, 0.3f));
- cam1->setInitialState();
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->clipNear(0.1f);
+ cam1->clipFar(1000);
+ cam1->translation(0, 10, 40);
+ cam1->focalDist(100);
+ cam1->lookAt(0, 0, 0);
+ cam1->background().colors(SLCol4f(0.3f, 0.3f, 0.3f));
+ cam1->setInitialState();
- // Root scene node
- SLNode* root = new SLNode;
- s->root3D(root);
- root->addChild(cam1);
- const int NUM_NODES = 250;
-
- // Create textures and materials
- SLGLTexture* texFireCld = new SLGLTexture(am, texPath + "ParticleFirecloudTransparent_C.png");
- SLGLTexture* texFireFlm = new SLGLTexture(am, texPath + "ParticleFlames_00_8x4_C.png");
- SLGLTexture* texCircle = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
- SLGLTexture* texSmokeB = new SLGLTexture(am, texPath + "ParticleCloudBlack_C.png");
- SLGLTexture* texSmokeW = new SLGLTexture(am, texPath + "ParticleCloudWhite_C.png");
-
- SLVNode nodes(NUM_NODES);
- for (int i = 0; i < NUM_NODES; ++i)
- {
- SLNode* fireComplex = createComplexFire(am,
- s,
- false,
- texFireCld,
- texFireFlm,
- 8,
- 4,
- texCircle,
- texSmokeB,
- texSmokeW);
- fireComplex->translate(-20.0f + (float)(i % 20) * 2,
- 0.0f,
- -(float)((i - (i % 20)) / 20) * 4,
- TS_object);
- root->addChild(fireComplex);
- }
+ // Root scene node
+ SLNode* root = new SLNode;
+ s->root3D(root);
+ root->addChild(cam1);
+ const int NUM_NODES = 250;
- sv->camera(cam1);
- sv->doWaitOnIdle(false);
+ // Create textures and materials
+ SLGLTexture* texFireCld = new SLGLTexture(am, texPath + "ParticleFirecloudTransparent_C.png");
+ SLGLTexture* texFireFlm = new SLGLTexture(am, texPath + "ParticleFlames_00_8x4_C.png");
+ SLGLTexture* texCircle = new SLGLTexture(am, texPath + "ParticleCircle_05_C.png");
+ SLGLTexture* texSmokeB = new SLGLTexture(am, texPath + "ParticleCloudBlack_C.png");
+ SLGLTexture* texSmokeW = new SLGLTexture(am, texPath + "ParticleCloudWhite_C.png");
+
+ SLVNode nodes(NUM_NODES);
+ for (int i = 0; i < NUM_NODES; ++i)
+ {
+ SLNode* fireComplex = createComplexFire(am,
+ s,
+ false,
+ texFireCld,
+ texFireFlm,
+ 8,
+ 4,
+ texCircle,
+ texSmokeB,
+ texSmokeW);
+ fireComplex->translate(-20.0f + (float)(i % 20) * 2,
+ 0.0f,
+ -(float)((i - (float)(i % 20)) / 20) * 4,
+ TS_object);
+ root->addChild(fireComplex);
}
+
+ sv->camera(cam1);
+ sv->doWaitOnIdle(false);
}
else if (sceneID == SID_Benchmark9_ParticleSystemManyParticles) //.............................
{
- if (stateGL->glHasGeometryShaders())
- {
- s->name("Particle System number Scene");
- s->info(s->name());
+ s->name("Particle System number Scene");
+ s->info(s->name());
- SLCamera* cam1 = new SLCamera("Camera 1");
- cam1->clipNear(0.1f);
- cam1->clipFar(1000);
- cam1->translation(0, 0, 400);
- cam1->focalDist(400);
- cam1->lookAt(0, 0, 0);
- cam1->background().colors(SLCol4f(0.3f, 0.3f, 0.3f));
- cam1->setInitialState();
+ SLCamera* cam1 = new SLCamera("Camera 1");
+ cam1->clipNear(0.1f);
+ cam1->clipFar(1000);
+ cam1->translation(0, 0, 400);
+ cam1->focalDist(400);
+ cam1->lookAt(0, 0, 0);
+ cam1->background().colors(SLCol4f(0.3f, 0.3f, 0.3f));
+ cam1->setInitialState();
+
+ // Root scene node
+ SLNode* root = new SLNode;
+ root->addChild(cam1);
- // Root scene node
- SLNode* root = new SLNode;
- root->addChild(cam1);
-
- // Create textures and materials
- SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
- SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
-
- // Create meshes and nodes
- SLParticleSystem* ps = new SLParticleSystem(am,
- 1000000,
- SLVec3f(-10.0f, -10.0f, -10.0f),
- SLVec3f(10.0f, 10.0f, 10.0f),
- 4.0f,
- texC,
- "Particle System",
- texFlipbook);
- ps->doAlphaOverLT(false);
- ps->doSizeOverLT(false);
- ps->doRotation(false);
- ps->doShape(true);
- ps->shapeType(ST_Box);
- ps->shapeScale(100.0f, 100.0f, 100.0f);
- ps->doDirectionSpeed(true);
- ps->doBlendBrightness(true);
- ps->doColor(true);
- ps->color(SLCol4f(0.875f, 0.156f, 0.875f, 1.0f));
- ps->speed(0.0f);
- SLMesh* pSMesh = ps;
- SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
- root->addChild(pSNode);
+ // Create textures and materials
+ SLGLTexture* texC = new SLGLTexture(am, texPath + "ParticleSmoke_08_C.png");
+ SLGLTexture* texFlipbook = new SLGLTexture(am, texPath + "ParticleSmoke_03_8x8_C.png");
- sv->camera(cam1);
- sv->doWaitOnIdle(false);
- s->root3D(root);
- }
+ // Create meshes and nodes
+ SLParticleSystem* ps = new SLParticleSystem(am,
+ 1000000,
+ SLVec3f(-10.0f, -10.0f, -10.0f),
+ SLVec3f(10.0f, 10.0f, 10.0f),
+ 4.0f,
+ texC,
+ "Particle System",
+ texFlipbook);
+ ps->doAlphaOverLT(false);
+ ps->doSizeOverLT(false);
+ ps->doRotation(false);
+ ps->doShape(true);
+ ps->shapeType(ST_Box);
+ ps->shapeScale(100.0f, 100.0f, 100.0f);
+ ps->doDirectionSpeed(true);
+ ps->doBlendBrightness(true);
+ ps->doColor(true);
+ ps->color(SLCol4f(0.875f, 0.156f, 0.875f, 1.0f));
+ ps->speed(0.0f);
+ SLMesh* pSMesh = ps;
+ SLNode* pSNode = new SLNode(pSMesh, "Particle system node");
+ root->addChild(pSNode);
+
+ sv->camera(cam1);
+ sv->doWaitOnIdle(false);
+ s->root3D(root);
}
////////////////////////////////////////////////////////////////////////////
diff --git a/modules/sl/source/SLMaterial.cpp b/modules/sl/source/SLMaterial.cpp
index 283a95ed..238b3b52 100644
--- a/modules/sl/source/SLMaterial.cpp
+++ b/modules/sl/source/SLMaterial.cpp
@@ -388,7 +388,7 @@ void SLMaterial::deleteDataGpu()
If this material has not yet a shader program assigned (SLMaterial::_program)
a suitable program will be generated with an instance of SLGLProgramGenerated.
*/
-void SLMaterial::generateProgramPS(bool renderInstanced)
+void SLMaterial::generateProgramPS(bool drawInstanced)
{
// If no shader program is attached add a generated shader program
// A 3D object can be stored without material or shader program information.
@@ -403,14 +403,14 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
SLGLProgramGenerated::buildProgramNamePS(this,
programNameDraw,
true,
- renderInstanced);
+ drawInstanced);
_program = _assetManager->getProgramByName(programNameDraw);
// If the program was not found by name generate a new one
if (!_program)
{
std::string geom = "";
- if (!renderInstanced)
+ if (!drawInstanced)
geom = "Geom";
_program = new SLGLProgramGenerated(_assetManager,
@@ -429,7 +429,7 @@ void SLMaterial::generateProgramPS(bool renderInstanced)
// Check first the asset manager if the requested programTF type already exists
string programNameUpdate;
- SLGLProgramGenerated::buildProgramNamePS(this, programNameUpdate, false, renderInstanced);
+ SLGLProgramGenerated::buildProgramNamePS(this, programNameUpdate, false, drawInstanced);
_programTF = _assetManager->getProgramByName(programNameUpdate);
if (!_programTF)
{
diff --git a/modules/sl/source/SLMaterial.h b/modules/sl/source/SLMaterial.h
index a1a55fc3..608395ec 100644
--- a/modules/sl/source/SLMaterial.h
+++ b/modules/sl/source/SLMaterial.h
@@ -108,7 +108,7 @@ class SLMaterial : public SLObject
SLGLProgram* program);
~SLMaterial() override;
- void generateProgramPS(bool renderInstanced = false);
+ void generateProgramPS(bool drawInstanced = false);
void activate(SLCamera* cam, SLVLight* lights, SLbool supportGPUSkinning);
SLint passToUniforms(SLGLProgram* program, SLint nextTexUnit);
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.cpp b/modules/sl/source/gl/SLGLProgramGenerated.cpp
index bb0cc546..c98006b8 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.cpp
+++ b/modules/sl/source/gl/SLGLProgramGenerated.cpp
@@ -1781,7 +1781,7 @@ void SLGLProgramGenerated::buildProgramName(SLMaterial* mat,
void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
string& programName,
bool isDrawProg,
- bool renderInstanced)
+ bool drawInstanced)
{
assert(mat && "No material pointer passed!");
programName = "gen";
@@ -1796,7 +1796,7 @@ void SLGLProgramGenerated::buildProgramNamePS(SLMaterial* mat,
{
programName += "-Draw";
- if (renderInstanced)
+ if (drawInstanced)
programName += "-Inst";
programName += mat->texturesString();
@@ -1904,7 +1904,7 @@ void SLGLProgramGenerated::buildProgramCode(SLMaterial* mat,
*/
void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat,
bool isDrawProg,
- bool renderInstanced)
+ bool drawInstanced)
{
if (mat->name() == "IBLMat")
{
@@ -1917,7 +1917,7 @@ void SLGLProgramGenerated::buildProgramCodePS(SLMaterial* mat,
if (isDrawProg)
{
- if (renderInstanced)
+ if (drawInstanced)
buildPerPixParticleInstanced(mat);
else
buildPerPixParticle(mat);
diff --git a/modules/sl/source/gl/SLGLProgramGenerated.h b/modules/sl/source/gl/SLGLProgramGenerated.h
index 48a40bd4..99062d26 100644
--- a/modules/sl/source/gl/SLGLProgramGenerated.h
+++ b/modules/sl/source/gl/SLGLProgramGenerated.h
@@ -101,11 +101,11 @@ class SLGLProgramGenerated : public SLGLProgram
static void buildProgramNamePS(SLMaterial* mat,
string& programName,
bool isDrawProg,
- bool renderInstanced);
+ bool drawInstanced);
void buildProgramCodePS(SLMaterial* mat,
bool isDrawProg,
- bool renderInstanced = false);
+ bool drawInstanced = false);
void buildProgramCode(SLMaterial* mat,
SLVLight* lights,
SLbool supportGPUSkinning);
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index 2d1dc253..4104b423 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -34,10 +34,8 @@ SLParticleSystem::SLParticleSystem(SLAssetManager* assetMgr,
{
assert(!name.empty());
- // To be added to constructor
-
_assetManager = assetMgr;
- _drawInstanced = SLGLState::instance()->glHasGeometryShaders() ? drawInstanced : true;
+ _drawInstanced = !SLGLState::instance()->glHasGeometryShaders() || drawInstanced;
_primitive = PT_points;
P.push_back(SLVec3f(0, 0, 0)); // Trick SL project because it wants mesh to have vertex
@@ -559,7 +557,6 @@ void SLParticleSystem::generateBernsteinPSize()
// 1
_bernsteinPYSize.w = StaEnd[1];
}
-
//-----------------------------------------------------------------------------
/*! Function called inside SLNode cull3DRec(..) which flags the particle system
to be not visible in the view frustum. This is needed to correct later the
From 39054c1182fbac8e333a1c649af96bc43411bab5 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Sat, 9 Dec 2023 16:52:10 +0100
Subject: [PATCH 076/108] Changed SID order
---
.../glfw/AppDemoMainGLFW.cpp | 16 ++++++++-----
apps/source/SLInterface.h | 8 +++----
modules/sl/source/SLEnums.h | 23 ++++++++++---------
modules/sl/source/mesh/SLParticleSystem.cpp | 2 ++
4 files changed, 28 insertions(+), 21 deletions(-)
diff --git a/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp b/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
index eb398952..a45ab392 100644
--- a/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
+++ b/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
@@ -119,13 +119,13 @@ SLKey mapKeyToSLKey(SLint key)
case GLFW_KEY_DOWN: return K_down;
case GLFW_KEY_LEFT: return K_left;
case GLFW_KEY_RIGHT: return K_right;
- case GLFW_KEY_LEFT_SHIFT: return K_shift;
+ case GLFW_KEY_LEFT_SHIFT:
case GLFW_KEY_RIGHT_SHIFT: return K_shift;
- case GLFW_KEY_LEFT_CONTROL: return K_ctrl;
+ case GLFW_KEY_LEFT_CONTROL:
case GLFW_KEY_RIGHT_CONTROL: return K_ctrl;
- case GLFW_KEY_LEFT_ALT: return K_alt;
+ case GLFW_KEY_LEFT_ALT:
case GLFW_KEY_RIGHT_ALT: return K_alt;
- case GLFW_KEY_LEFT_SUPER: return K_super; // Apple command key
+ case GLFW_KEY_LEFT_SUPER:
case GLFW_KEY_RIGHT_SUPER: return K_super; // Apple command key
case GLFW_KEY_TAB: return K_tab;
case GLFW_KEY_ENTER: return K_enter;
@@ -381,6 +381,7 @@ static void onKeyPress(GLFWwindow* myWindow,
AppDemo::scene,
sv,
SID_Empty);
+ SL_LOG("----------------------------------------------");
SL_LOG("Loading SceneID: %d", AppDemo::sceneID);
}
else if (key == K_left && sv && AppDemo::sceneID > 0)
@@ -389,6 +390,7 @@ static void onKeyPress(GLFWwindow* myWindow,
AppDemo::scene,
sv,
(SLSceneID)(AppDemo::sceneID - 1));
+ SL_LOG("----------------------------------------------");
SL_LOG("Loading SceneID: %d", AppDemo::sceneID);
}
else if (key == K_right && sv && AppDemo::sceneID < SID_Maximal - 1)
@@ -397,6 +399,7 @@ static void onKeyPress(GLFWwindow* myWindow,
AppDemo::scene,
sv,
(SLSceneID)(AppDemo::sceneID + 1));
+ SL_LOG("----------------------------------------------");
SL_LOG("Loading SceneID: %d", AppDemo::sceneID);
}
}
@@ -521,8 +524,9 @@ void initSL(SLVstring& cmdLineArgs)
// setup platform dependent data path
AppDemo::calibFilePath = configDir;
- AppDemo::calibIniPath = projectRoot + "/data/calibrations/"; // for calibInitPath
- CVCapture::instance()->loadCalibrations(Utils::ComputerInfos::get(), AppDemo::calibFilePath); // for calibrations made
+ AppDemo::calibIniPath = projectRoot + "/data/calibrations/";
+ CVCapture::instance()->loadCalibrations(Utils::ComputerInfos::get(),
+ AppDemo::calibFilePath);
/////////////////////////////////////////////////////////
slCreateAppAndScene(cmdLineArgs,
diff --git a/apps/source/SLInterface.h b/apps/source/SLInterface.h
index d58a05d1..084583bb 100644
--- a/apps/source/SLInterface.h
+++ b/apps/source/SLInterface.h
@@ -44,7 +44,7 @@ void slCreateAppAndScene(SLVstring& cmdLineArgs,
const SLstring& configPath,
const SLstring& applicationName,
void* onSceneLoadCallback = nullptr);
-
+//-----------------------------------------------------------------------------
SLint slCreateSceneView(SLAssetManager* am,
SLScene* scene,
int screenWidth,
@@ -57,7 +57,7 @@ SLint slCreateSceneView(SLAssetManager* am,
void* onImGuiBuild = nullptr,
void* onImGuiLoadConfig = nullptr,
void* onImGuiSaveConfig = nullptr);
-
+//-----------------------------------------------------------------------------
SLSceneView* slNewSceneView(SLScene* s, int dotsPerInch, SLInputManager& inputManager);
bool slShouldClose();
void slShouldClose(bool val);
@@ -65,7 +65,7 @@ void slTerminate();
void slResize(int sceneViewIndex, int width, int height);
bool slUpdateParallelJob();
bool slPaintAllViews();
-
+//-----------------------------------------------------------------------------
void slMouseDown(int sceneViewIndex, SLMouseButton button, int x, int y, SLKey modifier);
void slMouseMove(int sceneViewIndex, int x, int y);
void slMouseUp(int sceneViewIndex, SLMouseButton button, int x, int y, SLKey modifier);
@@ -80,7 +80,7 @@ void slMouseWheel(int sceneViewIndex, int pos, SLKey modifier);
void slKeyPress(int sceneViewIndex, SLKey key, SLKey modifier);
void slKeyRelease(int sceneViewIndex, SLKey key, SLKey modifier);
void slCharInput(int sceneViewIndex, unsigned int character);
-
+//-----------------------------------------------------------------------------
bool slUsesRotation();
void slRotationQUAT(float quatX, float quatY, float quatZ, float quatW);
bool slUsesLocation();
diff --git a/modules/sl/source/SLEnums.h b/modules/sl/source/SLEnums.h
index 475a174c..a892a639 100644
--- a/modules/sl/source/SLEnums.h
+++ b/modules/sl/source/SLEnums.h
@@ -166,16 +166,6 @@ enum SLSceneID
SID_RTLens,
SID_RTTest,
- SID_ErlebARBernChristoffel,
- SID_ErlebARBielBFH,
- SID_ErlebARAugustaRauricaTmp,
- SID_ErlebARAugustaRauricaTht,
- SID_ErlebARAugustaRauricaTmpTht,
- SID_ErlebARAventicumAmphiteatre,
- SID_ErlebARAventicumCigognier,
- SID_ErlebARAventicumTheatre,
- SID_ErlebARSutzKirchrain18,
-
SID_ParticleSystem_First,
SID_ParticleSystem_Demo,
SID_ParticleSystem_DustStorm,
@@ -194,7 +184,18 @@ enum SLSceneID
SID_Benchmark8_ParticleSystemFireComplex,
SID_Benchmark9_ParticleSystemManyParticles,
- SID_Maximal
+ SID_Maximal,
+
+ // These scenes are not part of the public data
+ SID_ErlebARBernChristoffel,
+ SID_ErlebARBielBFH,
+ SID_ErlebARAugustaRauricaTmp,
+ SID_ErlebARAugustaRauricaTht,
+ SID_ErlebARAugustaRauricaTmpTht,
+ SID_ErlebARAventicumAmphiteatre,
+ SID_ErlebARAventicumCigognier,
+ SID_ErlebARAventicumTheatre,
+ SID_ErlebARSutzKirchrain18
};
//-----------------------------------------------------------------------------
//! Mouse button codes
diff --git a/modules/sl/source/mesh/SLParticleSystem.cpp b/modules/sl/source/mesh/SLParticleSystem.cpp
index 4104b423..121a6eca 100644
--- a/modules/sl/source/mesh/SLParticleSystem.cpp
+++ b/modules/sl/source/mesh/SLParticleSystem.cpp
@@ -597,12 +597,14 @@ void SLParticleSystem::draw(SLSceneView* sv, SLNode* node, SLuint instances)
/////////////////////////////////////
// Init particles vector and init VAO
/////////////////////////////////////
+
if (!_isGenerated)
generate();
////////////////////
// Generate programs
////////////////////
+
if (!_mat->program() || !_mat->programTF())
_mat->generateProgramPS(_drawInstanced);
From 67ce89050b4ea8dd81d457ea1a6ad10733a91f39 Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Sat, 9 Dec 2023 17:35:52 +0100
Subject: [PATCH 077/108] OpenCV build with included 3rdparties
---
.../build_opencv_w_contrib_for_macArm64.sh | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/externals/prebuild_scripts/build_opencv_w_contrib_for_macArm64.sh b/externals/prebuild_scripts/build_opencv_w_contrib_for_macArm64.sh
index 3f3f5b16..0f56dc7c 100755
--- a/externals/prebuild_scripts/build_opencv_w_contrib_for_macArm64.sh
+++ b/externals/prebuild_scripts/build_opencv_w_contrib_for_macArm64.sh
@@ -73,10 +73,14 @@ cmake \
-DBUILD_TESTS=OFF \
-DWITH_MATLAB=OFF \
-DBUILD_ZLIB=ON \
+-DWITH_PNG=ON \
-DBUILD_PNG=ON \
-DBUILD_JPEG=ON \
+-DWITH_JPEG=ON \
-DBUILD_TIFF=ON \
+-DWITH_WEBP=ON \
-DBUILD_WEBP=ON \
+-DWITH_OPENEXR=ON \
-DBUILD_OPENEXR=ON \
-DOPENCV_ENABLE_NONFREE=ON \
-DOPENCV_EXTRA_MODULES_PATH=../../../opencv_contrib/modules \
@@ -110,10 +114,14 @@ cmake \
-DBUILD_TESTS=OFF \
-DWITH_MATLAB=OFF \
-DBUILD_ZLIB=ON \
+-DWITH_PNG=ON \
-DBUILD_PNG=ON \
-DBUILD_JPEG=ON \
+-DWITH_JPEG=ON \
-DBUILD_TIFF=ON \
+-DWITH_WEBP=ON \
-DBUILD_WEBP=ON \
+-DWITH_OPENEXR=ON \
-DBUILD_OPENEXR=ON \
-DOPENCV_ENABLE_NONFREE=ON \
-DOPENCV_EXTRA_MODULES_PATH=../../../opencv_contrib/modules \
From 7c03129f516a2fbe76853e1e2bfb4c17944e85ab Mon Sep 17 00:00:00 2001
From: Marcus Hudritsch
Date: Sat, 9 Dec 2023 19:29:08 +0100
Subject: [PATCH 078/108] Added onlyErrorLogs cmd line argument
---
.../glfw/AppDemoMainGLFW.cpp | 9 +++
modules/cv/source/CVTrackedFaces.cpp | 58 +++++++++++++------
modules/sl/source/SLSceneView.cpp | 3 +-
modules/sl/source/gl/SLGLProgramGenerated.cpp | 4 --
modules/sl/source/input/SLAssimpImporter.cpp | 6 +-
modules/utils/source/Utils.cpp | 55 +++++++-----------
modules/utils/source/Utils.h | 3 +
7 files changed, 76 insertions(+), 62 deletions(-)
diff --git a/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp b/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
index a45ab392..2d4f98b5 100644
--- a/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
+++ b/apps/app_demo_slproject/glfw/AppDemoMainGLFW.cpp
@@ -567,6 +567,15 @@ int main(int argc, char* argv[])
for (int i = 0; i < argc; i++)
cmdLineArgs.push_back(SLstring(argv[i]));
+ // parse cmd line arguments
+ for (int i=1; i