Skip to content

Commit f477a6f

Browse files
committed
WebGPURenderer: Improve vertex format support.
1 parent cf6b962 commit f477a6f

File tree

4 files changed

+114
-122
lines changed

4 files changed

+114
-122
lines changed

examples/jsm/nodes/core/AttributeNode.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class AttributeNode extends Node {
3030

3131
const attribute = builder.geometry.getAttribute( attributeName );
3232

33-
nodeType = builder.getTypeFromLength( attribute.itemSize );
33+
nodeType = builder.getTypeFromAttribute( attribute );
3434

3535
} else {
3636

@@ -66,23 +66,26 @@ class AttributeNode extends Node {
6666

6767
if ( geometryAttribute === true ) {
6868

69-
const nodeAttribute = builder.getAttribute( attributeName, nodeType );
69+
const attribute = builder.geometry.getAttribute( attributeName );
70+
const attributeType = builder.getTypeFromAttribute( attribute );
71+
72+
const nodeAttribute = builder.getAttribute( attributeName, attributeType );
7073

7174
if ( builder.isShaderStage( 'vertex' ) ) {
7275

73-
return nodeAttribute.name;
76+
return builder.format( nodeAttribute.name, attributeType, nodeType );
7477

7578
} else {
7679

7780
const nodeVarying = varying( this );
7881

79-
return nodeVarying.build( builder, nodeAttribute.type );
82+
return nodeVarying.build( builder, nodeType );
8083

8184
}
8285

8386
} else {
8487

85-
console.warn( `Attribute "${ attributeName }" not found.` );
88+
console.warn( `AttributeNode: Attribute "${ attributeName }" not found.` );
8689

8790
return builder.getConst( nodeType );
8891

examples/jsm/nodes/core/NodeBuilder.js

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ import NodeKeywords from './NodeKeywords.js';
77
import NodeCache from './NodeCache.js';
88
import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js';
99

10-
import { REVISION, NoColorSpace, LinearEncoding, sRGBEncoding, SRGBColorSpace, Color, Vector2, Vector3, Vector4 } from 'three';
10+
import { REVISION, NoColorSpace, LinearEncoding, sRGBEncoding, SRGBColorSpace, Color, Vector2, Vector3, Vector4, Float16BufferAttribute } from 'three';
1111

1212
import { stack } from './StackNode.js';
1313
import { maxMipLevel } from '../utils/MaxMipLevelNode.js';
1414

15-
const typeFromLength = new Map();
16-
typeFromLength.set( 2, 'vec2' );
17-
typeFromLength.set( 3, 'vec3' );
18-
typeFromLength.set( 4, 'vec4' );
19-
typeFromLength.set( 9, 'mat3' );
20-
typeFromLength.set( 16, 'mat4' );
15+
const typeFromLength = new Map( [
16+
[ 2, 'vec2' ],
17+
[ 3, 'vec3' ],
18+
[ 4, 'vec4' ],
19+
[ 9, 'mat3' ],
20+
[ 16, 'mat4' ]
21+
] );
22+
23+
const typeFromArray = new Map( [
24+
[ Int8Array, 'int' ],
25+
[ Int16Array, 'int' ],
26+
[ Int32Array, 'int' ],
27+
[ Uint8Array, 'uint' ],
28+
[ Uint16Array, 'uint' ],
29+
[ Uint32Array, 'uint' ],
30+
[ Float32Array, 'float' ]
31+
] );
2132

2233
const toFloat = ( value ) => {
2334

@@ -412,12 +423,42 @@ class NodeBuilder {
412423
getTypeFromLength( length, componentType = 'float' ) {
413424

414425
if ( length === 1 ) return componentType;
426+
415427
const baseType = typeFromLength.get( length );
416428
const prefix = componentType === 'float' ? '' : componentType[ 0 ];
429+
417430
return prefix + baseType;
418431

419432
}
420433

434+
getTypeFromArray( array ) {
435+
436+
return typeFromArray.get( array.constructor );
437+
438+
}
439+
440+
getTypeFromAttribute( attribute ) {
441+
442+
let dataAttribute = attribute;
443+
444+
if ( attribute.isInterleavedBufferAttribute ) dataAttribute = attribute.data;
445+
446+
const array = dataAttribute.array;
447+
const itemSize = dataAttribute.stride || attribute.itemSize;
448+
const normalized = attribute.normalized;
449+
450+
let arrayType;
451+
452+
if ( ! ( attribute instanceof Float16BufferAttribute ) && normalized !== true ) {
453+
454+
arrayType = this.getTypeFromArray( array );
455+
456+
}
457+
458+
return this.getTypeFromLength( itemSize, arrayType );
459+
460+
}
461+
421462
getTypeLength( type ) {
422463

423464
const vecType = this.getVectorType( type );
@@ -677,7 +718,7 @@ class NodeBuilder {
677718

678719
if ( propertyName !== null ) {
679720

680-
flowData.code += `${propertyName} = ${flowData.result};\n` + this.tab;
721+
flowData.code += `${ this.tab + propertyName } = ${ flowData.result };\n`;
681722

682723
}
683724

@@ -864,7 +905,7 @@ class NodeBuilder {
864905

865906
if ( fromTypeLength > toTypeLength ) {
866907

867-
return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength ), toType );
908+
return this.format( `${ snippet }.${ 'xyz'.slice( 0, toTypeLength ) }`, this.getTypeFromLength( toTypeLength, this.getComponentType( fromType ) ), toType );
868909

869910
}
870911

examples/jsm/renderers/webgpu/WebGPUAttributes.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ class WebGPUAttributes {
99

1010
get( attribute ) {
1111

12-
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
12+
attribute = this._getAttribute( attribute );
1313

1414
return this.buffers.get( attribute );
1515

1616
}
1717

1818
remove( attribute ) {
1919

20-
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
20+
attribute = this._getAttribute( attribute );
2121

2222
const data = this.buffers.get( attribute );
2323

@@ -33,7 +33,7 @@ class WebGPUAttributes {
3333

3434
update( attribute, isIndex = false, usage = null ) {
3535

36-
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
36+
attribute = this._getAttribute( attribute );
3737

3838
let data = this.buffers.get( attribute );
3939

@@ -115,6 +115,14 @@ class WebGPUAttributes {
115115

116116
}
117117

118+
_getAttribute( attribute ) {
119+
120+
if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
121+
122+
return attribute;
123+
124+
}
125+
118126
_createBuffer( attribute, usage ) {
119127

120128
const array = attribute.array;

examples/jsm/renderers/webgpu/WebGPURenderPipeline.js

Lines changed: 45 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUVertexFormat, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
1+
import { GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
22
import {
3+
Float16BufferAttribute,
34
FrontSide, BackSide, DoubleSide,
45
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
56
NeverStencilFunc, AlwaysStencilFunc, LessStencilFunc, LessEqualStencilFunc, EqualStencilFunc, GreaterEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc,
@@ -9,6 +10,26 @@ import {
910
ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor
1011
} from 'three';
1112

13+
const typedArraysToVertexFormatPrefix = new Map( [
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+
const typedAttributeToVertexFormatPrefix = new Map( [
24+
[ Float16BufferAttribute, [ 'float16', ]],
25+
] );
26+
27+
const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [
28+
[ Int32Array, 'sint32' ],
29+
[ Uint32Array, 'uint32' ],
30+
[ Float32Array, 'float32' ]
31+
] );
32+
1233
class WebGPURenderPipeline {
1334

1435
constructor( device, utils ) {
@@ -561,127 +582,48 @@ class WebGPURenderPipeline {
561582

562583
}
563584

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

612-
return GPUVertexFormat.Sint16x2;
587+
const { itemSize, normalized } = geometryAttribute;
588+
const ArrayType = geometryAttribute.array.constructor;
589+
const AttributeType = geometryAttribute.constructor;
613590

614-
} else {
591+
let format;
615592

616-
return GPUVertexFormat.Sint32x2;
593+
if ( itemSize == 1 ) {
617594

618-
}
619-
620-
}
621-
622-
if ( type === 'ivec3' ) return GPUVertexFormat.Sint32x3;
623-
624-
if ( type === 'ivec4' ) {
625-
626-
if ( bytesPerElement === 1 ) {
627-
628-
return GPUVertexFormat.Sint8x4;
629-
630-
} else if ( bytesPerElement === 2 ) {
631-
632-
return GPUVertexFormat.Sint16x4;
633-
634-
} else {
635-
636-
return GPUVertexFormat.Sint32x4;
637-
638-
}
639-
640-
}
641-
642-
// uint
595+
format = typeArraysToVertexFormatPrefixForItemSize1.get( ArrayType );
643596

644-
if ( type === 'uint' ) return GPUVertexFormat.Uint32;
645-
646-
if ( type === 'uvec2' ) {
597+
} else {
647598

648-
if ( bytesPerElement === 1 ) {
599+
const prefixOptions = typedAttributeToVertexFormatPrefix.get( AttributeType ) || typedArraysToVertexFormatPrefix.get( ArrayType );
600+
const prefix = prefixOptions[ normalized ? 1 : 0 ];
601+
console.log( prefix );
602+
if ( prefix ) {
649603

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

652-
} else if ( bytesPerElement === 2 ) {
608+
if ( paddedItemSize % 1 ) {
653609

654-
return GPUVertexFormat.Uint16x2;
610+
throw new Error( `bad item size ` );
655611

656-
} else {
612+
}
657613

658-
return GPUVertexFormat.Uint32x2;
614+
format = `${prefix}x${paddedItemSize}`;
659615

660616
}
661617

662618
}
663619

664-
if ( type === 'uvec3' ) return GPUVertexFormat.Uint32x3;
665-
666-
if ( type === 'uvec4' ) {
667-
668-
if ( bytesPerElement === 1 ) {
620+
if ( ! format ) {
669621

670-
return GPUVertexFormat.Uint8x4;
671-
672-
} else if ( bytesPerElement === 2 ) {
673-
674-
return GPUVertexFormat.Uint16x4;
675-
676-
} else {
677-
678-
return GPUVertexFormat.Uint32x4;
679-
680-
}
622+
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.' );
681623

682624
}
683625

684-
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
626+
return format;
685627

686628
}
687629

@@ -693,14 +635,12 @@ class WebGPURenderPipeline {
693635
for ( let slot = 0; slot < nodeAttributes.length; slot ++ ) {
694636

695637
const nodeAttribute = nodeAttributes[ slot ];
696-
697638
const name = nodeAttribute.name;
698-
const type = nodeAttribute.type;
699639

700640
const geometryAttribute = geometry.getAttribute( name );
701641
const bytesPerElement = geometryAttribute.array.BYTES_PER_ELEMENT;
702642

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

705645
let arrayStride = geometryAttribute.itemSize * bytesPerElement;
706646
let offset = 0;

0 commit comments

Comments
 (0)