You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
745 lines
17 KiB
745 lines
17 KiB
import { GPUPrimitiveTopology, GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUVertexFormat, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
|
|
import {
|
|
FrontSide, BackSide, DoubleSide,
|
|
NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
|
|
NeverStencilFunc, AlwaysStencilFunc, LessStencilFunc, LessEqualStencilFunc, EqualStencilFunc, GreaterEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc,
|
|
KeepStencilOp, ZeroStencilOp, ReplaceStencilOp, InvertStencilOp, IncrementStencilOp, DecrementStencilOp, IncrementWrapStencilOp, DecrementWrapStencilOp,
|
|
NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending,
|
|
AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation,
|
|
ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor
|
|
} from 'three';
|
|
|
|
class WebGPURenderPipeline {
|
|
|
|
constructor( device, renderer, sampleCount ) {
|
|
|
|
this.cacheKey = null;
|
|
this.shaderAttributes = null;
|
|
this.stageVertex = null;
|
|
this.stageFragment = null;
|
|
this.usedTimes = 0;
|
|
|
|
this._device = device;
|
|
this._renderer = renderer;
|
|
this._sampleCount = sampleCount;
|
|
|
|
}
|
|
|
|
init( cacheKey, stageVertex, stageFragment, object, nodeBuilder ) {
|
|
|
|
const material = object.material;
|
|
const geometry = object.geometry;
|
|
|
|
// determine shader attributes
|
|
|
|
const shaderAttributes = this._parseShaderAttributes( nodeBuilder.vertexShader, geometry );
|
|
|
|
// vertex buffers
|
|
|
|
const vertexBuffers = [];
|
|
|
|
for ( const attribute of shaderAttributes ) {
|
|
|
|
const name = attribute.name;
|
|
const geometryAttribute = geometry.getAttribute( name );
|
|
const stepMode = ( geometryAttribute !== undefined && geometryAttribute.isInstancedBufferAttribute ) ? GPUInputStepMode.Instance : GPUInputStepMode.Vertex;
|
|
|
|
vertexBuffers.push( {
|
|
arrayStride: attribute.arrayStride,
|
|
attributes: [ { shaderLocation: attribute.slot, offset: 0, format: attribute.format } ],
|
|
stepMode: stepMode
|
|
} );
|
|
|
|
}
|
|
|
|
this.cacheKey = cacheKey;
|
|
this.shaderAttributes = shaderAttributes;
|
|
this.stageVertex = stageVertex;
|
|
this.stageFragment = stageFragment;
|
|
|
|
// blending
|
|
|
|
let alphaBlend = {};
|
|
let colorBlend = {};
|
|
|
|
if ( material.transparent === true && material.blending !== NoBlending ) {
|
|
|
|
alphaBlend = this._getAlphaBlend( material );
|
|
colorBlend = this._getColorBlend( material );
|
|
|
|
}
|
|
|
|
// stencil
|
|
|
|
let stencilFront = {};
|
|
|
|
if ( material.stencilWrite === true ) {
|
|
|
|
stencilFront = {
|
|
compare: this._getStencilCompare( material ),
|
|
failOp: this._getStencilOperation( material.stencilFail ),
|
|
depthFailOp: this._getStencilOperation( material.stencilZFail ),
|
|
passOp: this._getStencilOperation( material.stencilZPass )
|
|
};
|
|
|
|
}
|
|
|
|
//
|
|
|
|
const primitiveState = this._getPrimitiveState( object, material );
|
|
const colorWriteMask = this._getColorWriteMask( material );
|
|
const depthCompare = this._getDepthCompare( material );
|
|
const colorFormat = this._renderer.getCurrentColorFormat();
|
|
const depthStencilFormat = this._renderer.getCurrentDepthStencilFormat();
|
|
|
|
this.pipeline = this._device.createRenderPipeline( {
|
|
vertex: Object.assign( {}, stageVertex.stage, { buffers: vertexBuffers } ),
|
|
fragment: Object.assign( {}, stageFragment.stage, { targets: [ {
|
|
format: colorFormat,
|
|
blend: {
|
|
alpha: alphaBlend,
|
|
color: colorBlend
|
|
},
|
|
writeMask: colorWriteMask
|
|
} ] } ),
|
|
primitive: primitiveState,
|
|
depthStencil: {
|
|
format: depthStencilFormat,
|
|
depthWriteEnabled: material.depthWrite,
|
|
depthCompare: depthCompare,
|
|
stencilFront: stencilFront,
|
|
stencilBack: {}, // three.js does not provide an API to configure the back function (gl.stencilFuncSeparate() was never used)
|
|
stencilReadMask: material.stencilFuncMask,
|
|
stencilWriteMask: material.stencilWriteMask
|
|
},
|
|
multisample: {
|
|
count: this._sampleCount
|
|
}
|
|
} );
|
|
|
|
}
|
|
|
|
_getArrayStride( type, bytesPerElement ) {
|
|
|
|
// @TODO: This code is GLSL specific. We need to update when we switch to WGSL.
|
|
|
|
if ( type === 'float' || type === 'int' || type === 'uint' ) return bytesPerElement;
|
|
if ( type === 'vec2' || type === 'ivec2' || type === 'uvec2' ) return bytesPerElement * 2;
|
|
if ( type === 'vec3' || type === 'ivec3' || type === 'uvec3' ) return bytesPerElement * 3;
|
|
if ( type === 'vec4' || type === 'ivec4' || type === 'uvec4' ) return bytesPerElement * 4;
|
|
|
|
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
|
|
|
|
}
|
|
|
|
_getAlphaBlend( material ) {
|
|
|
|
const blending = material.blending;
|
|
const premultipliedAlpha = material.premultipliedAlpha;
|
|
|
|
let alphaBlend = undefined;
|
|
|
|
switch ( blending ) {
|
|
|
|
case NormalBlending:
|
|
|
|
if ( premultipliedAlpha === false ) {
|
|
|
|
alphaBlend = {
|
|
srcFactor: GPUBlendFactor.One,
|
|
dstFactor: GPUBlendFactor.OneMinusSrcAlpha,
|
|
operation: GPUBlendOperation.Add
|
|
};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AdditiveBlending:
|
|
// no alphaBlend settings
|
|
break;
|
|
|
|
case SubtractiveBlending:
|
|
|
|
if ( premultipliedAlpha === true ) {
|
|
|
|
alphaBlend = {
|
|
srcFactor: GPUBlendFactor.OneMinusSrcColor,
|
|
dstFactor: GPUBlendFactor.OneMinusSrcAlpha,
|
|
operation: GPUBlendOperation.Add
|
|
};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MultiplyBlending:
|
|
if ( premultipliedAlpha === true ) {
|
|
|
|
alphaBlend = {
|
|
srcFactor: GPUBlendFactor.Zero,
|
|
dstFactor: GPUBlendFactor.SrcAlpha,
|
|
operation: GPUBlendOperation.Add
|
|
};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CustomBlending:
|
|
|
|
const blendSrcAlpha = material.blendSrcAlpha;
|
|
const blendDstAlpha = material.blendDstAlpha;
|
|
const blendEquationAlpha = material.blendEquationAlpha;
|
|
|
|
if ( blendSrcAlpha !== null && blendDstAlpha !== null && blendEquationAlpha !== null ) {
|
|
|
|
alphaBlend = {
|
|
srcFactor: this._getBlendFactor( blendSrcAlpha ),
|
|
dstFactor: this._getBlendFactor( blendDstAlpha ),
|
|
operation: this._getBlendOperation( blendEquationAlpha )
|
|
};
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Blending not supported.', blending );
|
|
|
|
}
|
|
|
|
return alphaBlend;
|
|
|
|
}
|
|
|
|
_getBlendFactor( blend ) {
|
|
|
|
let blendFactor;
|
|
|
|
switch ( blend ) {
|
|
|
|
case ZeroFactor:
|
|
blendFactor = GPUBlendFactor.Zero;
|
|
break;
|
|
|
|
case OneFactor:
|
|
blendFactor = GPUBlendFactor.One;
|
|
break;
|
|
|
|
case SrcColorFactor:
|
|
blendFactor = GPUBlendFactor.SrcColor;
|
|
break;
|
|
|
|
case OneMinusSrcColorFactor:
|
|
blendFactor = GPUBlendFactor.OneMinusSrcColor;
|
|
break;
|
|
|
|
case SrcAlphaFactor:
|
|
blendFactor = GPUBlendFactor.SrcAlpha;
|
|
break;
|
|
|
|
case OneMinusSrcAlphaFactor:
|
|
blendFactor = GPUBlendFactor.OneMinusSrcAlpha;
|
|
break;
|
|
|
|
case DstColorFactor:
|
|
blendFactor = GPUBlendFactor.DstColor;
|
|
break;
|
|
|
|
case OneMinusDstColorFactor:
|
|
blendFactor = GPUBlendFactor.OneMinusDstColor;
|
|
break;
|
|
|
|
case DstAlphaFactor:
|
|
blendFactor = GPUBlendFactor.DstAlpha;
|
|
break;
|
|
|
|
case OneMinusDstAlphaFactor:
|
|
blendFactor = GPUBlendFactor.OneMinusDstAlpha;
|
|
break;
|
|
|
|
case SrcAlphaSaturateFactor:
|
|
blendFactor = GPUBlendFactor.SrcAlphaSaturated;
|
|
break;
|
|
|
|
case BlendColorFactor:
|
|
blendFactor = GPUBlendFactor.BlendColor;
|
|
break;
|
|
|
|
case OneMinusBlendColorFactor:
|
|
blendFactor = GPUBlendFactor.OneMinusBlendColor;
|
|
break;
|
|
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Blend factor not supported.', blend );
|
|
|
|
}
|
|
|
|
return blendFactor;
|
|
|
|
}
|
|
|
|
_getBlendOperation( blendEquation ) {
|
|
|
|
let blendOperation;
|
|
|
|
switch ( blendEquation ) {
|
|
|
|
case AddEquation:
|
|
blendOperation = GPUBlendOperation.Add;
|
|
break;
|
|
|
|
case SubtractEquation:
|
|
blendOperation = GPUBlendOperation.Subtract;
|
|
break;
|
|
|
|
case ReverseSubtractEquation:
|
|
blendOperation = GPUBlendOperation.ReverseSubtract;
|
|
break;
|
|
|
|
case MinEquation:
|
|
blendOperation = GPUBlendOperation.Min;
|
|
break;
|
|
|
|
case MaxEquation:
|
|
blendOperation = GPUBlendOperation.Max;
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Blend equation not supported.', blendEquation );
|
|
|
|
}
|
|
|
|
return blendOperation;
|
|
|
|
}
|
|
|
|
_getColorBlend( material ) {
|
|
|
|
const blending = material.blending;
|
|
const premultipliedAlpha = material.premultipliedAlpha;
|
|
|
|
const colorBlend = {
|
|
srcFactor: null,
|
|
dstFactor: null,
|
|
operation: null
|
|
};
|
|
|
|
switch ( blending ) {
|
|
|
|
case NormalBlending:
|
|
|
|
colorBlend.srcFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.One : GPUBlendFactor.SrcAlpha;
|
|
colorBlend.dstFactor = GPUBlendFactor.OneMinusSrcAlpha;
|
|
colorBlend.operation = GPUBlendOperation.Add;
|
|
break;
|
|
|
|
case AdditiveBlending:
|
|
colorBlend.srcFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.One : GPUBlendFactor.SrcAlpha;
|
|
colorBlend.operation = GPUBlendOperation.Add;
|
|
break;
|
|
|
|
case SubtractiveBlending:
|
|
colorBlend.srcFactor = GPUBlendFactor.Zero;
|
|
colorBlend.dstFactor = ( premultipliedAlpha === true ) ? GPUBlendFactor.Zero : GPUBlendFactor.OneMinusSrcColor;
|
|
colorBlend.operation = GPUBlendOperation.Add;
|
|
break;
|
|
|
|
case MultiplyBlending:
|
|
colorBlend.srcFactor = GPUBlendFactor.Zero;
|
|
colorBlend.dstFactor = GPUBlendFactor.SrcColor;
|
|
colorBlend.operation = GPUBlendOperation.Add;
|
|
break;
|
|
|
|
case CustomBlending:
|
|
colorBlend.srcFactor = this._getBlendFactor( material.blendSrc );
|
|
colorBlend.dstFactor = this._getBlendFactor( material.blendDst );
|
|
colorBlend.operation = this._getBlendOperation( material.blendEquation );
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Blending not supported.', blending );
|
|
|
|
}
|
|
|
|
return colorBlend;
|
|
|
|
}
|
|
|
|
_getColorWriteMask( material ) {
|
|
|
|
return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None;
|
|
|
|
}
|
|
|
|
_getDepthCompare( material ) {
|
|
|
|
let depthCompare;
|
|
|
|
if ( material.depthTest === false ) {
|
|
|
|
depthCompare = GPUCompareFunction.Always;
|
|
|
|
} else {
|
|
|
|
const depthFunc = material.depthFunc;
|
|
|
|
switch ( depthFunc ) {
|
|
|
|
case NeverDepth:
|
|
depthCompare = GPUCompareFunction.Never;
|
|
break;
|
|
|
|
case AlwaysDepth:
|
|
depthCompare = GPUCompareFunction.Always;
|
|
break;
|
|
|
|
case LessDepth:
|
|
depthCompare = GPUCompareFunction.Less;
|
|
break;
|
|
|
|
case LessEqualDepth:
|
|
depthCompare = GPUCompareFunction.LessEqual;
|
|
break;
|
|
|
|
case EqualDepth:
|
|
depthCompare = GPUCompareFunction.Equal;
|
|
break;
|
|
|
|
case GreaterEqualDepth:
|
|
depthCompare = GPUCompareFunction.GreaterEqual;
|
|
break;
|
|
|
|
case GreaterDepth:
|
|
depthCompare = GPUCompareFunction.Greater;
|
|
break;
|
|
|
|
case NotEqualDepth:
|
|
depthCompare = GPUCompareFunction.NotEqual;
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Invalid depth function.', depthFunc );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return depthCompare;
|
|
|
|
}
|
|
|
|
_getPrimitiveState( object, material ) {
|
|
|
|
const descriptor = {};
|
|
|
|
descriptor.topology = this._getPrimitiveTopology( object );
|
|
|
|
if ( object.isLine === true && object.isLineSegments !== true ) {
|
|
|
|
const geometry = object.geometry;
|
|
const count = ( geometry.index ) ? geometry.index.count : geometry.attributes.position.count;
|
|
descriptor.stripIndexFormat = ( count > 65535 ) ? GPUIndexFormat.Uint32 : GPUIndexFormat.Uint16; // define data type for primitive restart value
|
|
|
|
}
|
|
|
|
switch ( material.side ) {
|
|
|
|
case FrontSide:
|
|
descriptor.frontFace = GPUFrontFace.CCW;
|
|
descriptor.cullMode = GPUCullMode.Back;
|
|
break;
|
|
|
|
case BackSide:
|
|
descriptor.frontFace = GPUFrontFace.CW;
|
|
descriptor.cullMode = GPUCullMode.Back;
|
|
break;
|
|
|
|
case DoubleSide:
|
|
descriptor.frontFace = GPUFrontFace.CCW;
|
|
descriptor.cullMode = GPUCullMode.None;
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Unknown Material.side value.', material.side );
|
|
break;
|
|
|
|
}
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
_getPrimitiveTopology( object ) {
|
|
|
|
if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
|
|
else if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
|
|
else if ( object.isLineSegments ) return GPUPrimitiveTopology.LineList;
|
|
else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
|
|
|
|
}
|
|
|
|
_getStencilCompare( material ) {
|
|
|
|
let stencilCompare;
|
|
|
|
const stencilFunc = material.stencilFunc;
|
|
|
|
switch ( stencilFunc ) {
|
|
|
|
case NeverStencilFunc:
|
|
stencilCompare = GPUCompareFunction.Never;
|
|
break;
|
|
|
|
case AlwaysStencilFunc:
|
|
stencilCompare = GPUCompareFunction.Always;
|
|
break;
|
|
|
|
case LessStencilFunc:
|
|
stencilCompare = GPUCompareFunction.Less;
|
|
break;
|
|
|
|
case LessEqualStencilFunc:
|
|
stencilCompare = GPUCompareFunction.LessEqual;
|
|
break;
|
|
|
|
case EqualStencilFunc:
|
|
stencilCompare = GPUCompareFunction.Equal;
|
|
break;
|
|
|
|
case GreaterEqualStencilFunc:
|
|
stencilCompare = GPUCompareFunction.GreaterEqual;
|
|
break;
|
|
|
|
case GreaterStencilFunc:
|
|
stencilCompare = GPUCompareFunction.Greater;
|
|
break;
|
|
|
|
case NotEqualStencilFunc:
|
|
stencilCompare = GPUCompareFunction.NotEqual;
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Invalid stencil function.', stencilFunc );
|
|
|
|
}
|
|
|
|
return stencilCompare;
|
|
|
|
}
|
|
|
|
_getStencilOperation( op ) {
|
|
|
|
let stencilOperation;
|
|
|
|
switch ( op ) {
|
|
|
|
case KeepStencilOp:
|
|
stencilOperation = GPUStencilOperation.Keep;
|
|
break;
|
|
|
|
case ZeroStencilOp:
|
|
stencilOperation = GPUStencilOperation.Zero;
|
|
break;
|
|
|
|
case ReplaceStencilOp:
|
|
stencilOperation = GPUStencilOperation.Replace;
|
|
break;
|
|
|
|
case InvertStencilOp:
|
|
stencilOperation = GPUStencilOperation.Invert;
|
|
break;
|
|
|
|
case IncrementStencilOp:
|
|
stencilOperation = GPUStencilOperation.IncrementClamp;
|
|
break;
|
|
|
|
case DecrementStencilOp:
|
|
stencilOperation = GPUStencilOperation.DecrementClamp;
|
|
break;
|
|
|
|
case IncrementWrapStencilOp:
|
|
stencilOperation = GPUStencilOperation.IncrementWrap;
|
|
break;
|
|
|
|
case DecrementWrapStencilOp:
|
|
stencilOperation = GPUStencilOperation.DecrementWrap;
|
|
break;
|
|
|
|
default:
|
|
console.error( 'THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation );
|
|
|
|
}
|
|
|
|
return stencilOperation;
|
|
|
|
}
|
|
|
|
_getVertexFormat( type, bytesPerElement ) {
|
|
|
|
// float
|
|
|
|
if ( type === 'float' ) return GPUVertexFormat.Float32;
|
|
|
|
if ( type === 'vec2' ) {
|
|
|
|
if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Float16x2;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Float32x2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( type === 'vec3' ) return GPUVertexFormat.Float32x3;
|
|
|
|
if ( type === 'vec4' ) {
|
|
|
|
if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Float16x4;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Float32x4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// int
|
|
|
|
if ( type === 'int' ) return GPUVertexFormat.Sint32;
|
|
|
|
if ( type === 'ivec2' ) {
|
|
|
|
if ( bytesPerElement === 1 ) {
|
|
|
|
return GPUVertexFormat.Sint8x2;
|
|
|
|
} else if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Sint16x2;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Sint32x2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( type === 'ivec3' ) return GPUVertexFormat.Sint32x3;
|
|
|
|
if ( type === 'ivec4' ) {
|
|
|
|
if ( bytesPerElement === 1 ) {
|
|
|
|
return GPUVertexFormat.Sint8x4;
|
|
|
|
} else if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Sint16x4;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Sint32x4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// uint
|
|
|
|
if ( type === 'uint' ) return GPUVertexFormat.Uint32;
|
|
|
|
if ( type === 'uvec2' ) {
|
|
|
|
if ( bytesPerElement === 1 ) {
|
|
|
|
return GPUVertexFormat.Uint8x2;
|
|
|
|
} else if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Uint16x2;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Uint32x2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( type === 'uvec3' ) return GPUVertexFormat.Uint32x3;
|
|
|
|
if ( type === 'uvec4' ) {
|
|
|
|
if ( bytesPerElement === 1 ) {
|
|
|
|
return GPUVertexFormat.Uint8x4;
|
|
|
|
} else if ( bytesPerElement === 2 ) {
|
|
|
|
return GPUVertexFormat.Uint16x4;
|
|
|
|
} else {
|
|
|
|
return GPUVertexFormat.Uint32x4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
console.error( 'THREE.WebGPURenderer: Shader variable type not supported yet.', type );
|
|
|
|
}
|
|
|
|
_parseShaderAttributes( shader, geometry ) {
|
|
|
|
// find "layout (location = num) in type name" in vertex shader
|
|
|
|
const regex = /\s*layout\s*\(\s*location\s*=\s*(?<location>[0-9]+)\s*\)\s*in\s+(?<type>\w+)\s+(?<name>\w+)\s*;/gmi;
|
|
let shaderAttribute = null;
|
|
|
|
const attributes = [];
|
|
|
|
while ( shaderAttribute = regex.exec( shader ) ) {
|
|
|
|
const name = shaderAttribute.groups.name;
|
|
|
|
const geometryAttribute = geometry.getAttribute( name );
|
|
const bytesPerElement = ( geometryAttribute !== undefined ) ? geometryAttribute.array.BYTES_PER_ELEMENT : 4;
|
|
|
|
const shaderLocation = parseInt( shaderAttribute.groups.location );
|
|
const arrayStride = this._getArrayStride( shaderAttribute.groups.type, bytesPerElement );
|
|
const vertexFormat = this._getVertexFormat( shaderAttribute.groups.type, bytesPerElement );
|
|
|
|
attributes.push( {
|
|
name: name,
|
|
arrayStride: arrayStride,
|
|
slot: shaderLocation,
|
|
format: vertexFormat
|
|
} );
|
|
|
|
}
|
|
|
|
// the sort ensures to setup vertex buffers in the correct order
|
|
|
|
return attributes.sort( function ( a, b ) {
|
|
|
|
return a.slot - b.slot;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export default WebGPURenderPipeline;
|
|
|