Revision control
Copy as Markdown
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#version 440
layout (location = 0) in vec3 attr_pos;
// SKIN INSTANCE layouts ####################
#if defined(QSSG_SKIN) && defined(QSSG_INSTANCE)
layout (location = 1) in ivec4 attr_joints;
layout (location = 2) in vec4 attr_weights;
layout (location = 3) in vec4 qt_instanceTransform0;
layout (location = 4) in vec4 qt_instanceTransform1;
layout (location = 5) in vec4 qt_instanceTransform2;
layout (location = 6) in vec4 qt_instanceColor;
layout (location = 7) in vec4 qt_instanceData;
layout (binding = 2) uniform sampler2D qt_boneTexture;
layout (binding = 3) uniform sampler2D lastBoneTexture;
layout (binding = 4) uniform sampler2D lastInstanceTexture;
#ifdef QSSG_MORPH
layout (binding = 5) uniform sampler2D morphWeightTexture;
layout (binding = 6) uniform sampler2D lastMorphWeightTexture;
layout (binding = 7) uniform sampler2DArray qt_morphTargetTexture;
#endif
// SKIN layouts ####################
#elif defined(QSSG_SKIN)
layout (location = 1) in ivec4 attr_joints;
layout (location = 2) in vec4 attr_weights;
layout (binding = 1) uniform sampler2D qt_boneTexture;
layout (binding = 2) uniform sampler2D lastBoneTexture;
#ifdef QSSG_MORPH
layout (binding = 3) uniform sampler2D morphWeightTexture;
layout (binding = 4) uniform sampler2D lastMorphWeightTexture;
layout (binding = 5) uniform sampler2DArray qt_morphTargetTexture;
#endif
// INSTANCE layouts ####################
#elif defined(QSSG_INSTANCE)
layout (location = 1) in vec4 qt_instanceTransform0;
layout (location = 2) in vec4 qt_instanceTransform1;
layout (location = 3) in vec4 qt_instanceTransform2;
layout (location = 4) in vec4 qt_instanceColor;
layout (location = 5) in vec4 qt_instanceData;
layout (binding = 2) uniform sampler2D lastInstanceTexture;
#ifdef QSSG_MORPH
layout (binding = 3) uniform sampler2D morphWeightTexture;
layout (binding = 4) uniform sampler2D lastMorphWeightTexture;
layout (binding = 5) uniform sampler2DArray qt_morphTargetTexture;
#endif
// BASE layouts ####################
#else
#ifdef QSSG_MORPH
layout (binding = 1) uniform sampler2D morphWeightTexture;
layout (binding = 2) uniform sampler2D lastMorphWeightTexture;
layout (binding = 3) uniform sampler2DArray qt_morphTargetTexture;
#endif
#endif
out gl_PerVertex { vec4 gl_Position; };
layout (location = 0) out vec4 vPosition;
layout (location = 1) out vec4 vPrevPosition;
layout (std140, binding = 0) uniform buf {
mat4 mvp;
mat4 prevMVP;
mat4 instanceLocal;
mat4 instanceGlobal;
mat4 prevInstanceLocal;
mat4 prevInstanceGlobal;
vec4 currentAndLastJitter;
float velocityAmount;
int morphTargetCount;
vec2 padding;
} ubuf;
#if defined(QSSG_SKIN) || defined(QSSG_INSTANCE)
mat4 getTexMatrix(int index, sampler2D textureStorage)
{
mat4 ret;
int width = textureSize(textureStorage, 0).x;
int matId = index * 4;
ivec2 p;
// Rounding mode of integers is undefined for GLES 3.0
// https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf (section 12.33)
p.x = matId % width;
p.y = (matId - p.x) / width;
ret[0] = texelFetch(textureStorage, p, 0);
p.x = (matId + 1) % width;
p.y = (matId + 1 - p.x) / width;
ret[1] = texelFetch(textureStorage, p, 0);
p.x = (matId + 2) % width;
p.y = (matId + 2 - p.x) / width;
ret[2] = texelFetch(textureStorage, p, 0);
p.x = (matId + 3) % width;
p.y = (matId + 3 - p.x) / width;
ret[3] = texelFetch(textureStorage, p, 0);
return ret;
}
#endif
#ifdef QSSG_SKIN
mat4 getSkinMatrix(ivec4 joints, vec4 weights, sampler2D boneTexture)
{
return getTexMatrix(joints.x * 2, boneTexture) * weights.x
+ getTexMatrix(joints.y * 2, boneTexture) * weights.y
+ getTexMatrix(joints.z * 2, boneTexture) * weights.z
+ getTexMatrix(joints.w * 2, boneTexture) * weights.w;
}
#endif
#ifdef QSSG_MORPH
vec4 getTargetTexValue(ivec3 texCoord, sampler2DArray targetTexture)
{
return texelFetch(targetTexture, texCoord, 0);
}
vec4 qt_getTargetValue(vec4 orgValue, int offset, sampler2DArray targetTexture, sampler2D weightTexture)
{
vec4 result = orgValue;
ivec3 texCoord;
int texWidth = textureSize(targetTexture, 0).x;
texCoord.x = gl_VertexIndex % texWidth;
texCoord.y = (gl_VertexIndex - texCoord.x) / texWidth;
for (int i = 0; i < ubuf.morphTargetCount; ++i) {
texCoord.z = offset + i;
vec4 targetValue = getTargetTexValue(texCoord, targetTexture);
result += texelFetch(weightTexture, ivec2(i, 0), 0).x * (targetValue - orgValue);
}
return vec4(result.xyz, 1.);
}
#endif
void main()
{
vec4 vp = vec4(attr_pos, 1.0);
vec4 vpPre = vec4(attr_pos, 1.0);
#ifdef QSSG_MORPH
vp = qt_getTargetValue(vp, 0, qt_morphTargetTexture, morphWeightTexture);
vpPre = qt_getTargetValue(vpPre, 0, qt_morphTargetTexture, lastMorphWeightTexture);
#endif
#ifdef QSSG_INSTANCE
mat4 instanceMat = transpose(mat4(qt_instanceTransform0,
qt_instanceTransform1,
qt_instanceTransform2,
vec4(0.0, 0.0, 0.0, 1.0)));
mat4 lastInstanceMat = getTexMatrix(gl_InstanceIndex, lastInstanceTexture);
instanceMat = ubuf.instanceGlobal * instanceMat;
lastInstanceMat = ubuf.prevInstanceGlobal * lastInstanceMat;
#ifndef QSSG_SKIN
instanceMat *= ubuf.instanceLocal;
lastInstanceMat *= ubuf.prevInstanceLocal;
#endif
vpPre = instanceMat * vpPre;
vp = lastInstanceMat * vp;
#endif
#ifdef QSSG_SKIN
if (attr_weights != vec4(0.0)) {
mat4 skinMat = getSkinMatrix(attr_joints, attr_weights, qt_boneTexture);
vp = skinMat * vp;
mat4 lastSkinMat = getSkinMatrix(attr_joints, attr_weights, lastBoneTexture);
vpPre = lastSkinMat * vpPre;
}
#endif
gl_Position = vPosition = ubuf.mvp * vp;
vPrevPosition = ubuf.prevMVP * vpPre;
}