gpu-curtains
Version:
gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.
96 lines (88 loc) • 3.64 kB
JavaScript
const getVertexSkinnedPositionNormal = ({ bindings = [], geometry }) => {
let output = "";
const hasInstances = geometry.instancesCount > 1 && bindings.find((binding) => binding.name === "instances");
const skinJoints = [];
const skinWeights = [];
if (geometry.vertexBuffers && geometry.vertexBuffers.length) {
geometry.vertexBuffers.forEach((vertexBuffer) => {
vertexBuffer.attributes.forEach((attribute) => {
if (attribute.name.includes("joints")) {
skinJoints.push(attribute);
}
if (attribute.name.includes("weights")) {
skinWeights.push(attribute);
}
});
});
}
const skinBindings = bindings.filter((binding) => binding.name.includes("skin"));
const hasSkin = skinJoints.length && skinWeights.length && skinBindings.length;
if (hasSkin) {
output += hasInstances ? `
var instancesWorldPosition = array<vec4f, ${geometry.instancesCount}>();
var instancesNormal = array<vec3f, ${geometry.instancesCount}>();
` : "";
output += `
let skinJoints: vec4f = ${skinJoints.map((skinJoint) => skinJoint.name).join(" + ")};`;
output += `
var skinWeights: vec4f = ${skinWeights.map((skinWeight) => skinWeight.name).join(" + ")};
let skinWeightsSum = dot(skinWeights, vec4(1.0));
if(skinWeightsSum > 0.0) {
skinWeights = skinWeights / skinWeightsSum;
}
`;
skinBindings.forEach((binding, bindingIndex) => {
output += /* wgsl */
`
${hasInstances ? "// instancing with different skins: joints calculations for skin " + bindingIndex + "\n" : ""}
// position
let skinMatrix_${bindingIndex}: mat4x4f =
skinWeights.x * ${binding.name}.joints[u32(skinJoints.x)].jointMatrix +
skinWeights.y * ${binding.name}.joints[u32(skinJoints.y)].jointMatrix +
skinWeights.z * ${binding.name}.joints[u32(skinJoints.z)].jointMatrix +
skinWeights.w * ${binding.name}.joints[u32(skinJoints.w)].jointMatrix;
${hasInstances ? "instancesWorldPosition[" + bindingIndex + "] = skinMatrix_" + bindingIndex + " * worldPosition;" : "worldPosition = skinMatrix_" + bindingIndex + " * worldPosition;"}
// normal
let skinNormalMatrix_${bindingIndex}: mat4x4f =
skinWeights.x * ${binding.name}.joints[u32(skinJoints.x)].normalMatrix +
skinWeights.y * ${binding.name}.joints[u32(skinJoints.y)].normalMatrix +
skinWeights.z * ${binding.name}.joints[u32(skinJoints.z)].normalMatrix +
skinWeights.w * ${binding.name}.joints[u32(skinJoints.w)].normalMatrix;
let skinNormalMatrix_${bindingIndex}_3: mat3x3f = mat3x3f(
vec3(skinNormalMatrix_${bindingIndex}[0].xyz),
vec3(skinNormalMatrix_${bindingIndex}[1].xyz),
vec3(skinNormalMatrix_${bindingIndex}[2].xyz)
);
${hasInstances ? "instancesNormal[" + bindingIndex + "] = skinNormalMatrix_" + bindingIndex + "_3 * normal;" : "normal = skinNormalMatrix_" + bindingIndex + "_3 * normal;"}
`;
});
}
output += /* wgsl */
`
var modelMatrix: mat4x4f;
`;
if (hasInstances) {
if (hasSkin) {
output += /* wgsl */
`
worldPosition = instancesWorldPosition[instanceIndex];
normal = instancesNormal[instanceIndex];
`;
}
output += /* wgsl */
`
modelMatrix = instances.matrices[instanceIndex].model;
worldPosition = modelMatrix * worldPosition;
normal = normalize(instances.matrices[instanceIndex].normal * normal);
`;
} else {
output += /* wgsl */
`
modelMatrix = matrices.model;
worldPosition = modelMatrix * worldPosition;
normal = getWorldNormal(normal);
`;
}
return output;
};
export { getVertexSkinnedPositionNormal };