diff --git a/examples/showcase/instancing/app.ts b/examples/showcase/instancing/app.ts index 435042086..54ee4fb2f 100644 --- a/examples/showcase/instancing/app.ts +++ b/examples/showcase/instancing/app.ts @@ -1,8 +1,8 @@ -// +// import type {ShaderUniformType, NumberArray} from '@luma.gl/core'; -import {Device, Framebuffer, makeRandomNumberGenerator, UniformStore, glsl} from '@luma.gl/core'; +import {Device, Framebuffer, makeRandomNumberGenerator, glsl} from '@luma.gl/core'; import type {AnimationProps, ModelProps} from '@luma.gl/engine'; -import {AnimationLoopTemplate, CubeGeometry, Timeline, Model} from '@luma.gl/engine'; +import {AnimationLoopTemplate, CubeGeometry, Timeline, Model, _ShaderInputs} from '@luma.gl/engine'; import {readPixelsToArray} from '@luma.gl/webgl'; import {picking, dirlight} from '@luma.gl/shadertools'; import {Matrix4, radians} from '@math.gl/core'; @@ -39,19 +39,6 @@ uniform appUniforms { out vec3 color; void main(void) { - // vec3 normal = vec3(uModel * vec4(normals, 1.0)); - - // // Set up data for modules - // color = instanceColors; - // project_setNormal(normal); - // // vec4 pickColor = vec4(0., instancePickingColors, 1.0); - // picking_setPickingColor(vec3(0., instancePickingColors)); - - // // Vertex position (z coordinate undulates with time), and model rotates around center - // float delta = length(instanceOffsets); - // vec4 offset = vec4(instanceOffsets, sin((uTime + delta) * 0.1) * 16.0, 0); - // gl_Position = uProjection * uView * (uModel * vec4(positions * 1., 1.0) + offset); - // Set up data for modules color = instanceColors; vec3 normal = vec3(app.modelMatrix * vec4(normals, 1.0)); @@ -72,7 +59,6 @@ const fs = glsl`\ precision highp float; in vec3 color; - out vec4 fragColor; void main(void) { @@ -86,7 +72,6 @@ const SIDE = 256; // Make a cube with 65K instances and attributes to control offset and color of each instance class InstancedCube extends Model { - // uniformBuffer: Buffer; constructor(device: Device, props?: Partial) { @@ -139,8 +124,8 @@ class InstancedCube extends Model { bufferLayout: [ {name: 'instanceOffsets', format: 'float32x2'}, {name: 'instanceColors', format: 'unorm8x4'}, - {name: 'instancePickingColors', format: 'unorm8x2'}, - // TODO - normalizing picking colors breaks picking + {name: 'instancePickingColors', format: 'unorm8x2'} + // TODO - normalizing picking colors breaks picking // {name: 'instancePickingColors', format: 'unorm8x2'}, ], attributes: { @@ -182,10 +167,10 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { timelineChannels: Record; pickingFramebuffer: Framebuffer; - uniformStore = new UniformStore<{ - app: AppUniforms, - dirlight: typeof dirlight.uniforms, - picking: typeof picking.uniforms + shaderInputs = new _ShaderInputs<{ + app: AppUniforms; + dirlight: typeof dirlight.props; + picking: typeof picking.props; }>({ app, dirlight, @@ -210,13 +195,10 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { colorAttachments: ['rgba8unorm'], depthStencilAttachment: 'depth24plus' }); - + this.cube = new InstancedCube(device, { - bindings: { - app: this.uniformStore.getManagedUniformBuffer(device, 'app'), - dirlight: this.uniformStore.getManagedUniformBuffer(device, 'dirlight'), - picking: this.uniformStore.getManagedUniformBuffer(device, 'picking'), - } + // @ts-ignore + shaderInputs: this.shaderInputs }); } @@ -225,11 +207,16 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { const {_mousePosition} = animationProps; const {timeChannel, eyeXChannel, eyeYChannel, eyeZChannel} = this.timelineChannels; - this.uniformStore.setUniforms({ + this.shaderInputs.setProps({ app: { time: this.timeline.getTime(timeChannel), // Basic projection matrix - projectionMatrix: new Matrix4().perspective({fovy: radians(60), aspect, near: 1, far: 2048.0}), + projectionMatrix: new Matrix4().perspective({ + fovy: radians(60), + aspect, + near: 1, + far: 2048.0 + }), // Move the eye around the plane viewMatrix: new Matrix4().lookAt({ center: [0, 0, 0], @@ -244,9 +231,7 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { } }); - if (_mousePosition) { - this.pickInstance(device, _mousePosition, this.cube, this.pickingFramebuffer); - } + this.pickInstance(device, _mousePosition, this.cube, this.pickingFramebuffer); // Draw the cubes const renderPass = device.beginRenderPass({ @@ -265,25 +250,34 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { pickInstance( device: Device, - mousePosition: number[], + mousePosition: number[] | null | undefined, model: Model, framebuffer: Framebuffer ) { + if (!mousePosition) { + this.shaderInputs.setProps({picking: {highlightedObjectColor: null}}); + return; + } + // use the center pixel location in device pixel range - const devicePixels = device.canvasContext.cssToDevicePixels(mousePosition); + const devicePixels = device.canvasContext!.cssToDevicePixels(mousePosition); const pickX = devicePixels.x + Math.floor(devicePixels.width / 2); const pickY = devicePixels.y + Math.floor(devicePixels.height / 2); // Render picking colors - framebuffer.resize(device.canvasContext.getPixelSize()); + framebuffer.resize(device.canvasContext!.getPixelSize()); - this.uniformStore.setUniforms({picking: {isActive: true}}); + this.shaderInputs.setProps({picking: {isActive: true}}); - const pickingPass = device.beginRenderPass({framebuffer, clearColor: [0, 0, 0, 0], clearDepth: 1}); + const pickingPass = device.beginRenderPass({ + framebuffer, + clearColor: [0, 0, 0, 0], + clearDepth: 1 + }); model.draw(pickingPass); pickingPass.end(); - // Read back + // Read back const color255 = readPixelsToArray(framebuffer, { sourceX: pickX, sourceY: pickY, @@ -292,10 +286,12 @@ export default class AppAnimationLoopTemplate extends AnimationLoopTemplate { }); // console.log(color255); - const highlightedObjectColor = new Float32Array(color255).map((x) => x / 255); - const isHighlightActive = highlightedObjectColor[0] + highlightedObjectColor[1] + highlightedObjectColor[2] > 0; - - this.uniformStore.setUniforms({picking: {isActive: false, isHighlightActive, highlightedObjectColor}}); - } -} + const highlightedObjectColor = new Float32Array(color255).map(x => x / 255); + const isHighlightActive = + highlightedObjectColor[0] + highlightedObjectColor[1] + highlightedObjectColor[2] > 0; + this.shaderInputs.setProps({ + picking: {isActive: false, isHighlightActive, highlightedObjectColor} + }); + } +} diff --git a/modules/core/src/index.ts b/modules/core/src/index.ts index 912b53a23..5ed205d1c 100644 --- a/modules/core/src/index.ts +++ b/modules/core/src/index.ts @@ -163,10 +163,6 @@ export {requestAnimationFrame, cancelAnimationFrame} from './utils/request-anima */ export const glsl = (x: TemplateStringsArray) => `${x}`; -// DEBUG - -export {getDebugTableForShaderLayout} from './lib/debug/debug-shader-layout'; - // INTERNAL export type { diff --git a/modules/core/src/init.ts b/modules/core/src/init.ts index 1012edebd..34febf3fb 100644 --- a/modules/core/src/init.ts +++ b/modules/core/src/init.ts @@ -14,7 +14,7 @@ declare global { function initializeLuma(): string { // Version detection using babel plugin // @ts-expect-error - const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'untranspiled source'; + const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'running from source'; const STARTUP_MESSAGE = 'set luma.log.level=1 (or higher) to trace rendering'; // Assign luma.log.level in console to control logging: \ @@ -27,7 +27,7 @@ function initializeLuma(): string { if (!globalThis.luma) { if (isBrowser()) { - log.log(1, `luma.gl ${VERSION} - ${STARTUP_MESSAGE}`)(); + log.log(1, `${VERSION} - ${STARTUP_MESSAGE}`)(); } globalThis.luma = globalThis.luma || { diff --git a/modules/core/test/index.ts b/modules/core/test/index.ts index f4860fe1f..58a3eed70 100644 --- a/modules/core/test/index.ts +++ b/modules/core/test/index.ts @@ -22,6 +22,3 @@ import './lib/uniforms/uniform-buffer-layout.spec'; // compiler logs import './lib/compiler-log/format-compiler-log.spec'; - -// debug -import './lib/debug/get-debug-table-from-shader-layout.spec'; diff --git a/modules/core/src/lib/debug/debug-shader-layout.ts b/modules/engine/src/debug/debug-shader-layout.ts similarity index 89% rename from modules/core/src/lib/debug/debug-shader-layout.ts rename to modules/engine/src/debug/debug-shader-layout.ts index bbf6efb1b..6ee4ba09a 100644 --- a/modules/core/src/lib/debug/debug-shader-layout.ts +++ b/modules/engine/src/debug/debug-shader-layout.ts @@ -1,4 +1,8 @@ -import type {ShaderLayout} from '../../adapter/types/shader-layout'; +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import type {ShaderLayout} from '@luma.gl/core'; /** * Extracts a table suitable for `console.table()` from a shader layout to assist in debugging. diff --git a/modules/engine/src/model/model.ts b/modules/engine/src/model/model.ts index 090b63665..8d00036e7 100644 --- a/modules/engine/src/model/model.ts +++ b/modules/engine/src/model/model.ts @@ -6,13 +6,14 @@ import type {BufferLayout, VertexArray, TransformFeedback} from '@luma.gl/core'; import type {AttributeInfo, Binding, UniformValue, PrimitiveTopology} from '@luma.gl/core'; import {Device, Buffer, RenderPipeline, RenderPass, UniformStore} from '@luma.gl/core'; import {log, uid, deepEqual, splitUniformsAndBindings} from '@luma.gl/core'; -import {getAttributeInfosFromLayouts, getDebugTableForShaderLayout} from '@luma.gl/core'; +import {getAttributeInfosFromLayouts} from '@luma.gl/core'; import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools'; import {ShaderAssembler} from '@luma.gl/shadertools'; import {ShaderInputs} from '../shader-inputs'; import type {Geometry} from '../geometry/geometry'; import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry'; import {PipelineFactory} from '../lib/pipeline-factory'; +import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout'; const LOG_DRAW_PRIORITY = 2; const LOG_DRAW_TIMEOUT = 10000; @@ -304,7 +305,7 @@ export class Model { _setGeometryAttributes(gpuGeometry: GPUGeometry): void { // TODO - delete previous geometry? this.vertexCount = gpuGeometry.vertexCount; - this.setAttributes(gpuGeometry.attributes); + this.setAttributes(gpuGeometry.attributes, 'ignore-unknown'); this.setIndexBuffer(gpuGeometry.indices); } @@ -438,7 +439,7 @@ export class Model { * Sets attributes (buffers) * @note Overrides any attributes previously set with the same name */ - setAttributes(buffers: Record): void { + setAttributes(buffers: Record, _option?: 'ignore-unknown'): void { if (buffers.indices) { log.warn( `Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()` @@ -463,7 +464,7 @@ export class Model { set = true; } } - if (!set) { + if (!set && _option !== 'ignore-unknown') { log.warn( `Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"` )(); @@ -552,6 +553,13 @@ export class Model { // log.table(logLevel, uniformTable)(); log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)(); + const uniformTable = this.shaderInputs.getDebugTable(); + // Add any global uniforms + for (const [name, value] of Object.entries(this.uniforms)) { + uniformTable[name] = {value}; + } + log.table(LOG_DRAW_PRIORITY, uniformTable)(); + log.groupEnd(LOG_DRAW_PRIORITY)(); this._logOpen = false; } diff --git a/modules/engine/src/shader-inputs.ts b/modules/engine/src/shader-inputs.ts index 816c4f951..f20e31a68 100644 --- a/modules/engine/src/shader-inputs.ts +++ b/modules/engine/src/shader-inputs.ts @@ -134,4 +134,17 @@ export class ShaderInputs< } return bindings; } + + getDebugTable(): Record> { + const table: Record> = {}; + for (const [moduleName, module] of Object.entries(this.moduleUniforms)) { + for (const [key, value] of Object.entries(module)) { + table[`${moduleName}.${key}`] = { + type: this.modules[moduleName].uniformTypes?.[key], + value: String(value) + }; + } + } + return table; + } } diff --git a/modules/core/test/lib/debug/get-debug-table-from-shader-layout.spec.ts b/modules/engine/test/debug/get-debug-table-from-shader-layout.spec.ts similarity index 84% rename from modules/core/test/lib/debug/get-debug-table-from-shader-layout.spec.ts rename to modules/engine/test/debug/get-debug-table-from-shader-layout.spec.ts index 7b9879bcb..39af777b1 100644 --- a/modules/core/test/lib/debug/get-debug-table-from-shader-layout.spec.ts +++ b/modules/engine/test/debug/get-debug-table-from-shader-layout.spec.ts @@ -2,8 +2,8 @@ // Copyright (c) vis.gl contributors import test from 'tape-promise/tape'; -import {getDebugTableForShaderLayout, ShaderLayout} from '@luma.gl/core'; - +import type {ShaderLayout} from '@luma.gl/core'; +import {getDebugTableForShaderLayout} from '../../src/debug/debug-shader-layout'; const SHADER_LAYOUT: ShaderLayout = { attributes: [ diff --git a/modules/engine/test/index.ts b/modules/engine/test/index.ts index 6d1f1d40b..46729cc35 100644 --- a/modules/engine/test/index.ts +++ b/modules/engine/test/index.ts @@ -20,3 +20,7 @@ import './scenegraph/model-node.spec'; import './shader-inputs.spec'; import './transform/buffer-transform.spec'; import './transform/texture-transform.spec'; + + +// debug +import './debug/get-debug-table-from-shader-layout.spec'; diff --git a/modules/webgl/src/context/polyfill/polyfill-context.ts b/modules/webgl/src/context/polyfill/polyfill-context.ts index 6ae2552a1..49df93321 100644 --- a/modules/webgl/src/context/polyfill/polyfill-context.ts +++ b/modules/webgl/src/context/polyfill/polyfill-context.ts @@ -38,9 +38,13 @@ function initializeExtensions(gl: WebGLRenderingContext): void { const contextState = getContextData(gl); // `getSupportedExtensions` can return null when context is lost. const EXTENSIONS = gl.getSupportedExtensions() || []; + // Generates warnings in Chrome + const IGNORE_EXTENSIONS = ['WEBGL_polygon_mode']; for (const extensionName of EXTENSIONS) { - const extension = gl.getExtension(extensionName); - contextState._extensions[extensionName] = extension; + if (!IGNORE_EXTENSIONS.includes(extensionName)) { + const extension = gl.getExtension(extensionName); + contextState._extensions[extensionName] = extension; + } } }