From 7758fa2e176d087df95d2ea009707cb245ee49de Mon Sep 17 00:00:00 2001 From: kpal81xd Date: Wed, 31 Jan 2024 17:45:05 +0000 Subject: [PATCH 1/6] changed grid lines to use shader --- examples/src/examples/misc/gizmos.mjs | 162 +++++++++++++++++++++----- 1 file changed, 135 insertions(+), 27 deletions(-) diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index b183dfc44d3..e6615a2283f 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -234,9 +234,9 @@ function controls({ observer, ReactPCUI, React, jsx, fragment }) { * @param {import('../../options.mjs').ExampleOptions} options - The example options. * @returns {Promise} The example application. */ -async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, scriptsPath }) { +async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgslPath, scriptsPath }) { - // Class for handling gizmos + // class for handling gizmos class GizmoHandler { /** * Gizmo type. @@ -421,11 +421,11 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, const app = new pc.AppBase(canvas); app.init(createOptions); - // Set the canvas to fill the window and automatically change resolution to be the same as the canvas size + // set the canvas to fill the window and automatically change resolution to be the same as the canvas size app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW); app.setCanvasResolution(pc.RESOLUTION_AUTO); - // Ensure canvas is resized when window changes size + // ensure canvas is resized when window changes size const resize = () => app.resizeCanvas(); window.addEventListener('resize', resize); @@ -452,17 +452,90 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, * @param {pc.Color} color - The color. * @returns {pc.Material} - The standard material. */ - function createMaterial(color) { + function createColorMaterial(color) { const material = new pc.StandardMaterial(); material.diffuse = color; return material; } + /** + * @param {pc.Shader} shader - The shader. + * @returns {pc.Material} - The standard material. + */ + function createShaderMaterial(shader) { + const material = new pc.Material(); + material.shader = shader; + material.blendType = pc.BLEND_NONE; + material.update(); + return material; + } + + /** + * @param {{ gridSize: number }} options - Grid mesh options. + * @returns {pc.Mesh} - The mesh. + */ + function createGridMesh(options) { + const gridSize = options.gridSize ?? 4; + + const vertexFormat = new pc.VertexFormat(device, [{ + semantic: pc.SEMANTIC_POSITION, + components: 3, + type: pc.TYPE_FLOAT32 + }, { + semantic: pc.SEMANTIC_COLOR, + components: 4, + type: pc.TYPE_UINT8, + normalize: true + }]); + + + const numLines = gridSize + 1; + + const gridData = new Float32Array(numLines * 4 * 4); + const clrData = new Uint32Array(gridData.buffer); + + for (let i = 0; i < numLines; i++) { + const a = (i / (numLines - 1) - 0.5) * gridSize; + const b = gridSize / 2; + const idx = i * 16; + const clr = i === Math.floor(numLines / 2) ? 0xff000000 : 0xffa0a0a0; + + gridData[idx + 0] = a; + gridData[idx + 1] = 0; + gridData[idx + 2] = -b; + clrData[idx + 3] = clr; + + gridData[idx + 4] = a; + gridData[idx + 5] = 0; + gridData[idx + 6] = b; + clrData[idx + 7] = clr; + + gridData[idx + 8] = -b; + gridData[idx + 9] = 0; + gridData[idx + 10] = a; + clrData[idx + 11] = clr; + + gridData[idx + 12] = b; + gridData[idx + 13] = 0; + gridData[idx + 14] = a; + clrData[idx + 15] = clr; + } + + const mesh = new pc.Mesh(device); + mesh.vertexBuffer = new pc.VertexBuffer(device, vertexFormat, numLines * 4, pc.BUFFER_STATIC, gridData.buffer); + mesh.primitive[0].type = pc.PRIMITIVE_LINES; + mesh.primitive[0].base = 0; + mesh.primitive[0].indexed = false; + mesh.primitive[0].count = numLines * 4; + + return mesh; + } + // create entities const box = new pc.Entity('box'); box.addComponent('render', { type: 'box', - material: createMaterial(new pc.Color(0.8, 1, 1)) + material: createColorMaterial(new pc.Color(0.8, 1, 1)) }); box.setPosition(1, 0, 1); app.root.addChild(box); @@ -470,7 +543,7 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, const sphere = new pc.Entity('sphere'); sphere.addComponent('render', { type: 'sphere', - material: createMaterial(new pc.Color(1, 0.8, 1)) + material: createColorMaterial(new pc.Color(1, 0.8, 1)) }); sphere.setPosition(-1, 0, 1); app.root.addChild(sphere); @@ -478,7 +551,7 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, const cone = new pc.Entity('cone'); cone.addComponent('render', { type: 'cone', - material: createMaterial(new pc.Color(1, 1, 0.8)) + material: createColorMaterial(new pc.Color(1, 1, 0.8)) }); cone.setPosition(-1, 0, -1); cone.setLocalScale(1.5, 2.25, 1.5); @@ -487,7 +560,7 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, const capsule = new pc.Entity('capsule'); capsule.addComponent('render', { type: 'capsule', - material: createMaterial(new pc.Color(0.8, 0.8, 1)) + material: createColorMaterial(new pc.Color(0.8, 0.8, 1)) }); capsule.setPosition(1, 0, -1); app.root.addChild(capsule); @@ -533,15 +606,27 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, app.root.addChild(keyLight); keyLight.setEulerAngles(0, 0, -60); - // create gizmoLayer + // create layers + const debugLayer = new pc.Layer({ + name: 'Debug Layer', + opaqueSortMode: pc.SORTMODE_NONE, + transparentSortMode: pc.SORTMODE_NONE + }); const gizmoLayer = new pc.Layer({ name: 'Gizmo', clearDepthBuffer: true, opaqueSortMode: pc.SORTMODE_NONE, transparentSortMode: pc.SORTMODE_NONE }); - app.scene.layers.push(gizmoLayer); - camera.camera.layers = camera.camera.layers.concat(gizmoLayer.id); + const layers = app.scene.layers; + const worldLayer = layers.getLayerByName('World'); + const idx = layers.getOpaqueIndex(worldLayer); + layers.insert(debugLayer, idx + 1); + layers.push(gizmoLayer); + camera.camera.layers = camera.camera.layers.concat([ + debugLayer.id, + gizmoLayer.id + ]); // create gizmo const gizmoHandler = new GizmoHandler(app, camera.camera, gizmoLayer); @@ -565,6 +650,7 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, window.top.setProj(value); }; + // key event handlers const keydown = (/** @type {KeyboardEvent} */ e) => { gizmoHandler.gizmo.snap = !!e.shiftKey; gizmoHandler.gizmo.uniform = !e.ctrlKey; @@ -599,7 +685,7 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, window.addEventListener('keyup', keyup); window.addEventListener('keypress', keypress); - // Gizmo and camera set handler + // gizmo and camera set handler const tmpC = new pc.Color(); data.on('*:set', (/** @type {string} */ path, value) => { const pathArray = path.split('.'); @@ -638,9 +724,8 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, } }); - // Picker + // picker const picker = new pc.Picker(app, canvas.clientWidth, canvas.clientHeight); - const worldLayer = app.scene.layers.getLayerByName("World"); const pickerLayers = [worldLayer]; const onPointerDown = (/** @type {PointerEvent} */ e) => { @@ -663,20 +748,17 @@ async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, }; window.addEventListener('pointerdown', onPointerDown); - const gridColor = new pc.Color(1, 1, 1, 0.5); - const gridHalfSize = 4; - /** - * @type {pc.Vec3[]} - */ - const gridLines = []; - for (let i = 0; i < gridHalfSize * 2 + 1; i++) { - gridLines.push(new pc.Vec3(-gridHalfSize, 0, i - gridHalfSize), new pc.Vec3(gridHalfSize, 0, i - gridHalfSize)); - gridLines.push(new pc.Vec3(i - gridHalfSize, 0, -gridHalfSize), new pc.Vec3(i - gridHalfSize, 0, gridHalfSize)); - } - app.on('update', () => { - app.drawLines(gridLines, gridColor); + // grid + const shader = pc.createShaderFromCode(device, files['shader.vert'], files['shader.frag'], 'grid-lines', { + vertex_position: pc.SEMANTIC_POSITION, + vertex_color: pc.SEMANTIC_COLOR }); + const mesh = createGridMesh({ gridSize: 8 }); + const material = createShaderMaterial(shader); + const meshInstance = new pc.MeshInstance(mesh, material, new pc.GraphNode()); + debugLayer.addMeshInstances([meshInstance], true); + app.on('destroy', () => { gizmoHandler.destroy(); @@ -695,6 +777,32 @@ class GizmosExample { static WEBGPU_ENABLED = false; static controls = controls; static example = example; + static FILES = { + 'shader.vert': /* glsl */` +attribute vec3 vertex_position; +attribute vec4 vertex_color; +varying vec4 vColor; +varying vec2 vZW; +uniform mat4 matrix_model; +uniform mat4 matrix_viewProjection; +void main(void) { + gl_Position = matrix_viewProjection * matrix_model * vec4(vertex_position, 1.0); + // store z/w for later use in fragment shader + vColor = vertex_color; + vZW = gl_Position.zw; + // disable depth clipping + gl_Position.z = 0.0; +}`, + 'shader.frag': /* glsl */` +precision highp float; +varying vec4 vColor; +varying vec2 vZW; +void main(void) { + gl_FragColor = vColor; + // clamp depth in Z to [0, 1] range + gl_FragDepth = max(0.0, min(1.0, (vZW.x / vZW.y + 1.0) * 0.5)); +}` + }; } export { GizmosExample }; From 4f16ec497c3864566ddd24257f3a7b34eb7f6f81 Mon Sep 17 00:00:00 2001 From: kpal81xd Date: Wed, 31 Jan 2024 17:46:27 +0000 Subject: [PATCH 2/6] create color material material update --- examples/src/examples/misc/gizmos.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index e6615a2283f..5963e76b28f 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -455,6 +455,7 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs function createColorMaterial(color) { const material = new pc.StandardMaterial(); material.diffuse = color; + material.update(); return material; } From b3f30856fd0eaff2e0fe960c6d60965dfe09b19e Mon Sep 17 00:00:00 2001 From: kpal81xd Date: Wed, 31 Jan 2024 22:51:40 +0000 Subject: [PATCH 3/6] set near/far clip in example for testing --- examples/src/examples/misc/gizmos.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index 5963e76b28f..0808805a68a 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -584,6 +584,9 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs camera.setPosition(1, 1, 1); app.root.addChild(camera); orbitCamera.distance = 14; + camera.camera.nearClip = 0.1; + camera.camera.farClip = 15; + // create 3-point lighting const backLight = new pc.Entity('light'); From f9e0f502d66f1870a52fb3bbcf0aa8dfe9f756ca Mon Sep 17 00:00:00 2001 From: kpal Date: Thu, 1 Feb 2024 18:39:54 +0000 Subject: [PATCH 4/6] basic shader material working for bypassing camera clipping --- examples/src/examples/misc/gizmos.mjs | 20 +++--- extras/gizmo/axis-shapes.js | 94 +++++++++++++++++++++++---- 2 files changed, 93 insertions(+), 21 deletions(-) diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index 0808805a68a..68f50333436 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -584,9 +584,7 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs camera.setPosition(1, 1, 1); app.root.addChild(camera); orbitCamera.distance = 14; - camera.camera.nearClip = 0.1; - camera.camera.farClip = 15; - + camera.camera.farClip = 12.3; // create 3-point lighting const backLight = new pc.Entity('light'); @@ -791,11 +789,13 @@ uniform mat4 matrix_model; uniform mat4 matrix_viewProjection; void main(void) { gl_Position = matrix_viewProjection * matrix_model * vec4(vertex_position, 1.0); - // store z/w for later use in fragment shader vColor = vertex_color; - vZW = gl_Position.zw; - // disable depth clipping - gl_Position.z = 0.0; + #ifdef GL2 + // store z/w for later use in fragment shader + vZW = gl_Position.zw; + // disable depth clipping + gl_Position.z = 0.0; + #endif }`, 'shader.frag': /* glsl */` precision highp float; @@ -803,8 +803,10 @@ varying vec4 vColor; varying vec2 vZW; void main(void) { gl_FragColor = vColor; - // clamp depth in Z to [0, 1] range - gl_FragDepth = max(0.0, min(1.0, (vZW.x / vZW.y + 1.0) * 0.5)); + #ifdef GL2 + // clamp depth in Z to [0, 1] range + gl_FragDepth = max(0.0, min(1.0, (vZW.x / vZW.y + 1.0) * 0.5)); + #endif }` }; } diff --git a/extras/gizmo/axis-shapes.js b/extras/gizmo/axis-shapes.js index fa19109578a..7f75bb6bdb9 100644 --- a/extras/gizmo/axis-shapes.js +++ b/extras/gizmo/axis-shapes.js @@ -1,13 +1,19 @@ import { + CULLFACE_BACK, + BLEND_NORMAL, + SEMANTIC_POSITION, + SEMANTIC_COLOR, createBox, createCone, createCylinder, createPlane, createMesh, createTorus, + createShaderFromCode, Material, MeshInstance, Entity, + Color, Quat, Vec3 } from 'playcanvas'; @@ -17,6 +23,7 @@ import { MeshTriData } from './mesh-tri-data.js'; // constants const SHADOW_DAMP_SCALE = 0.25; const SHADOW_DAMP_OFFSET = 0.75; +const SHADOW_MESH_MAP = new Map(); const TORUS_RENDER_SEGMENTS = 80; const TORUS_INTERSECT_SEGMENTS = 20; const LIGHT_DIR = new Vec3(1, 2, 3); @@ -27,13 +34,43 @@ const MESH_TEMPLATES = { plane: createPlane, torus: createTorus }; +const SHADER = { + vert: /* glsl */` + attribute vec3 vertex_position; + attribute vec4 vertex_color; + varying vec4 vColor; + varying vec2 vZW; + uniform mat4 matrix_model; + uniform mat4 matrix_viewProjection; + void main(void) { + gl_Position = matrix_viewProjection * matrix_model * vec4(vertex_position, 1.0); + vColor = vertex_color; + #ifdef GL2 + // store z/w for later use in fragment shader + vZW = gl_Position.zw; + // disable depth clipping + gl_Position.z = 0.0; + #endif + }`, + frag: /* glsl */` + precision highp float; + varying vec4 vColor; + varying vec2 vZW; + void main(void) { + gl_FragColor = vColor; + #ifdef GL2 + // clamp depth in Z to [0, 1] range + gl_FragDepth = max(0.0, min(1.0, (vZW.x / vZW.y + 1.0) * 0.5)); + #endif + }` +}; // temporary variables const tmpV1 = new Vec3(); const tmpV2 = new Vec3(); const tmpQ1 = new Quat(); -function createShadowMesh(device, entity, type, templateOpts = {}) { +function createShadowMesh(device, entity, type, color = Color.WHITE, templateOpts = {}) { const createTemplate = MESH_TEMPLATES[type]; if (!createTemplate) { throw new Error('Invalid primitive type.'); @@ -56,12 +93,19 @@ function createShadowMesh(device, entity, type, templateOpts = {}) { wtm.transformVector(tmpV1, tmpV1); tmpV1.normalize(); const numVertices = mesh.vertexBuffer.numVertices; - calculateShadowColors(tmpV1, numVertices, options.normals, options.colors); + const shadow = calculateShadow(tmpV1, numVertices, options.normals); + for (let i = 0; i < shadow.length; i++) { + options.colors.push(shadow[i] * color.r * 255, shadow[i] * color.g * 255, shadow[i] * color.b * 255, color.a * 255); + } + + const shadowMesh = createMesh(device, options.positions, options); + SHADOW_MESH_MAP.set(shadowMesh, shadow); - return createMesh(device, options.positions, options); + return shadowMesh; } -function calculateShadowColors(lightDir, numVertices, normals, colors = []) { +function calculateShadow(lightDir, numVertices, normals) { + const shadow = []; for (let i = 0; i < numVertices; i++) { const x = normals[i * 3]; const y = normals[i * 3 + 1]; @@ -69,11 +113,23 @@ function calculateShadowColors(lightDir, numVertices, normals, colors = []) { tmpV2.set(x, y, z); const dot = lightDir.dot(tmpV2); - const shadow = dot * SHADOW_DAMP_SCALE + SHADOW_DAMP_OFFSET; - colors.push(shadow * 255, shadow * 255, shadow * 255, 1); + shadow.push(dot * SHADOW_DAMP_SCALE + SHADOW_DAMP_OFFSET); } - return colors; + return shadow; +} + +function setShadowMeshColor(mesh, color) { + if (!SHADOW_MESH_MAP.has(mesh)) { + return; + } + const shadow = SHADOW_MESH_MAP.get(mesh); + const colors = []; + for (let i = 0; i < shadow.length; i++) { + colors.push(shadow[i] * color.r * 255, shadow[i] * color.g * 255, shadow[i] * color.b * 255, color.a * 255); + } + mesh.setColors32(colors); + mesh.update(); } class AxisShape { @@ -153,9 +209,20 @@ class AxisShape { } _addRenderMeshes(entity, meshes) { + const shader = createShaderFromCode(this.device, SHADER.vert, SHADER.frag, 'axis-shape', { + vertex_position: SEMANTIC_POSITION, + vertex_color: SEMANTIC_COLOR + }); + + const material = new Material(); + material.shader = shader; + material.cull = CULLFACE_BACK; + material.blendType = BLEND_NORMAL; + material.update(); + const meshInstances = []; for (let i = 0; i < meshes.length; i++) { - const mi = new MeshInstance(meshes[i], this._disabled ? this._disabledMaterial : this._defaultMaterial); + const mi = new MeshInstance(meshes[i], material); meshInstances.push(mi); this.meshInstances.push(mi); } @@ -167,7 +234,8 @@ class AxisShape { } _addRenderShadowMesh(entity, type) { - const mesh = createShadowMesh(this.device, entity, type); + const material = this._disabled ? this._disabledMaterial : this._defaultMaterial; + const mesh = createShadowMesh(this.device, entity, type, material.emissive); this._addRenderMeshes(entity, [mesh]); } @@ -175,9 +243,10 @@ class AxisShape { if (this._disabled) { return; } - const material = state ? this._hoverMaterial : this._defaultMaterial; + for (let i = 0; i < this.meshInstances.length; i++) { - this.meshInstances[i].material = material; + const material = state ? this._hoverMaterial : this._defaultMaterial; + setShadowMeshColor(this.meshInstances[i].mesh, material.emissive); } } @@ -501,7 +570,8 @@ class AxisDisk extends AxisShape { } _createRenderTorus(sectorAngle) { - return createShadowMesh(this.device, this.entity, 'torus', { + const material = this._disabled ? this._disabledMaterial : this._defaultMaterial; + return createShadowMesh(this.device, this.entity, 'torus', material.emissive, { tubeRadius: this._tubeRadius, ringRadius: this._ringRadius, sectorAngle: sectorAngle, From d2681a638c459d59a4c277b44301ab910c9ed1a2 Mon Sep 17 00:00:00 2001 From: kpal Date: Fri, 2 Feb 2024 13:44:12 +0000 Subject: [PATCH 5/6] Changed materials to colors, moved colors to separate file to remove passing in disabled color parameter each time --- examples/src/examples/misc/gizmos.mjs | 1 - extras/gizmo/axis-shapes.js | 45 +++++----- extras/gizmo/default-colors.js | 7 ++ extras/gizmo/rotate-gizmo.js | 20 ++--- extras/gizmo/scale-gizmo.js | 35 +++----- extras/gizmo/transform-gizmo.js | 117 +++++++++----------------- extras/gizmo/translate-gizmo.js | 30 +++---- 7 files changed, 105 insertions(+), 150 deletions(-) create mode 100644 extras/gizmo/default-colors.js diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index 68f50333436..bc98bcfe542 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -584,7 +584,6 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs camera.setPosition(1, 1, 1); app.root.addChild(camera); orbitCamera.distance = 14; - camera.camera.farClip = 12.3; // create 3-point lighting const backLight = new pc.Entity('light'); diff --git a/extras/gizmo/axis-shapes.js b/extras/gizmo/axis-shapes.js index 7f75bb6bdb9..7230ebc3020 100644 --- a/extras/gizmo/axis-shapes.js +++ b/extras/gizmo/axis-shapes.js @@ -1,4 +1,5 @@ import { + CULLFACE_NONE, CULLFACE_BACK, BLEND_NORMAL, SEMANTIC_POSITION, @@ -18,6 +19,7 @@ import { Vec3 } from 'playcanvas'; +import { COLOR_GRAY } from './default-colors.js'; import { MeshTriData } from './mesh-tri-data.js'; // constants @@ -143,11 +145,13 @@ class AxisShape { _disabled; - _defaultMaterial; + _defaultColor = Color.WHITE; - _hoverMaterial; + _hoverColor = Color.BLACK; - _disabledMaterial; + _disabledColor = COLOR_GRAY; + + _cull = CULLFACE_BACK; device; @@ -170,25 +174,20 @@ class AxisShape { this._layers = options.layers ?? this._layers; - if (!(options.defaultMaterial instanceof Material)) { - throw new Error('No default material provided.'); + if (options.defaultColor instanceof Color) { + this._defaultColor = options.defaultColor; } - this._defaultMaterial = options.defaultMaterial; - - if (!(options.hoverMaterial instanceof Material)) { - throw new Error('No hover material provided.'); + if (options.hoverColor instanceof Color) { + this._hoverColor = options.hoverColor; } - this._hoverMaterial = options.hoverMaterial; - - if (!(options.disabledMaterial instanceof Material)) { - throw new Error('No disabled material provided.'); + if (options.disabledColor instanceof Color) { + this._disabledColor = options.disabledColor; } - this._disabledMaterial = options.disabledMaterial; } set disabled(value) { for (let i = 0; i < this.meshInstances.length; i++) { - this.meshInstances[i].material = value ? this._disabledMaterial : this._defaultMaterial; + setShadowMeshColor(this.meshInstances[i].mesh, this._disabledColor); } this._disabled = value ?? false; } @@ -216,7 +215,7 @@ class AxisShape { const material = new Material(); material.shader = shader; - material.cull = CULLFACE_BACK; + material.cull = this._cull; material.blendType = BLEND_NORMAL; material.update(); @@ -234,8 +233,8 @@ class AxisShape { } _addRenderShadowMesh(entity, type) { - const material = this._disabled ? this._disabledMaterial : this._defaultMaterial; - const mesh = createShadowMesh(this.device, entity, type, material.emissive); + const color = this._disabled ? this._disabledColor : this._defaultColor; + const mesh = createShadowMesh(this.device, entity, type, color); this._addRenderMeshes(entity, [mesh]); } @@ -245,8 +244,8 @@ class AxisShape { } for (let i = 0; i < this.meshInstances.length; i++) { - const material = state ? this._hoverMaterial : this._defaultMaterial; - setShadowMeshColor(this.meshInstances[i].mesh, material.emissive); + const color = state ? this._hoverColor : this._defaultColor; + setShadowMeshColor(this.meshInstances[i].mesh, color); } } @@ -570,8 +569,8 @@ class AxisDisk extends AxisShape { } _createRenderTorus(sectorAngle) { - const material = this._disabled ? this._disabledMaterial : this._defaultMaterial; - return createShadowMesh(this.device, this.entity, 'torus', material.emissive, { + const color = this._disabled ? this._disabledColor : this._defaultColor; + return createShadowMesh(this.device, this.entity, 'torus', color, { tubeRadius: this._tubeRadius, ringRadius: this._ringRadius, sectorAngle: sectorAngle, @@ -643,6 +642,8 @@ class AxisDisk extends AxisShape { } class AxisPlane extends AxisShape { + _cull = CULLFACE_NONE; + _size = 0.2; _gap = 0.1; diff --git a/extras/gizmo/default-colors.js b/extras/gizmo/default-colors.js new file mode 100644 index 00000000000..b4b4288f0eb --- /dev/null +++ b/extras/gizmo/default-colors.js @@ -0,0 +1,7 @@ +import { Color } from 'playcanvas'; + +export const COLOR_RED = Object.freeze(new Color(1, 0.3, 0.3)); +export const COLOR_GREEN = Object.freeze(new Color(0.3, 1, 0.3)); +export const COLOR_BLUE = Object.freeze(new Color(0.3, 0.3, 1)); +export const COLOR_YELLOW = Object.freeze(new Color(1, 1, 0.5)); +export const COLOR_GRAY = Object.freeze(new Color(0.5, 0.5, 0.5, 0.5)); diff --git a/extras/gizmo/rotate-gizmo.js b/extras/gizmo/rotate-gizmo.js index b69456fef0c..b90358b3969 100644 --- a/extras/gizmo/rotate-gizmo.js +++ b/extras/gizmo/rotate-gizmo.js @@ -30,36 +30,32 @@ class RotateGizmo extends TransformGizmo { axis: 'z', layers: [this._layer.id], rotation: new Vec3(90, 0, 90), - defaultMaterial: this._materials.axis.z.cullBack, - hoverMaterial: this._materials.hover.z.cullBack, - disabledMaterial: this._materials.disabled.cullBack, + defaultColor: this._meshColors.axis.z, + hoverColor: this._meshColors.hover.z, sectorAngle: 180 }), x: new AxisDisk(this._device, { axis: 'x', layers: [this._layer.id], rotation: new Vec3(0, 0, -90), - defaultMaterial: this._materials.axis.x.cullBack, - hoverMaterial: this._materials.hover.x.cullBack, - disabledMaterial: this._materials.disabled.cullBack, + defaultColor: this._meshColors.axis.x, + hoverColor: this._meshColors.hover.x, sectorAngle: 180 }), y: new AxisDisk(this._device, { axis: 'y', layers: [this._layer.id], rotation: new Vec3(0, 0, 0), - defaultMaterial: this._materials.axis.y.cullBack, - hoverMaterial: this._materials.hover.y.cullBack, - disabledMaterial: this._materials.disabled.cullBack, + defaultColor: this._meshColors.axis.y, + hoverColor: this._meshColors.hover.y, sectorAngle: 180 }), face: new AxisDisk(this._device, { axis: 'face', layers: [this._layer.id], rotation: this._getLookAtEulerAngles(this._camera.entity.getPosition()), - defaultMaterial: this._materials.axis.face, - hoverMaterial: this._materials.hover.face, - disabledMaterial: this._materials.disabled.cullBack, + defaultColor: this._meshColors.axis.face, + hoverColor: this._meshColors.hover.face, ringRadius: 0.55 }) }; diff --git a/extras/gizmo/scale-gizmo.js b/extras/gizmo/scale-gizmo.js index b092340de82..a0af31add86 100644 --- a/extras/gizmo/scale-gizmo.js +++ b/extras/gizmo/scale-gizmo.js @@ -17,60 +17,53 @@ class ScaleGizmo extends TransformGizmo { xyz: new AxisBoxCenter(this._device, { axis: 'xyz', layers: [this._layer.id], - defaultMaterial: this._materials.axis.xyz, - hoverMaterial: this._materials.hover.xyz, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.xyz, + hoverColor: this._meshColors.hover.xyz }), yz: new AxisPlane(this._device, { axis: 'x', flipAxis: 'y', layers: [this._layer.id], rotation: new Vec3(0, 0, -90), - defaultMaterial: this._materials.axis.x.cullNone, - hoverMaterial: this._materials.hover.x.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.x, + hoverColor: this._meshColors.hover.x }), xz: new AxisPlane(this._device, { axis: 'y', flipAxis: 'z', layers: [this._layer.id], rotation: new Vec3(0, 0, 0), - defaultMaterial: this._materials.axis.y.cullNone, - hoverMaterial: this._materials.hover.y.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.y, + hoverColor: this._meshColors.hover.y }), xy: new AxisPlane(this._device, { axis: 'z', flipAxis: 'x', layers: [this._layer.id], rotation: new Vec3(90, 0, 0), - defaultMaterial: this._materials.axis.z.cullNone, - hoverMaterial: this._materials.hover.z.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.z, + hoverColor: this._meshColors.hover.z }), x: new AxisBoxLine(this._device, { axis: 'x', layers: [this._layer.id], rotation: new Vec3(0, 0, -90), - defaultMaterial: this._materials.axis.x.cullBack, - hoverMaterial: this._materials.hover.x.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.x, + hoverColor: this._meshColors.hover.x }), y: new AxisBoxLine(this._device, { axis: 'y', layers: [this._layer.id], rotation: new Vec3(0, 0, 0), - defaultMaterial: this._materials.axis.y.cullBack, - hoverMaterial: this._materials.hover.y.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.y, + hoverColor: this._meshColors.hover.y }), z: new AxisBoxLine(this._device, { axis: 'z', layers: [this._layer.id], rotation: new Vec3(90, 0, 0), - defaultMaterial: this._materials.axis.z.cullBack, - hoverMaterial: this._materials.hover.z.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.z, + hoverColor: this._meshColors.hover.z }) }; diff --git a/extras/gizmo/transform-gizmo.js b/extras/gizmo/transform-gizmo.js index ed50d43fec7..f970e589d4c 100644 --- a/extras/gizmo/transform-gizmo.js +++ b/extras/gizmo/transform-gizmo.js @@ -1,16 +1,19 @@ import { math, - CULLFACE_NONE, - CULLFACE_BACK, PROJECTION_PERSPECTIVE, PROJECTION_ORTHOGRAPHIC, - BLEND_NORMAL, Color, - StandardMaterial, Vec3, Quat } from 'playcanvas'; +import { + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE, + COLOR_YELLOW, + COLOR_GRAY +} from './default-colors.js'; import { Gizmo } from "./gizmo.js"; // temporary variables @@ -27,16 +30,15 @@ const FACING_EPSILON = 0.2; const SPANLINE_SIZE = 1e3; const ROTATE_SCALE = 900; -const RED_COLOR = new Color(1, 0.3, 0.3); -const SEMI_RED_COLOR = new Color(1, 0.3, 0.3, 0.6); -const GREEN_COLOR = new Color(0.3, 1, 0.3); -const SEMI_GREEN_COLOR = new Color(0.3, 1, 0.3, 0.6); -const BLUE_COLOR = new Color(0.3, 0.3, 1); -const SEMI_BLUE_COLOR = new Color(0.3, 0.3, 1, 0.6); -const YELLOW_COLOR = new Color(1, 1, 0.5); -const WHITE_COLOR = new Color(1, 1, 1); -const SEMI_WHITE_COLOR = new Color(1, 1, 1, 0.6); -const GRAY_COLOR = new Color(0.5, 0.5, 0.5, 0.5); +/** + * @param {Color} color - The color. + * @returns {Color} - The semi transparent color. + */ +const colorSemi = (color) => { + const clone = color.clone(); + clone.a = 0.6; + return clone; +}; /** * Shape axis for the line X. @@ -138,48 +140,27 @@ class TransformGizmo extends Gizmo { static EVENT_TRANSFORMEND = 'transform:end'; /** - * Internal material objects for mesh instances. + * Internal color for meshs. * * @type {Object} * @protected */ - _materials = { + _meshColors = { axis: { - x: { - cullBack: this._createMaterial(SEMI_RED_COLOR), - cullNone: this._createMaterial(SEMI_RED_COLOR, CULLFACE_NONE) - }, - y: { - cullBack: this._createMaterial(SEMI_GREEN_COLOR), - cullNone: this._createMaterial(SEMI_GREEN_COLOR, CULLFACE_NONE) - }, - z: { - cullBack: this._createMaterial(SEMI_BLUE_COLOR), - cullNone: this._createMaterial(SEMI_BLUE_COLOR, CULLFACE_NONE) - }, - face: this._createMaterial(SEMI_WHITE_COLOR), - xyz: this._createMaterial(SEMI_WHITE_COLOR) + x: colorSemi(COLOR_RED), + y: colorSemi(COLOR_GREEN), + z: colorSemi(COLOR_BLUE), + xyz: colorSemi(Color.WHITE), + face: colorSemi(Color.WHITE) }, hover: { - x: { - cullBack: this._createMaterial(RED_COLOR), - cullNone: this._createMaterial(RED_COLOR, CULLFACE_NONE) - }, - y: { - cullBack: this._createMaterial(GREEN_COLOR), - cullNone: this._createMaterial(GREEN_COLOR, CULLFACE_NONE) - }, - z: { - cullBack: this._createMaterial(BLUE_COLOR), - cullNone: this._createMaterial(BLUE_COLOR, CULLFACE_NONE) - }, - face: this._createMaterial(YELLOW_COLOR), - xyz: this._createMaterial(WHITE_COLOR) + x: COLOR_RED.clone(), + y: COLOR_GREEN.clone(), + z: COLOR_BLUE.clone(), + xyz: Color.WHITE.clone(), + face: COLOR_YELLOW.clone() }, - disabled: { - cullBack: this._createMaterial(GRAY_COLOR), - cullNone: this._createMaterial(GRAY_COLOR, CULLFACE_NONE) - } + disabled: COLOR_GRAY.clone() }; /** @@ -189,10 +170,10 @@ class TransformGizmo extends Gizmo { * @protected */ _guideColors = { - x: RED_COLOR, - y: GREEN_COLOR, - z: BLUE_COLOR, - face: YELLOW_COLOR + x: COLOR_RED.clone(), + y: COLOR_GREEN.clone(), + z: COLOR_BLUE.clone(), + face: COLOR_YELLOW.clone() }; /** @@ -421,7 +402,7 @@ class TransformGizmo extends Gizmo { } get xAxisColor() { - return this._materials.axis.x.cullBack.emissive; + return this._meshColors.axis.x; } /** @@ -434,7 +415,7 @@ class TransformGizmo extends Gizmo { } get yAxisColor() { - return this._materials.axis.y.cullBack.emissive; + return this._meshColors.axis.y; } /** @@ -447,21 +428,17 @@ class TransformGizmo extends Gizmo { } get zAxisColor() { - return this._materials.axis.z.cullBack.emissive; + return this._meshColors.axis.z; } _updateAxisColor(axis, value) { this._guideColors[axis].copy(value); + this._meshColors.axis[axis].copy(colorSemi(value)); + this._meshColors.hover[axis].copy(value); - this._materials.axis[axis].cullBack.emissive.copy(value); - this._materials.axis[axis].cullNone.emissive.copy(value); - this._materials.hover[axis].cullBack.emissive.copy(value); - this._materials.hover[axis].cullNone.emissive.copy(value); - - this._materials.axis[axis].cullBack.update(); - this._materials.axis[axis].cullNone.update(); - this._materials.hover[axis].cullBack.update(); - this._materials.hover[axis].cullNone.update(); + for (const name in this._shapes) { + this._shapes[name].hover(!!this._hoverAxis); + } } _getAxis(meshInstance) { @@ -671,18 +648,6 @@ class TransformGizmo extends Gizmo { this._app.drawLine(tmpV1.add(pos), tmpV2.add(pos), this._guideColors[axis], true); } - _createMaterial(color, cull = CULLFACE_BACK) { - const material = new StandardMaterial(); - material.emissive = color; - material.emissiveVertexColor = true; - material.cull = cull; - material.blendType = BLEND_NORMAL; - if (color.a !== 1) { - material.opacity = color.a; - } - return material; - } - _createTransform() { // shapes for (const key in this._shapes) { diff --git a/extras/gizmo/translate-gizmo.js b/extras/gizmo/translate-gizmo.js index 923a504a1ef..2effcf56134 100644 --- a/extras/gizmo/translate-gizmo.js +++ b/extras/gizmo/translate-gizmo.js @@ -25,51 +25,45 @@ class TranslateGizmo extends TransformGizmo { flipAxis: 'y', layers: [this._layer.id], rotation: new Vec3(0, 0, -90), - defaultMaterial: this._materials.axis.x.cullNone, - hoverMaterial: this._materials.hover.x.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.x, + hoverColor: this._meshColors.hover.x }), xz: new AxisPlane(this._device, { axis: 'y', flipAxis: 'z', layers: [this._layer.id], rotation: new Vec3(0, 0, 0), - defaultMaterial: this._materials.axis.y.cullNone, - hoverMaterial: this._materials.hover.y.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.y, + hoverColor: this._meshColors.hover.y }), xy: new AxisPlane(this._device, { axis: 'z', flipAxis: 'x', layers: [this._layer.id], rotation: new Vec3(90, 0, 0), - defaultMaterial: this._materials.axis.z.cullNone, - hoverMaterial: this._materials.hover.z.cullNone, - disabledMaterial: this._materials.disabled.cullNone + defaultColor: this._meshColors.axis.z, + hoverColor: this._meshColors.hover.z }), x: new AxisArrow(this._device, { axis: 'x', layers: [this._layer.id], rotation: new Vec3(0, 0, -90), - defaultMaterial: this._materials.axis.x.cullBack, - hoverMaterial: this._materials.hover.x.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.x, + hoverColor: this._meshColors.hover.x }), y: new AxisArrow(this._device, { axis: 'y', layers: [this._layer.id], rotation: new Vec3(0, 0, 0), - defaultMaterial: this._materials.axis.y.cullBack, - hoverMaterial: this._materials.hover.y.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.y, + hoverColor: this._meshColors.hover.y }), z: new AxisArrow(this._device, { axis: 'z', layers: [this._layer.id], rotation: new Vec3(90, 0, 0), - defaultMaterial: this._materials.axis.z.cullBack, - hoverMaterial: this._materials.hover.z.cullBack, - disabledMaterial: this._materials.disabled.cullBack + defaultColor: this._meshColors.axis.z, + hoverColor: this._meshColors.hover.z }) }; From cba30625966bf22f71666b55f72733685a5f9fcb Mon Sep 17 00:00:00 2001 From: kpal Date: Fri, 2 Feb 2024 15:00:34 +0000 Subject: [PATCH 6/6] Reverted example grid to use non shader variant --- examples/src/examples/misc/gizmos.mjs | 139 +++----------------------- 1 file changed, 15 insertions(+), 124 deletions(-) diff --git a/examples/src/examples/misc/gizmos.mjs b/examples/src/examples/misc/gizmos.mjs index bc98bcfe542..cffa4209b0d 100644 --- a/examples/src/examples/misc/gizmos.mjs +++ b/examples/src/examples/misc/gizmos.mjs @@ -234,7 +234,7 @@ function controls({ observer, ReactPCUI, React, jsx, fragment }) { * @param {import('../../options.mjs').ExampleOptions} options - The example options. * @returns {Promise} The example application. */ -async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgslPath, scriptsPath }) { +async function example({ pcx, canvas, deviceType, data, glslangPath, twgslPath, scriptsPath }) { // class for handling gizmos class GizmoHandler { @@ -459,79 +459,6 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs return material; } - /** - * @param {pc.Shader} shader - The shader. - * @returns {pc.Material} - The standard material. - */ - function createShaderMaterial(shader) { - const material = new pc.Material(); - material.shader = shader; - material.blendType = pc.BLEND_NONE; - material.update(); - return material; - } - - /** - * @param {{ gridSize: number }} options - Grid mesh options. - * @returns {pc.Mesh} - The mesh. - */ - function createGridMesh(options) { - const gridSize = options.gridSize ?? 4; - - const vertexFormat = new pc.VertexFormat(device, [{ - semantic: pc.SEMANTIC_POSITION, - components: 3, - type: pc.TYPE_FLOAT32 - }, { - semantic: pc.SEMANTIC_COLOR, - components: 4, - type: pc.TYPE_UINT8, - normalize: true - }]); - - - const numLines = gridSize + 1; - - const gridData = new Float32Array(numLines * 4 * 4); - const clrData = new Uint32Array(gridData.buffer); - - for (let i = 0; i < numLines; i++) { - const a = (i / (numLines - 1) - 0.5) * gridSize; - const b = gridSize / 2; - const idx = i * 16; - const clr = i === Math.floor(numLines / 2) ? 0xff000000 : 0xffa0a0a0; - - gridData[idx + 0] = a; - gridData[idx + 1] = 0; - gridData[idx + 2] = -b; - clrData[idx + 3] = clr; - - gridData[idx + 4] = a; - gridData[idx + 5] = 0; - gridData[idx + 6] = b; - clrData[idx + 7] = clr; - - gridData[idx + 8] = -b; - gridData[idx + 9] = 0; - gridData[idx + 10] = a; - clrData[idx + 11] = clr; - - gridData[idx + 12] = b; - gridData[idx + 13] = 0; - gridData[idx + 14] = a; - clrData[idx + 15] = clr; - } - - const mesh = new pc.Mesh(device); - mesh.vertexBuffer = new pc.VertexBuffer(device, vertexFormat, numLines * 4, pc.BUFFER_STATIC, gridData.buffer); - mesh.primitive[0].type = pc.PRIMITIVE_LINES; - mesh.primitive[0].base = 0; - mesh.primitive[0].indexed = false; - mesh.primitive[0].count = numLines * 4; - - return mesh; - } - // create entities const box = new pc.Entity('box'); box.addComponent('render', { @@ -608,11 +535,6 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs keyLight.setEulerAngles(0, 0, -60); // create layers - const debugLayer = new pc.Layer({ - name: 'Debug Layer', - opaqueSortMode: pc.SORTMODE_NONE, - transparentSortMode: pc.SORTMODE_NONE - }); const gizmoLayer = new pc.Layer({ name: 'Gizmo', clearDepthBuffer: true, @@ -620,14 +542,8 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs transparentSortMode: pc.SORTMODE_NONE }); const layers = app.scene.layers; - const worldLayer = layers.getLayerByName('World'); - const idx = layers.getOpaqueIndex(worldLayer); - layers.insert(debugLayer, idx + 1); layers.push(gizmoLayer); - camera.camera.layers = camera.camera.layers.concat([ - debugLayer.id, - gizmoLayer.id - ]); + camera.camera.layers = camera.camera.layers.concat(gizmoLayer.id); // create gizmo const gizmoHandler = new GizmoHandler(app, camera.camera, gizmoLayer); @@ -727,6 +643,7 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs // picker const picker = new pc.Picker(app, canvas.clientWidth, canvas.clientHeight); + const worldLayer = layers.getLayerByName('World'); const pickerLayers = [worldLayer]; const onPointerDown = (/** @type {PointerEvent} */ e) => { @@ -750,16 +667,20 @@ async function example({ pcx, canvas, deviceType, files, data, glslangPath, twgs window.addEventListener('pointerdown', onPointerDown); // grid - const shader = pc.createShaderFromCode(device, files['shader.vert'], files['shader.frag'], 'grid-lines', { - vertex_position: pc.SEMANTIC_POSITION, - vertex_color: pc.SEMANTIC_COLOR + const gridColor = new pc.Color(1, 1, 1, 0.5); + const gridHalfSize = 4; + /** + * @type {pc.Vec3[]} + */ + const gridLines = []; + for (let i = 0; i < gridHalfSize * 2 + 1; i++) { + gridLines.push(new pc.Vec3(-gridHalfSize, 0, i - gridHalfSize), new pc.Vec3(gridHalfSize, 0, i - gridHalfSize)); + gridLines.push(new pc.Vec3(i - gridHalfSize, 0, -gridHalfSize), new pc.Vec3(i - gridHalfSize, 0, gridHalfSize)); + } + app.on('update', () => { + app.drawLines(gridLines, gridColor); }); - const mesh = createGridMesh({ gridSize: 8 }); - const material = createShaderMaterial(shader); - const meshInstance = new pc.MeshInstance(mesh, material, new pc.GraphNode()); - debugLayer.addMeshInstances([meshInstance], true); - app.on('destroy', () => { gizmoHandler.destroy(); @@ -778,36 +699,6 @@ class GizmosExample { static WEBGPU_ENABLED = false; static controls = controls; static example = example; - static FILES = { - 'shader.vert': /* glsl */` -attribute vec3 vertex_position; -attribute vec4 vertex_color; -varying vec4 vColor; -varying vec2 vZW; -uniform mat4 matrix_model; -uniform mat4 matrix_viewProjection; -void main(void) { - gl_Position = matrix_viewProjection * matrix_model * vec4(vertex_position, 1.0); - vColor = vertex_color; - #ifdef GL2 - // store z/w for later use in fragment shader - vZW = gl_Position.zw; - // disable depth clipping - gl_Position.z = 0.0; - #endif -}`, - 'shader.frag': /* glsl */` -precision highp float; -varying vec4 vColor; -varying vec2 vZW; -void main(void) { - gl_FragColor = vColor; - #ifdef GL2 - // clamp depth in Z to [0, 1] range - gl_FragDepth = max(0.0, min(1.0, (vZW.x / vZW.y + 1.0) * 0.5)); - #endif -}` - }; } export { GizmosExample };