Skip to content

Commit 6dd385a

Browse files
committed
Wrong fix for WebGPU gLTF support
This works but is probably the wrong fix. I don't know three.js that well so I thought I'd post this as an example of a fix and it might lead to the correct fix. The issue is WebGPU does not support itemSize = 1 or itemSize = 3 for 8bit or 16bit values. When using KHR_mesh_quantization some attributes are like Int16x3. But, according to the KHR_mesh_quantization spec they are actually padded to Int16x4 In WebGL it's fine to set the attribute to ``` size = 3, type = gl.SHORT, normalize = true, stride = 8. ``` But in WebGPU there is no such thing as `size = 3, type = gl.SHORT` If it existed it would be called `sint16x3` or `uint16x3` or `snorm16x3` or `unorm16x3` but none of those exist. Instead you have to set the attribute to `???x4` for these situations. You then need to be careful the shader doesn't actually use Z. The shader can still declare its attribute has vec3f/vec3<f32> but if it declares it as vec4/vec4<f32> the z value would be undefined (whatever happens to be in the file in the padding) My guess is the correct fix, rather than this hack which expands the type, it should look at the stride. The stride to figure out when to expand the type from x3 to x4 or from x1 to x2 or x1 to x4
1 parent 2236516 commit 6dd385a

File tree

1 file changed

+41
-102
lines changed

1 file changed

+41
-102
lines changed

examples/jsm/renderers/webgpu/WebGPURenderPipeline.js

Lines changed: 41 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ import {
99
ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor
1010
} from 'three';
1111

12+
const typedArraysToVertexFormatPrefix = new Map( [
13+
14+
[ Int8Array, [ 'sint8', 'snorm8' ] ],
15+
[ Uint8Array, [ 'uint8', 'unorm8' ] ],
16+
[ Int16Array, [ 'sint16', 'snorm16' ] ],
17+
[ Uint16Array, [ 'uint16', 'unorm16' ] ],
18+
[ Int32Array, [ 'sint32', 'snorm32' ] ],
19+
[ Uint32Array, [ 'uint32', 'unorm32' ] ],
20+
[ Float32Array, [ 'float32', ] ],
21+
22+
] );
23+
24+
const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [
25+
26+
[ Int32Array, 'sint32' ],
27+
[ Uint32Array, 'uint32' ],
28+
[ Float32Array, 'float32' ],
29+
30+
] );
31+
1232
class WebGPURenderPipeline {
1333

1434
constructor( device, utils ) {
@@ -563,127 +583,46 @@ class WebGPURenderPipeline {
563583

564584
}
565585

566-
_getVertexFormat( type, bytesPerElement ) {
567-
568-
// float
569-
570-
if ( type === 'float' ) return GPUVertexFormat.Float32;
571-
572-
if ( type === 'vec2' ) {
573-
574-
if ( bytesPerElement === 2 ) {
575-
576-
return GPUVertexFormat.Float16x2;
577-
578-
} else {
579-
580-
return GPUVertexFormat.Float32x2;
581-
582-
}
583-
584-
}
585-
586-
if ( type === 'vec3' ) return GPUVertexFormat.Float32x3;
587-
588-
if ( type === 'vec4' ) {
589-
590-
if ( bytesPerElement === 2 ) {
591-
592-
return GPUVertexFormat.Float16x4;
593-
594-
} else {
595-
596-
return GPUVertexFormat.Float32x4;
597-
598-
}
599-
600-
}
601-
602-
// int
603-
604-
if ( type === 'int' ) return GPUVertexFormat.Sint32;
605-
606-
if ( type === 'ivec2' ) {
607-
608-
if ( bytesPerElement === 1 ) {
586+
_getVertexFormat( geometryAttribute ) {
609587

610-
return GPUVertexFormat.Sint8x2;
588+
const { itemSize, normalized } = geometryAttribute;
589+
const ArrayType = geometryAttribute.array.__proto__.constructor;
611590

612-
} else if ( bytesPerElement === 2 ) {
591+
let format;
613592

614-
return GPUVertexFormat.Sint16x2;
593+
if ( itemSize == 1 ) {
615594

616-
} else {
595+
format = typeArraysToVertexFormatPrefixForItemSize1.get(ArrayType)
617596

618-
return GPUVertexFormat.Sint32x2;
619-
620-
}
621-
622-
}
623-
624-
if ( type === 'ivec3' ) return GPUVertexFormat.Sint32x3;
625-
626-
if ( type === 'ivec4' ) {
627-
628-
if ( bytesPerElement === 1 ) {
629-
630-
return GPUVertexFormat.Sint8x4;
631-
632-
} else if ( bytesPerElement === 2 ) {
633-
634-
return GPUVertexFormat.Sint16x4;
635-
636-
} else {
637-
638-
return GPUVertexFormat.Sint32x4;
639-
640-
}
641-
642-
}
643-
644-
// uint
645-
646-
if ( type === 'uint' ) return GPUVertexFormat.Uint32;
597+
} else {
647598

648-
if ( type === 'uvec2' ) {
599+
const prefix = typedArraysToVertexFormatPrefix.get(ArrayType)[ normalized ? 1 : 0 ];
649600

650-
if ( bytesPerElement === 1 ) {
601+
if ( prefix ) {
651602

652-
return GPUVertexFormat.Uint8x2;
603+
const bytesPerUnit = ArrayType.BYTES_PER_ELEMENT * itemSize;
604+
const paddedBytesPerUnit = Math.floor( ( bytesPerUnit + 3 ) / 4 ) * 4;
605+
const paddedItemSize = paddedBytesPerUnit / ArrayType.BYTES_PER_ELEMENT;
653606

654-
} else if ( bytesPerElement === 2 ) {
607+
if ( paddedItemSize % 1) {
655608

656-
return GPUVertexFormat.Uint16x2;
609+
throw new Error( `bad item size `);
657610

658-
} else {
611+
}
659612

660-
return GPUVertexFormat.Uint32x2;
613+
format = `${prefix}x${paddedItemSize}`;
661614

662615
}
663616

664617
}
665618

666-
if ( type === 'uvec3' ) return GPUVertexFormat.Uint32x3;
667-
668-
if ( type === 'uvec4' ) {
669-
670-
if ( bytesPerElement === 1 ) {
671-
672-
return GPUVertexFormat.Uint8x4;
619+
if ( !format ) {
673620

674-
} else if ( bytesPerElement === 2 ) {
675-
676-
return GPUVertexFormat.Uint16x4;
677-
678-
} else {
679-
680-
return GPUVertexFormat.Uint32x4;
681-
682-
}
621+
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.' );
683622

684623
}
685624

686-
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
625+
return format;
687626

688627
}
689628

@@ -700,10 +639,10 @@ class WebGPURenderPipeline {
700639
const type = nodeAttribute.type;
701640

702641
const geometryAttribute = geometry.getAttribute( name );
703-
const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT;
704642

705-
const format = this._getVertexFormat( type, bytesPerElement );
643+
const format = this._getVertexFormat( geometryAttribute );
706644

645+
const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT;
707646
let arrayStride = geometryAttribute.itemSize * bytesPerElement;
708647
let offset = 0;
709648

0 commit comments

Comments
 (0)