Browse Source

shader refactoring

- add dRenderVariant
- add convenince defines
Alexander Rose 5 years ago
parent
commit
70bd035898

+ 25 - 21
src/mol-gl/shader/chunks/assign-color-varying.glsl.ts

@@ -1,26 +1,30 @@
 export default `
-#if defined(dColorType_attribute)
-    vColor.rgb = aColor;
-#elif defined(dColorType_instance)
-    vColor.rgb = readFromTexture(tColor, aInstance, uColorTexDim).rgb;
-#elif defined(dColorType_group)
-    vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
-#elif defined(dColorType_groupInstance)
-    vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
-#elif defined(dColorType_objectPicking)
-    vColor = vec4(encodeFloatRGB(float(uObjectId)), 1.0);
-#elif defined(dColorType_instancePicking)
-    vColor = vec4(encodeFloatRGB(aInstance), 1.0);
-#elif defined(dColorType_groupPicking)
-    vColor = vec4(encodeFloatRGB(group), 1.0);
-#endif
+#if defined(dRenderVariant_color)
+    #if defined(dColorType_attribute)
+        vColor.rgb = aColor;
+    #elif defined(dColorType_instance)
+        vColor.rgb = readFromTexture(tColor, aInstance, uColorTexDim).rgb;
+    #elif defined(dColorType_group)
+        vColor.rgb = readFromTexture(tColor, group, uColorTexDim).rgb;
+    #elif defined(dColorType_groupInstance)
+        vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + group, uColorTexDim).rgb;
+    #endif
 
-#ifdef dOverpaint
-    vOverpaint = readFromTexture(tOverpaint, aInstance * float(uGroupCount) + group, uOverpaintTexDim);
-#endif
+    #ifdef dOverpaint
+        vOverpaint = readFromTexture(tOverpaint, aInstance * float(uGroupCount) + group, uOverpaintTexDim);
+    #endif
 
-#ifdef dTransparency
-    vGroup = group;
-    vTransparency = readFromTexture(tTransparency, aInstance * float(uGroupCount) + group, uTransparencyTexDim).a;
+    #ifdef dTransparency
+        vGroup = group;
+        vTransparency = readFromTexture(tTransparency, aInstance * float(uGroupCount) + group, uTransparencyTexDim).a;
+    #endif
+#elif defined(dRenderVariant_pick)
+    #if defined(dRenderVariant_pickObject)
+        vColor = vec4(encodeFloatRGB(float(uObjectId)), 1.0);
+    #elif defined(dRenderVariant_pickInstance)
+        vColor = vec4(encodeFloatRGB(aInstance), 1.0);
+    #elif defined(dRenderVariant_pickGroup)
+        vColor = vec4(encodeFloatRGB(group), 1.0);
+    #endif
 #endif
 `;

+ 36 - 34
src/mol-gl/shader/chunks/assign-material-color.glsl.ts

@@ -1,43 +1,45 @@
 export default `
-#if defined(dColorType_uniform)
-    vec4 material = vec4(uColor, uAlpha);
-#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)
-    vec4 material = vec4(vColor.rgb, uAlpha);
-#elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
-    vec4 material = uPickable == 1 ? vColor : vec4(0.0, 0.0, 0.0, 1.0); // set to empty picking id
-#elif defined(dColorType_depth)
-    #ifdef enabledFragDepth
-        vec4 material = packDepthToRGBA(gl_FragDepthEXT);
-    #else
-        vec4 material = packDepthToRGBA(gl_FragCoord.z);
+#if defined(dRenderVariant_color)
+    #if defined(dColorType_uniform)
+        vec4 material = vec4(uColor, uAlpha);
+    #elif defined(dColorType_varying)
+        vec4 material = vec4(vColor.rgb, uAlpha);
     #endif
-#endif
 
-// mix material with overpaint
-#if defined(dOverpaint) && (defined(dColorType_uniform) || defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance))
-    material.rgb = mix(material.rgb, vOverpaint.rgb, vOverpaint.a);
-#endif
+    // mix material with overpaint
+    #if defined(dOverpaint)
+        material.rgb = mix(material.rgb, vOverpaint.rgb, vOverpaint.a);
+    #endif
 
-// apply screendoor transparency
-#if defined(dTransparency) && (defined(dColorType_uniform) || defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance))
-    float ta = 1.0 - vTransparency;
-    float at = 0.0;
+    // apply screendoor transparency
+    #if defined(dTransparency)
+        float ta = 1.0 - vTransparency;
+        float at = 0.0;
 
-    // shift by view-offset during multi-sample rendering to allow for blending
-    vec2 coord = gl_FragCoord.xy + uViewOffset * 0.25;
+        // shift by view-offset during multi-sample rendering to allow for blending
+        vec2 coord = gl_FragCoord.xy + uViewOffset * 0.25;
 
-    #if defined(dTransparencyVariant_single)
-        const mat4 thresholdMatrix = mat4(
-            1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
-            13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
-            4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
-            16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
-        );
-        at = thresholdMatrix[int(intMod(coord.x, 4.0))][int(intMod(coord.y, 4.0))];
-    #elif defined(dTransparencyVariant_multi)
-        at = fract(dot(vec3(coord, vGroup + 0.5), vec3(2.0, 7.0, 23.0) / 17.0f));
-    #endif
+        #if defined(dTransparencyVariant_single)
+            const mat4 thresholdMatrix = mat4(
+                1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
+                13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
+                4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
+                16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
+            );
+            at = thresholdMatrix[int(intMod(coord.x, 4.0))][int(intMod(coord.y, 4.0))];
+        #elif defined(dTransparencyVariant_multi)
+            at = fract(dot(vec3(coord, vGroup + 0.5), vec3(2.0, 7.0, 23.0) / 17.0f));
+        #endif
 
-    if (ta < 0.99 && (ta < 0.01 || ta < at)) discard;
+        if (ta < 0.99 && (ta < 0.01 || ta < at)) discard;
+    #endif
+#elif defined(dRenderVariant_pick)
+    vec4 material = uPickable == 1 ? vColor : vec4(0.0, 0.0, 0.0, 1.0); // set to empty picking id
+#elif defined(dRenderVariant_depth)
+    #ifdef enabledFragDepth
+        vec4 material = packDepthToRGBA(gl_FragDepthEXT);
+    #else
+        vec4 material = packDepthToRGBA(gl_FragCoord.z);
+    #endif
 #endif
 `;

+ 16 - 14
src/mol-gl/shader/chunks/color-frag-params.glsl.ts

@@ -1,22 +1,24 @@
 export default `
-#if defined(dColorType_uniform)
-    uniform vec3 uColor;
-#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)
-    varying vec4 vColor;
-#elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+#if defined(dRenderVariant_color)
+    #if defined(dColorType_uniform)
+        uniform vec3 uColor;
+    #elif defined(dColorType_varying)
+        varying vec4 vColor;
+    #endif
+
+    #ifdef dOverpaint
+        varying vec4 vOverpaint;
+    #endif
+
+    #ifdef dTransparency
+        varying float vGroup;
+        varying float vTransparency;
+    #endif
+#elif defined(dRenderVariant_pick)
     #if __VERSION__ != 300
         varying vec4 vColor;
     #else
         flat in vec4 vColor;
     #endif
 #endif
-
-#ifdef dOverpaint
-    varying vec4 vOverpaint;
-#endif
-
-#ifdef dTransparency
-    varying float vGroup;
-    varying float vTransparency;
-#endif
 `;

+ 25 - 23
src/mol-gl/shader/chunks/color-vert-params.glsl.ts

@@ -1,31 +1,33 @@
 export default `
-#if defined(dColorType_uniform)
-    uniform vec3 uColor;
-#elif defined(dColorType_attribute)
-    varying vec4 vColor;
-    attribute vec3 aColor;
-#elif defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)
-    varying vec4 vColor;
-    uniform vec2 uColorTexDim;
-    uniform sampler2D tColor;
-#elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+#if defined(dRenderVariant_color)
+    #if defined(dColorType_uniform)
+        uniform vec3 uColor;
+    #elif defined(dColorType_attribute)
+        varying vec4 vColor;
+        attribute vec3 aColor;
+    #elif defined(dColorType_texture)
+        varying vec4 vColor;
+        uniform vec2 uColorTexDim;
+        uniform sampler2D tColor;
+    #endif
+
+    #ifdef dOverpaint
+        varying vec4 vOverpaint;
+        uniform vec2 uOverpaintTexDim;
+        uniform sampler2D tOverpaint;
+    #endif
+
+    #ifdef dTransparency
+        varying float vGroup;
+        varying float vTransparency;
+        uniform vec2 uTransparencyTexDim;
+        uniform sampler2D tTransparency;
+    #endif
+#elif defined(dRenderVariant_pick)
     #if __VERSION__ != 300
         varying vec4 vColor;
     #else
         flat out vec4 vColor;
     #endif
 #endif
-
-#ifdef dOverpaint
-    varying vec4 vOverpaint;
-    uniform vec2 uOverpaintTexDim;
-    uniform sampler2D tOverpaint;
-#endif
-
-#ifdef dTransparency
-    varying float vGroup;
-    varying float vTransparency;
-    uniform vec2 uTransparencyTexDim;
-    uniform sampler2D tTransparency;
-#endif
 `;

+ 16 - 0
src/mol-gl/shader/chunks/common.glsl.ts

@@ -1,4 +1,20 @@
 export default `
+// TODO find a better place for these convenience defines
+
+#if defined(dRenderVariant_pickObject) || defined(dRenderVariant_pickInstance) || defined(dRenderVariant_pickGroup)
+    #define dRenderVariant_pick
+#endif
+
+#if defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)
+    #define dColorType_texture
+#endif
+
+#if defined(dColorType_attribute) || defined(dColorType_texture)
+    #define dColorType_varying
+#endif
+
+//
+
 #define PI 3.14159265
 #define RECIPROCAL_PI 0.31830988618
 #define EPSILON 1e-6

+ 7 - 7
src/mol-gl/shader/direct-volume.frag.ts

@@ -41,7 +41,7 @@ uniform int uPickable;
 
 #if defined(dColorType_uniform)
     uniform vec3 uColor;
-#elif defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)
+#elif defined(dColorType_varying)
     uniform vec2 uColorTexDim;
     uniform sampler2D tColor;
 #endif
@@ -114,23 +114,23 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) {
                 tmp = ((prevValue - uIsoValue) / ((prevValue - uIsoValue) - (value - uIsoValue)));
                 isoPos = mix(pos - step, pos, tmp);
 
-                #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+                #if defined(dRenderVariant_pick)
                     if (uAlpha < uPickingAlphaThreshold)
                         discard; // ignore so the element below can be picked
                     if (uPickable == 0)
                         return vec4(0.0, 0.0, 0.0, 1.0); // set to empty picking id
                 #endif
 
-                #if defined(dColorType_objectPicking)
+                #if defined(dRenderVariant_pickObject)
                     return vec4(encodeFloatRGB(float(uObjectId)), 1.0);
-                #elif defined(dColorType_instancePicking)
+                #elif defined(dRenderVariant_pickInstance)
                     return vec4(encodeFloatRGB(instance), 1.0);
-                #elif defined(dColorType_groupPicking)
+                #elif defined(dRenderVariant_pickGroup)
                     float group = floor(decodeFloatRGB(textureGroup(isoPos).rgb) + 0.5);
                     return vec4(encodeFloatRGB(group), 1.0);
-                #elif defined(dColorType_depth)
+                #elif defined(dRenderVariant_depth)
                     return packDepthToRGBA(gl_FragCoord.z); // TODO calculate isosurface depth
-                #else
+                #elif defined(dRenderVariant_color)
                     // compute gradient by central differences
                     gradient.x = textureVal(isoPos - dx).a - textureVal(isoPos + dx).a;
                     gradient.y = textureVal(isoPos - dy).a - textureVal(isoPos + dy).a;

+ 3 - 3
src/mol-gl/shader/lines.frag.ts

@@ -15,12 +15,12 @@ precision highp int;
 void main(){
     #include assign_material_color
 
-    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+    #if defined(dRenderVariant_pick)
         #include check_picking_alpha
         gl_FragColor = material;
-    #elif defined(dColorType_depth)
+    #elif defined(dRenderVariant_depth)
         gl_FragColor = material;
-    #else
+    #elif defined(dRenderVariant_color)
         gl_FragColor = material;
 
         #include apply_marker_color

+ 3 - 3
src/mol-gl/shader/mesh.frag.ts

@@ -33,12 +33,12 @@ void main() {
 
     #include assign_material_color
 
-    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+    #if defined(dRenderVariant_pick)
         #include check_picking_alpha
         gl_FragColor = material;
-    #elif defined(dColorType_depth)
+    #elif defined(dRenderVariant_depth)
         gl_FragColor = material;
-    #else
+    #elif defined(dRenderVariant_color)
         #ifdef dIgnoreLight
             gl_FragColor = material;
         #else

+ 3 - 3
src/mol-gl/shader/points.frag.ts

@@ -22,12 +22,12 @@ const float radius = 0.5;
 void main(){
     #include assign_material_color
 
-    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+    #if defined(dRenderVariant_pick)
         #include check_picking_alpha
         gl_FragColor = material;
-    #elif defined(dColorType_depth)
+    #elif defined(dRenderVariant_depth)
         gl_FragColor = material;
-    #else
+    #elif defined(dRenderVariant_color)
         gl_FragColor = material;
 
         #ifdef dPointFilledCircle

+ 4 - 4
src/mol-gl/shader/spheres.frag.ts

@@ -58,7 +58,7 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
 
     cameraPos = rayDirection * negT + rayOrigin;
 
-    
+
     if (calcDepth(cameraPos) <= 0.0) {
         cameraPos = rayDirection * posT + rayOrigin;
         interior = true;
@@ -94,12 +94,12 @@ void main(void){
 
     #include assign_material_color
 
-    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+    #if defined(dRenderVariant_pick)
         #include check_picking_alpha
         gl_FragColor = material;
-    #elif defined(dColorType_depth)
+    #elif defined(dRenderVariant_depth)
         gl_FragColor = material;
-    #else
+    #elif defined(dRenderVariant_color)
         #ifdef dIgnoreLight
             gl_FragColor = material;
         #else

+ 3 - 3
src/mol-gl/shader/text.frag.ts

@@ -56,11 +56,11 @@ void main(){
         gl_FragColor = material;
     }
 
-    #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking)
+    #if defined(dRenderVariant_pick)
         #include check_picking_alpha
-    #elif defined(dColorType_depth)
+    #elif defined(dRenderVariant_depth)
         gl_FragColor = material;
-    #else
+    #elif defined(dRenderVariant_color)
         #include apply_marker_color
         #include apply_fog
     #endif

+ 32 - 36
src/mol-gl/webgl/render-item.ts

@@ -7,9 +7,9 @@
 import { createAttributeBuffers, ElementsBuffer, AttributeKind } from './buffer';
 import { createTextures, Texture } from './texture';
 import { WebGLContext, checkError } from './context';
-import { ShaderCode } from '../shader-code';
+import { ShaderCode, DefineValues } from '../shader-code';
 import { Program } from './program';
-import { RenderableSchema, RenderableValues, AttributeSpec, getValueVersions, splitValues, Values } from '../renderable/schema';
+import { RenderableSchema, RenderableValues, AttributeSpec, getValueVersions, splitValues, DefineSpec } from '../renderable/schema';
 import { idFactory } from '../../mol-util/id-factory';
 import { ValueCell } from '../../mol-util';
 import { TextureImage, TextureVolume } from '../../mol-gl/renderable/util';
@@ -46,21 +46,19 @@ export interface RenderItem<T extends string> {
 
 //
 
-const GraphicsRenderVariantDefines = {
-    'color': {},
-    'pickObject': { dColorType: ValueCell.create('objectPicking') },
-    'pickInstance': { dColorType: ValueCell.create('instancePicking') },
-    'pickGroup': { dColorType: ValueCell.create('groupPicking') },
-    'depth': { dColorType: ValueCell.create('depth') }
-};
-export type GraphicsRenderVariant = keyof typeof GraphicsRenderVariantDefines
+const GraphicsRenderVariant = { 'color': '', 'pickObject': '', 'pickInstance': '', 'pickGroup': '', 'depth': '' };
+export type GraphicsRenderVariant = keyof typeof GraphicsRenderVariant
+const GraphicsRenderVariants = Object.keys(GraphicsRenderVariant) as GraphicsRenderVariant[];
 
-const ComputeRenderVariantDefines = {
-    'compute': {},
-};
-export type ComputeRenderVariant = keyof typeof ComputeRenderVariantDefines
+const ComputeRenderVariant = { 'compute': '' };
+export type ComputeRenderVariant = keyof typeof ComputeRenderVariant
+const ComputeRenderVariants = Object.keys(ComputeRenderVariant) as ComputeRenderVariant[];
 
-type RenderVariantDefines = typeof GraphicsRenderVariantDefines | typeof ComputeRenderVariantDefines
+function createProgramVariant(ctx: WebGLContext, variant: string, defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) {
+    defineValues = { ...defineValues, dRenderVariant: ValueCell.create(variant) };
+    schema = { ...schema, dRenderVariant: DefineSpec('string') };
+    return ctx.resources.program(defineValues, shaderCode, schema);
+}
 
 //
 
@@ -90,14 +88,14 @@ function resetValueChanges(valueChanges: ValueChanges) {
 
 //
 
-export type GraphicsRenderItem = RenderItem<keyof typeof GraphicsRenderVariantDefines & string>
+export type GraphicsRenderItem = RenderItem<GraphicsRenderVariant>
 export function createGraphicsRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number) {
-    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, GraphicsRenderVariantDefines);
+    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, GraphicsRenderVariants);
 }
 
-export type ComputeRenderItem = RenderItem<keyof typeof ComputeRenderVariantDefines & string>
+export type ComputeRenderItem = RenderItem<ComputeRenderVariant>
 export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId = -1) {
-    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, ComputeRenderVariantDefines);
+    return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, ComputeRenderVariants);
 }
 
 /**
@@ -105,7 +103,7 @@ export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, s
  *
  * - assumes that `values.drawCount` and `values.instanceCount` exist
  */
-export function createRenderItem<T extends RenderVariantDefines, S extends keyof T & string>(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, renderVariantDefines: T): RenderItem<S> {
+export function createRenderItem<T extends string>(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, renderVariants: T[]): RenderItem<T> {
     const id = getNextRenderItemId();
     const { stats, state, resources } = ctx;
     const { instancedArrays, vertexArrayObject } = ctx.extensions;
@@ -121,10 +119,9 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
     const glDrawMode = getDrawMode(ctx, drawMode);
 
     const programs: ProgramVariants = {};
-    Object.keys(renderVariantDefines).forEach(k => {
-        const variantDefineValues: Values<RenderableSchema> = (renderVariantDefines as any)[k];
-        programs[k] = resources.program({ ...defineValues, ...variantDefineValues }, shaderCode, schema);
-    });
+    for (const k of renderVariants) {
+        programs[k] = createProgramVariant(ctx, k, defineValues, shaderCode, schema);
+    }
 
     const textures = createTextures(ctx, schema, textureValues);
     const attributeBuffers = createAttributeBuffers(ctx, schema, attributeValues);
@@ -136,9 +133,9 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
     }
 
     const vertexArrays: VertexArrayVariants = {};
-    Object.keys(renderVariantDefines).forEach(k => {
+    for (const k of renderVariants) {
         vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null;
-    });
+    }
 
     let drawCount = values.drawCount.ref.value;
     let instanceCount = values.instanceCount.ref.value;
@@ -155,9 +152,9 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
     return {
         id,
         materialId,
-        getProgram: (variant: S) => programs[variant],
+        getProgram: (variant: T) => programs[variant],
 
-        render: (variant: S) => {
+        render: (variant: T) => {
             if (drawCount === 0 || instanceCount === 0 || ctx.isContextLost) return;
             const program = programs[variant];
             if (program.id === currentProgramId && state.currentRenderItemId === id) {
@@ -216,11 +213,10 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
 
             if (valueChanges.defines) {
                 // console.log('some defines changed, need to rebuild programs')
-                Object.keys(renderVariantDefines).forEach(k => {
-                    const variantDefineValues: Values<RenderableSchema> = (renderVariantDefines as any)[k];
+                for (const k of renderVariants) {
                     programs[k].destroy();
-                    programs[k] = resources.program({ ...defineValues, ...variantDefineValues }, shaderCode, schema);
-                });
+                    programs[k] = createProgramVariant(ctx, k, defineValues, shaderCode, schema);
+                }
             }
 
             if (values.drawCount.ref.version !== versions.drawCount) {
@@ -271,11 +267,11 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
 
             if (valueChanges.attributes || valueChanges.defines || valueChanges.elements) {
                 // console.log('program/defines or buffers changed, update vaos')
-                Object.keys(renderVariantDefines).forEach(k => {
+                for (const k of renderVariants) {
                     const vertexArray = vertexArrays[k];
                     if (vertexArray) vertexArray.destroy();
                     vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null;
-                });
+                }
             }
 
             for (let i = 0, il = textures.length; i < il; ++i) {
@@ -298,11 +294,11 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof
         },
         destroy: () => {
             if (!destroyed) {
-                Object.keys(renderVariantDefines).forEach(k => {
+                for (const k of renderVariants) {
                     programs[k].destroy();
                     const vertexArray = vertexArrays[k];
                     if (vertexArray) vertexArray.destroy();
-                });
+                }
                 textures.forEach(([k, texture]) => {
                     // lifetime of textures with kind 'texture' is defined externally
                     if (schema[k].kind !== 'texture') {