diff --git a/packages/g-plugin-3d/src/geometries/CubeGeometry.ts b/packages/g-plugin-3d/src/geometries/CubeGeometry.ts index eb3548e48..1326baa39 100644 --- a/packages/g-plugin-3d/src/geometries/CubeGeometry.ts +++ b/packages/g-plugin-3d/src/geometries/CubeGeometry.ts @@ -150,7 +150,7 @@ export class CubeGeometry extends ProceduralGeometry { return [ { bufferIndex: ProceduralGeometryAttributeLocation.POSITION, - location: VertexAttributeLocation.POSITION, + location: VertexAttributeLocation.MAX, data: p, }, ]; diff --git a/packages/g-plugin-3d/src/geometries/PlaneGeometry.ts b/packages/g-plugin-3d/src/geometries/PlaneGeometry.ts index ded930d86..5fe2362b5 100644 --- a/packages/g-plugin-3d/src/geometries/PlaneGeometry.ts +++ b/packages/g-plugin-3d/src/geometries/PlaneGeometry.ts @@ -86,7 +86,7 @@ export class PlaneGeometry extends ProceduralGeometry { return [ { bufferIndex: ProceduralGeometryAttributeLocation.POSITION, - location: VertexAttributeLocation.POSITION, + location: VertexAttributeLocation.MAX, data: p, }, ]; diff --git a/packages/g-plugin-3d/src/geometries/ProceduralGeometry.ts b/packages/g-plugin-3d/src/geometries/ProceduralGeometry.ts index 665b204c3..2047cd653 100644 --- a/packages/g-plugin-3d/src/geometries/ProceduralGeometry.ts +++ b/packages/g-plugin-3d/src/geometries/ProceduralGeometry.ts @@ -100,7 +100,7 @@ export abstract class ProceduralGeometry extends BufferGeometry extends BufferGeometry extends BufferGeometry { return [ { bufferIndex: ProceduralGeometryAttributeLocation.POSITION, - location: VertexAttributeLocation.POSITION, + location: VertexAttributeLocation.MAX, data: p, }, ]; diff --git a/packages/g-plugin-3d/src/lights/AmbientLight.ts b/packages/g-plugin-3d/src/lights/AmbientLight.ts index 735eb78f3..62e65a98d 100644 --- a/packages/g-plugin-3d/src/lights/AmbientLight.ts +++ b/packages/g-plugin-3d/src/lights/AmbientLight.ts @@ -1,5 +1,5 @@ import { DisplayObjectConfig, PARSED_COLOR_TYPE, Tuple4Number } from '@antv/g'; -import { Light, LightProps, fillVec4 } from '@antv/g-plugin-webgl-renderer'; +import { Light, LightProps, RenderInstUniform } from '@antv/g-plugin-webgl-renderer'; export interface AmbientLightProps extends LightProps {} export class AmbientLight extends Light { @@ -16,18 +16,19 @@ export class AmbientLight extends Light { }); } - getUniformWordCount() { - return 4; - } + // getUniformWordCount() { + // return 4; + // } - uploadUBO(d: Float32Array, offs: number) { + uploadUBO(uniforms: RenderInstUniform[], index: number) { const { fill } = this.parsedStyle; if (fill?.type === PARSED_COLOR_TYPE.Constant) { const fillColor = fill.value as Tuple4Number; - offs += fillVec4(d, offs, ...fillColor); // color + uniforms.push({ + name: 'u_AmbientLightColor', + value: fillColor, + }); } - - return offs; } } diff --git a/packages/g-plugin-3d/src/lights/DirectionalLight.ts b/packages/g-plugin-3d/src/lights/DirectionalLight.ts index 9b0bc6cf7..e95ad98bd 100644 --- a/packages/g-plugin-3d/src/lights/DirectionalLight.ts +++ b/packages/g-plugin-3d/src/lights/DirectionalLight.ts @@ -1,5 +1,5 @@ import { DisplayObjectConfig, PARSED_COLOR_TYPE, Tuple4Number } from '@antv/g'; -import { Light, LightProps, fillVec4 } from '@antv/g-plugin-webgl-renderer'; +import { Light, LightProps, RenderInstUniform } from '@antv/g-plugin-webgl-renderer'; import { vec3 } from 'gl-matrix'; export interface DirectionalLightProps extends LightProps { @@ -24,15 +24,23 @@ export class DirectionalLight extends Light { return 4 + 4; } - uploadUBO(d: Float32Array, offs: number) { + uploadUBO(uniforms: RenderInstUniform[], index: number) { const { fill, direction, intensity } = this.parsedStyle; if (fill?.type === PARSED_COLOR_TYPE.Constant) { const fillColor = fill.value as Tuple4Number; - offs += fillVec4(d, offs, ...(direction as [number, number, number]), intensity); // direction - offs += fillVec4(d, offs, ...fillColor); // color + uniforms.push({ + name: `directionalLights[${index}].direction`, + value: direction, + }); + uniforms.push({ + name: `directionalLights[${index}].intensity`, + value: intensity, + }); + uniforms.push({ + name: `directionalLights[${index}].color`, + value: fillColor.slice(0, 3), + }); } - - return offs; } } diff --git a/packages/g-plugin-3d/src/materials/MeshBasicMaterial.ts b/packages/g-plugin-3d/src/materials/MeshBasicMaterial.ts index 8f25c40f9..00c75c3b3 100644 --- a/packages/g-plugin-3d/src/materials/MeshBasicMaterial.ts +++ b/packages/g-plugin-3d/src/materials/MeshBasicMaterial.ts @@ -1,4 +1,10 @@ -import { Material, Texture2D, CullMode, IMaterial, Format } from '@antv/g-plugin-webgl-renderer'; +import { + Material, + Texture2D, + CullMode, + IMaterial, + VertexAttributeLocation, +} from '@antv/g-plugin-webgl-renderer'; import vert from '../shaders/material.basic.vert'; import frag from '../shaders/material.basic.frag'; @@ -72,6 +78,9 @@ export class MeshBasicMaterial extends Material USE_WIREFRAME: false, USE_FOG: false, USE_LIGHT: false, + POSITION: VertexAttributeLocation.MAX, + UV: VertexAttributeLocation.MAX + 2, + BARYCENTRIC: VertexAttributeLocation.MAX + 3, }; const { map, wireframe } = props || {}; @@ -80,10 +89,8 @@ export class MeshBasicMaterial extends Material } this.wireframe = wireframe; - this.addUniform({ - name: Uniform.PLACE_HOLDER, - format: Format.F32_RGBA, - data: [0, 0, 0, 0], + this.setUniforms({ + [Uniform.PLACE_HOLDER]: [0, 0, 0, 0], }); } } diff --git a/packages/g-plugin-3d/src/materials/MeshPhongMaterial.ts b/packages/g-plugin-3d/src/materials/MeshPhongMaterial.ts index da3a4f3c7..9c22c40ce 100644 --- a/packages/g-plugin-3d/src/materials/MeshPhongMaterial.ts +++ b/packages/g-plugin-3d/src/materials/MeshPhongMaterial.ts @@ -1,5 +1,5 @@ import { parseColor, Tuple4Number } from '@antv/g'; -import { Format, Texture2D } from '@antv/g-plugin-webgl-renderer'; +import { Format, Texture2D, VertexAttributeLocation } from '@antv/g-plugin-webgl-renderer'; import { MeshBasicMaterial, IMeshBasicMaterial } from './MeshBasicMaterial'; import vert from '../shaders/material.phong.vert'; import frag from '../shaders/material.phong.frag'; @@ -35,7 +35,9 @@ export class MeshPhongMaterial extends MeshBasicMaterial { set emissive(v) { this.props.emissive = v; const emissiveColor = parseColor(v).value as Tuple4Number; - this.updateUniformData(Uniform.EMISSIVE, emissiveColor.slice(0, 3) as [number, number, number]); + this.setUniforms({ + [Uniform.EMISSIVE]: emissiveColor.slice(0, 3) as [number, number, number], + }); } get shininess() { @@ -43,7 +45,9 @@ export class MeshPhongMaterial extends MeshBasicMaterial { } set shininess(v) { this.props.shininess = v; - this.updateUniformData(Uniform.SHININESS, v); + this.setUniforms({ + [Uniform.SHININESS]: v, + }); } get specular() { @@ -52,7 +56,9 @@ export class MeshPhongMaterial extends MeshBasicMaterial { set specular(v) { this.props.specular = v; const specularColor = parseColor(v).value as Tuple4Number; - this.updateUniformData(Uniform.SPECULAR, specularColor.slice(0, 3) as [number, number, number]); + this.setUniforms({ + [Uniform.SPECULAR]: specularColor.slice(0, 3) as [number, number, number], + }); } get specularMap() { @@ -84,14 +90,14 @@ export class MeshPhongMaterial extends MeshBasicMaterial { this.defines.USE_BUMPMAP = !!v; if (v) { this.addTexture(v, Uniform.BUMP_MAP, SamplerLocation.BUMP_MAP); - this.addUniform({ - name: Uniform.BUMP_SCALE, - format: Format.F32_R, - data: this.bumpScale, + this.setUniforms({ + [Uniform.BUMP_SCALE]: this.bumpScale, }); } else { this.removeTexture(Uniform.BUMP_MAP); - this.removeUniform(Uniform.BUMP_SCALE); + this.setUniforms({ + [Uniform.BUMP_SCALE]: null, + }); } } get bumpScale() { @@ -99,7 +105,9 @@ export class MeshPhongMaterial extends MeshBasicMaterial { } set bumpScale(v) { this.props.bumpScale = v; - this.updateUniformData(Uniform.BUMP_SCALE, v); + this.setUniforms({ + [Uniform.BUMP_SCALE]: v, + }); } get doubleSide() { @@ -126,21 +134,11 @@ export class MeshPhongMaterial extends MeshBasicMaterial { const emissiveColor = parseColor(emissive).value as Tuple4Number; const specularColor = parseColor(specular).value as Tuple4Number; - this.removeUniform('u_Placeholder'); - this.addUniform({ - name: Uniform.EMISSIVE, - format: Format.F32_RGB, - data: emissiveColor, - }); - this.addUniform({ - name: Uniform.SHININESS, - format: Format.F32_R, - data: shininess, - }); - this.addUniform({ - name: Uniform.SPECULAR, - format: Format.F32_RGB, - data: specularColor, + this.setUniforms({ + u_Placeholder: null, + [Uniform.EMISSIVE]: emissiveColor.slice(0, 3) as [number, number, number], + [Uniform.SHININESS]: shininess, + [Uniform.SPECULAR]: specularColor.slice(0, 3) as [number, number, number], }); if (specularMap) { @@ -152,5 +150,10 @@ export class MeshPhongMaterial extends MeshBasicMaterial { } this.doubleSide = doubleSide; + + this.defines = { + ...this.defines, + NORMAL: VertexAttributeLocation.MAX + 1, + }; } } diff --git a/packages/g-plugin-3d/src/shaders/material.basic.vert b/packages/g-plugin-3d/src/shaders/material.basic.vert index 86357daac..7d019a02b 100644 --- a/packages/g-plugin-3d/src/shaders/material.basic.vert +++ b/packages/g-plugin-3d/src/shaders/material.basic.vert @@ -4,15 +4,15 @@ #pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') #pragma glslify: project = require('@antv/g-shader-components/project.vert') -layout(location = 10) attribute vec3 a_Position; +layout(location = POSITION) attribute vec3 a_Position; #ifdef USE_UV - layout(location = 12) attribute vec2 a_Uv; + layout(location = UV) attribute vec2 a_Uv; varying vec2 v_Uv; #endif #ifdef USE_WIREFRAME - layout(location = 13) attribute vec3 a_Barycentric; + layout(location = BARYCENTRIC) attribute vec3 a_Barycentric; varying vec3 v_Barycentric; #endif diff --git a/packages/g-plugin-3d/src/shaders/material.phong.vert b/packages/g-plugin-3d/src/shaders/material.phong.vert index 8866ebe11..cac315876 100644 --- a/packages/g-plugin-3d/src/shaders/material.phong.vert +++ b/packages/g-plugin-3d/src/shaders/material.phong.vert @@ -6,16 +6,16 @@ #pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') #pragma glslify: project = require('@antv/g-shader-components/project.vert') -layout(location = 10) attribute vec3 a_Position; -layout(location = 11) attribute vec3 a_Normal; +layout(location = POSITION) attribute vec3 a_Position; +layout(location = NORMAL) attribute vec3 a_Normal; #ifdef USE_UV - layout(location = 12) attribute vec2 a_Uv; + layout(location = UV) attribute vec2 a_Uv; varying vec2 v_Uv; #endif #ifdef USE_WIREFRAME - layout(location = 13) attribute vec3 a_Barycentric; + layout(location = BARYCENTRIC) attribute vec3 a_Barycentric; varying vec3 v_Barycentric; #endif @@ -34,7 +34,7 @@ void main() { // v_ViewPosition = vec3(mvPosition) / mvPosition.w; - mat3 normalWorld = mat3(transpose(inverse(u_ViewMatrix * u_ModelMatrix))); + mat3 normalWorld = mat3(transposeMat3(inverseMat3(mat3(u_ViewMatrix * u_ModelMatrix)))); v_Normal = normalize(normalWorld * a_Normal); #pragma glslify: import('@antv/g-shader-components/uv.vert') diff --git a/packages/g-plugin-webgl-renderer/src/RenderGraphPlugin.ts b/packages/g-plugin-webgl-renderer/src/RenderGraphPlugin.ts index 0cb143240..57eb70ea1 100644 --- a/packages/g-plugin-webgl-renderer/src/RenderGraphPlugin.ts +++ b/packages/g-plugin-webgl-renderer/src/RenderGraphPlugin.ts @@ -42,6 +42,16 @@ import { import { Fog, Light } from './lights'; import { LightPool } from './LightPool'; +// uniforms in scene level +export enum SceneUniform { + PROJECTION_MATRIX = 'u_ProjectionMatrix', + VIEW_MATRIX = 'u_ViewMatrix', + CAMERA_POSITION = 'u_CameraPosition', + DEVICE_PIXEL_RATIO = 'u_DevicePixelRatio', + VIEWPORT = 'u_Viewport', + IS_ORTHO = 'u_IsOrtho', +} + @singleton({ contrib: RenderingPluginContribution }) export class RenderGraphPlugin implements RenderingPlugin { static tag = 'RenderGraphPlugin'; @@ -78,9 +88,7 @@ export class RenderGraphPlugin implements RenderingPlugin { private swapChain: SwapChain; private renderLists = { - skyscape: new RenderInstList(), world: new RenderInstList(), - picking: new RenderInstList(), }; /** @@ -230,7 +238,7 @@ export class RenderGraphPlugin implements RenderingPlugin { rgbBlendMode: BlendMode.Add, alphaBlendMode: BlendMode.Add, rgbBlendSrcFactor: BlendFactor.SrcAlpha, - alphaBlendSrcFactor: BlendFactor.One, + alphaBlendSrcFactor: BlendFactor.Zero, rgbBlendDstFactor: BlendFactor.OneMinusSrcAlpha, alphaBlendDstFactor: BlendFactor.One, }, @@ -238,13 +246,33 @@ export class RenderGraphPlugin implements RenderingPlugin { ); // Update Scene Params - let offs = template.allocateUniformBuffer(0, 16 + 16 + 4 + 4); - let d = template.mapUniformBufferF32(0); - offs += fillMatrix4x4(d, offs, this.camera.getPerspective()); // ProjectionMatrix 16 - offs += fillMatrix4x4(d, offs, this.camera.getViewTransform()); // ViewMatrix 16 - offs += fillVec3v(d, offs, this.camera.getPosition(), this.contextService.getDPR()); // CameraPosition DPR isOrtho 4 const { width, height } = this.canvasConfig; - offs += fillVec4(d, offs, width, height, this.camera.isOrtho() ? 1 : 0); // Viewport isOrtho + template.setUniforms(0, [ + { + name: SceneUniform.PROJECTION_MATRIX, + value: this.camera.getPerspective(), + }, + { + name: SceneUniform.VIEW_MATRIX, + value: this.camera.getViewTransform(), + }, + { + name: SceneUniform.CAMERA_POSITION, + value: this.camera.getPosition(), + }, + { + name: SceneUniform.DEVICE_PIXEL_RATIO, + value: this.contextService.getDPR(), + }, + { + name: SceneUniform.VIEWPORT, + value: [width, height], + }, + { + name: SceneUniform.IS_ORTHO, + value: this.camera.isOrtho() ? 1 : 0, + }, + ]); renderInstManager.setCurrentRenderInstList(this.renderLists.world); // render batches diff --git a/packages/g-plugin-webgl-renderer/src/Texture2D.ts b/packages/g-plugin-webgl-renderer/src/Texture2D.ts index e88c1d574..0aeda8c47 100644 --- a/packages/g-plugin-webgl-renderer/src/Texture2D.ts +++ b/packages/g-plugin-webgl-renderer/src/Texture2D.ts @@ -19,9 +19,9 @@ export class Texture2D { descriptor.sampler = { wrapS: WrapMode.Clamp, wrapT: WrapMode.Clamp, - minFilter: TexFilterMode.Bilinear, + minFilter: TexFilterMode.Point, magFilter: TexFilterMode.Bilinear, - mipFilter: MipFilterMode.NoMip, + mipFilter: MipFilterMode.Linear, minLOD: 0, maxLOD: 0, ...descriptor.sampler, diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/Batch.ts b/packages/g-plugin-webgl-renderer/src/drawcall/Batch.ts index 5618a3f48..e4ee09b3a 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/Batch.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/Batch.ts @@ -20,23 +20,6 @@ export interface Batch { afterRender?(list: RenderInstList): void; } -export enum AttributeLocation { - // TODO: bind mat4 in WebGL2 instead of decomposed 4 * vec4? - // @see https://stackoverflow.com/questions/38853096/webgl-how-to-bind-values-to-a-mat4-attribute/38853623#38853623 - a_ModelMatrix0, - a_ModelMatrix1, - a_ModelMatrix2, - a_ModelMatrix3, // model matrix - a_Color, // fill color - a_StrokeColor, // stroke color - a_StylePacked1, // opacity fillOpacity strokeOpacity lineWidth - a_StylePacked2, // visibility - a_PickingColor, // picking color - a_Anchor, // anchor - // a_Uv, // UV - MAX, -} - /** * A container for multiple display objects with the same `style`, * eg. 1000 Circles with the same stroke color, but their position, radius can be different diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/BatchMesh.ts b/packages/g-plugin-webgl-renderer/src/drawcall/BatchMesh.ts index c88faaed7..279e9c40f 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/BatchMesh.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/BatchMesh.ts @@ -10,8 +10,13 @@ import { } from '@antv/g'; import type { Tuple4Number } from '@antv/g'; import { inject, injectable } from 'mana-syringe'; -import { mat3, mat4 } from 'gl-matrix'; -import { BufferGeometry, Geometry, makeStaticDataBuffer } from '../geometries'; +import { mat4 } from 'gl-matrix'; +import { + BufferGeometry, + Geometry, + makeStaticDataBuffer, + VertexAttributeLocation, +} from '../geometries'; import { Material, ShaderMaterial } from '../materials'; import { BindingLayoutSamplerDescriptor, @@ -29,15 +34,15 @@ import { } from '../platform'; import { DeviceProgram, - fillVec4, makeSortKeyOpaque, RendererLayer, RenderHelper, RenderInst, + RenderInstUniform, TextureMapping, } from '../render'; import { preprocessProgramObj_GLSL, ProgramDescriptorSimpleWithOrig } from '../shader/compiler'; -import { AttributeLocation, RENDER_ORDER_SCALE, Batch } from './Batch'; +import { RENDER_ORDER_SCALE, Batch } from './Batch'; import { TexturePool } from '../TexturePool'; import { Fog } from '../lights'; import { LightPool } from '../LightPool'; @@ -74,6 +79,11 @@ export abstract class BatchMesh { private program: DeviceProgram = new DeviceProgram(); private programDescriptorSimpleWithOrig?: ProgramDescriptorSimpleWithOrig; geometryDirty = true; + + /** + * the same material maybe shared between different canvases + */ + materialDirty = true; private inputStateDirty = true; /** * texture mappings @@ -87,8 +97,11 @@ export abstract class BatchMesh { protected createBatchedGeometry(objects: DisplayObject[]) { const modelMatrix = mat4.create(); const modelViewMatrix = mat4.create(); - const normalMatrix = mat3.create(); + // const normalMatrix = mat3.create(); const packed = []; + + // const useNormal = this.material.defines.NORMAL; + objects.forEach((object) => { const { fill, @@ -97,6 +110,7 @@ export abstract class BatchMesh { fillOpacity, strokeOpacity, lineWidth = 0, + lineDash, anchor, visibility, } = object.parsedStyle; @@ -106,6 +120,7 @@ export abstract class BatchMesh { } let strokeColor: Tuple4Number = [0, 0, 0, 0]; if (stroke?.type === PARSED_COLOR_TYPE.Constant) { + // if (object.) strokeColor = stroke.value; } @@ -118,11 +133,6 @@ export abstract class BatchMesh { mat4.copy(modelMatrix, object.getWorldTransform()); } mat4.mul(modelViewMatrix, this.camera.getViewTransform(), modelMatrix); - // should not calc normal matrix in shader, mat3.invert is not cheap - // @see https://stackoverflow.com/a/21079741 - mat3.fromMat4(normalMatrix, modelViewMatrix); - mat3.invert(normalMatrix, normalMatrix); - mat3.transpose(normalMatrix, normalMatrix); // @ts-ignore const encodedPickingColor = object.renderable3D?.encodedPickingColor || [0, 0, 0]; @@ -144,6 +154,42 @@ export abstract class BatchMesh { anchor[0], anchor[1], ); + + // if (useNormal) { + // // should not calc normal matrix in shader, mat3.invert is not cheap + // // @see https://stackoverflow.com/a/21079741 + // mat3.fromMat4(normalMatrix, modelViewMatrix); + // mat3.invert(normalMatrix, normalMatrix); + // mat3.transpose(normalMatrix, normalMatrix); + + // const { NORMAL_MATRIX0, NORMAL_MATRIX1, NORMAL_MATRIX2 } = this.material.defines; + // this.bufferGeometry.setVertexBuffer({ + // bufferIndex: 4, + // byteStride: 4 * (3 * 3), + // frequency: VertexBufferFrequency.PerInstance, + // attributes: [ + // { + // format: Format.F32_RGB, + // bufferByteOffset: 4 * 0, + // location: Number(NORMAL_MATRIX0), + // divisor: 1, + // }, + // { + // format: Format.F32_RGB, + // bufferByteOffset: 4 * 3, + // location: Number(NORMAL_MATRIX1), + // divisor: 1, + // }, + // { + // format: Format.F32_RGB, + // bufferByteOffset: 4 * 6, + // location: Number(NORMAL_MATRIX2), + // divisor: 1, + // }, + // ], + // data: new Float32Array(normalMatrix), + // }); + // } }); this.bufferGeometry.instancedCount = objects.length; @@ -156,61 +202,61 @@ export abstract class BatchMesh { { format: Format.F32_RGBA, bufferByteOffset: 4 * 0, - location: AttributeLocation.a_ModelMatrix0, + location: VertexAttributeLocation.MODEL_MATRIX0, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 4, - location: AttributeLocation.a_ModelMatrix1, + location: VertexAttributeLocation.MODEL_MATRIX1, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 8, - location: AttributeLocation.a_ModelMatrix2, + location: VertexAttributeLocation.MODEL_MATRIX2, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 12, - location: AttributeLocation.a_ModelMatrix3, + location: VertexAttributeLocation.MODEL_MATRIX3, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 16, - location: AttributeLocation.a_Color, + location: VertexAttributeLocation.COLOR, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 20, - location: AttributeLocation.a_StrokeColor, + location: VertexAttributeLocation.STROKE_COLOR, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 24, - location: AttributeLocation.a_StylePacked1, + location: VertexAttributeLocation.PACKED_STYLE1, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 28, - location: AttributeLocation.a_StylePacked2, + location: VertexAttributeLocation.PACKED_STYLE2, divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 32, - location: AttributeLocation.a_PickingColor, + location: VertexAttributeLocation.PICKING_COLOR, divisor: 1, }, { format: Format.F32_RG, bufferByteOffset: 4 * 36, - location: AttributeLocation.a_Anchor, + location: VertexAttributeLocation.ANCHOR, divisor: 1, }, ], @@ -268,7 +314,7 @@ export abstract class BatchMesh { } // re-upload textures - if (this.material.textureDirty) { + if (this.material.textureDirty || this.materialDirty) { this.textureMappings = []; // set texture mappings @@ -281,7 +327,7 @@ export abstract class BatchMesh { } // re-compile program, eg. DEFINE changed - if (this.material.programDirty) { + if (this.material.programDirty || this.materialDirty) { this.createMaterial(objects); // set defines Object.keys(this.material.defines).forEach((key) => { @@ -304,7 +350,7 @@ export abstract class BatchMesh { this.material.programDirty = false; } - if (this.material.textureDirty) { + if (this.material.textureDirty || this.materialDirty) { this.material.textures.forEach(({ name, texture }) => { const mapping = new TextureMapping(); const { src, sampler, pixelStore, loadedTexture } = texture.descriptor; @@ -337,6 +383,8 @@ export abstract class BatchMesh { this.textureMappings.push(mapping); }); this.material.textureDirty = false; + + this.materialDirty = false; } if (this.material.geometryDirty) { @@ -422,7 +470,8 @@ export abstract class BatchMesh { // drawArrays renderInst.drawPrimitives(this.geometry.vertexCount, this.geometry.primitiveStart); } - renderInst.sortKey = makeSortKeyOpaque(RendererLayer.OPAQUE, program.id); + // FIXME: 暂时都当作非透明物体,按照创建顺序排序 + renderInst.sortKey = makeSortKeyOpaque(RendererLayer.OPAQUE, objects[0].sortable.renderOrder); } protected updateBatchedAttribute(object: DisplayObject, index: number, name: string, value: any) { @@ -437,7 +486,7 @@ export abstract class BatchMesh { this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_Color, + VertexAttributeLocation.COLOR, index, new Uint8Array(new Float32Array([...fillColor]).buffer), ); @@ -461,7 +510,7 @@ export abstract class BatchMesh { this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_StrokeColor, + VertexAttributeLocation.STROKE_COLOR, index, new Uint8Array(new Float32Array([...strokeColor]).buffer), ); @@ -469,7 +518,7 @@ export abstract class BatchMesh { const { opacity, fillOpacity, strokeOpacity, lineWidth = 0 } = object.parsedStyle; this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_StylePacked1, + VertexAttributeLocation.PACKED_STYLE1, index, new Uint8Array(new Float32Array([opacity, fillOpacity, strokeOpacity, lineWidth]).buffer), ); @@ -477,7 +526,7 @@ export abstract class BatchMesh { const modelMatrix = mat4.copy(mat4.create(), object.getWorldTransform()); this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_ModelMatrix0, + VertexAttributeLocation.MODEL_MATRIX0, index, new Uint8Array(new Float32Array(modelMatrix).buffer), ); @@ -485,7 +534,7 @@ export abstract class BatchMesh { const { anchor } = object.parsedStyle; this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_Anchor, + VertexAttributeLocation.ANCHOR, index, new Uint8Array(new Float32Array([anchor[0], anchor[1]]).buffer), ); @@ -493,7 +542,7 @@ export abstract class BatchMesh { const { visibility } = object.parsedStyle; this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_StylePacked2, + VertexAttributeLocation.PACKED_STYLE2, index, new Uint8Array(new Float32Array([visibility === 'visible' ? 1 : 0]).buffer), ); @@ -525,7 +574,7 @@ export abstract class BatchMesh { const encodedPickingColor = object.renderable3D?.encodedPickingColor || [0, 0, 0]; this.geometry.updateVertexBuffer( Batch.CommonBufferIndex, - AttributeLocation.a_PickingColor, + VertexAttributeLocation.PICKING_COLOR, index, new Uint8Array( new Float32Array([...encodedPickingColor, renderOrder * RENDER_ORDER_SCALE]).buffer, @@ -584,7 +633,7 @@ export abstract class BatchMesh { { format: Format.F32_RGB, bufferByteOffset: 4 * 0, - location: 13, + location: Number(this.material.defines.BARYCENTRIC), }, ], data: barycentricBuffer, @@ -596,8 +645,6 @@ export abstract class BatchMesh { protected beforeUploadUBO(renderInst: RenderInst, objects: DisplayObject[], i: number): void {} private uploadUBO(renderInst: RenderInst): void { let numUniformBuffers = 1; // Scene UBO - let wordCount = 0; - const material = this.material; const lights = this.lightPool.getAllLights(); const fog = this.lightPool.getFog(); @@ -605,42 +652,40 @@ export abstract class BatchMesh { const useLight = !!lights.length; const useWireframe = material.defines.USE_WIREFRAME; - // materials - wordCount += material.uboBuffer.length; - if (useWireframe) { - wordCount += 4; // u_WireframeLineColor & u_WireframeLineWidth - } - // add fog - if (useFog) { - wordCount += 8; - } - if (useLight) { - wordCount += lights.reduce((prev, cur) => prev + cur.getUniformWordCount(), 0); - } - - let offs = renderInst.allocateUniformBuffer(numUniformBuffers, wordCount); - const d = renderInst.mapUniformBufferF32(numUniformBuffers); + // collect uniforms + const uniforms = []; if (useWireframe) { const wireframeColor = parseColor(material.wireframeColor).value as Tuple4Number; - offs += fillVec4( - d, - offs, - ...(wireframeColor.slice(0, 3) as [number, number, number]), - material.wireframeLineWidth, - ); // u_WireframeLineColor & u_WireframeLineWidth + uniforms.push({ + name: 'u_WireframeLineColor', + value: wireframeColor.slice(0, 3), + }); + uniforms.push({ + name: 'u_WireframeLineWidth', + value: material.wireframeLineWidth, + }); } if (useFog) { - offs = this.uploadFog(d, offs, fog); + this.uploadFog(uniforms, fog); } - offs = this.uploadMaterial(d, offs, material); + this.uploadMaterial(uniforms, material); if (useLight) { + const counter: Record = {}; lights.forEach((light) => { - offs += light.uploadUBO(d, offs); + if (!counter[light.define]) { + counter[light.define] = -1; + } + + counter[light.define]++; + + light.uploadUBO(uniforms, counter[light.define]); }); } + renderInst.setUniforms(numUniformBuffers, uniforms); + const { depthCompare, depthWrite, @@ -702,29 +747,29 @@ export abstract class BatchMesh { renderInst.setSamplerBindingsFromTextureMappings(this.textureMappings); } - private uploadFog(d: Float32Array, offs: number, fog: Fog) { + private uploadFog(uniforms: RenderInstUniform[], fog: Fog) { const { type, fill, start, end, density } = fog.parsedStyle; if (fill?.type === PARSED_COLOR_TYPE.Constant) { const fillColor = fill.value as Tuple4Number; - offs += fillVec4(d, offs, type, start, end, density); // u_FogInfos - offs += fillVec4(d, offs, ...fillColor); // u_FogColor + uniforms.push({ + name: 'u_FogInfos', + value: [type, start, end, density], + }); + uniforms.push({ + name: 'u_FogColor', + value: fillColor, + }); } - return offs; } - private uploadMaterial(d: Float32Array, offs: number, material: Material) { - for (let i = 0; i < material.uboBuffer.length; i += 4) { - offs += fillVec4( - d, - offs, - material.uboBuffer[i], - material.uboBuffer[i + 1], - material.uboBuffer[i + 2], - material.uboBuffer[i + 3], - ); - } - return offs; + private uploadMaterial(uniforms: RenderInstUniform[], material: Material) { + // sort + const materialUniforms = Object.keys(material.uniforms).map((name) => ({ + name, + value: material.uniforms[name], + })); + uniforms.push(...materialUniforms); } protected createFillGradientTextureMapping(objects: DisplayObject[]): TextureMapping | null { @@ -780,9 +825,9 @@ export abstract class BatchMesh { // wrapT: WrapMode.Clamp, wrapS: WrapMode.Repeat, wrapT: WrapMode.Repeat, - minFilter: TexFilterMode.Bilinear, + minFilter: TexFilterMode.Point, magFilter: TexFilterMode.Bilinear, - mipFilter: MipFilterMode.NoMip, + mipFilter: MipFilterMode.Linear, minLOD: 0, maxLOD: 0, }); diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/Circle.ts b/packages/g-plugin-webgl-renderer/src/drawcall/Circle.ts index 30e202e20..eb5408d53 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/Circle.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/Circle.ts @@ -1,17 +1,18 @@ import { Circle, CircleStyleProps, DisplayObject, SHAPE, RenderingService } from '@antv/g'; import { injectable } from 'mana-syringe'; import { Format, VertexBufferFrequency } from '../platform'; -import { Batch, AttributeLocation } from './Batch'; +import { Batch } from './Batch'; import { ShapeRenderer, ShapeMesh } from '../tokens'; import vert from '../shader/circle.vert'; import frag from '../shader/circle.frag'; import { BatchMesh } from './BatchMesh'; +import { VertexAttributeLocation } from '../geometries'; -enum CircleProgram { - a_Extrude = AttributeLocation.MAX, - a_StylePacked3, - a_Size, - a_Uv, +enum CircleVertexAttributeLocation { + EXTRUDE = VertexAttributeLocation.MAX, + PACKED_STYLE3, + SIZE, + UV, } const PointShapes: string[] = [SHAPE.Circle, SHAPE.Ellipse, SHAPE.Rect]; @@ -60,12 +61,12 @@ export class CircleBatchMesh extends BatchMesh { { format: Format.F32_RG, bufferByteOffset: 4 * 0, - location: CircleProgram.a_Extrude, + location: CircleVertexAttributeLocation.EXTRUDE, }, { format: Format.F32_RG, bufferByteOffset: 4 * 2, - location: CircleProgram.a_Uv, + location: CircleVertexAttributeLocation.UV, }, ], data: new Float32Array(interleaved), @@ -78,7 +79,7 @@ export class CircleBatchMesh extends BatchMesh { { format: Format.F32_RG, bufferByteOffset: 4 * 0, - location: CircleProgram.a_Size, + location: CircleVertexAttributeLocation.SIZE, divisor: 1, }, ], @@ -92,7 +93,7 @@ export class CircleBatchMesh extends BatchMesh { { format: Format.F32_RGBA, bufferByteOffset: 4 * 0, - location: CircleProgram.a_StylePacked3, + location: CircleVertexAttributeLocation.PACKED_STYLE3, divisor: 1, }, ], @@ -118,14 +119,14 @@ export class CircleBatchMesh extends BatchMesh { this.geometry.updateVertexBuffer( 2, - CircleProgram.a_Size, + CircleVertexAttributeLocation.SIZE, index, new Uint8Array(new Float32Array([...size]).buffer), ); } else if (name === 'radius') { this.geometry.updateVertexBuffer( 3, - CircleProgram.a_StylePacked3, + CircleVertexAttributeLocation.PACKED_STYLE3, index, new Uint8Array( new Float32Array([ @@ -161,22 +162,18 @@ export class CircleBatchMesh extends BatchMesh { ], }) export class CircleRenderer extends Batch { - protected validate() { + protected validate(object: DisplayObject): boolean { + // cannot be merged when lineDash used + if (object.parsedStyle.lineDash) { + return false; + } + return true; } protected createBatchMeshList() { + // draw stroke separate this.batchMeshList.push(this.meshFactory(SHAPE.Circle)); + // this.batchMeshList.push(this.meshFactory(SHAPE.Path)); } - - // FIXME: use uniform by names in WebGL - // if (program.gl_program) { - // program.setUniforms({ - // u_ProjectionMatrix: this.camera.getPerspective(), - // u_ViewMatrix: this.camera.getViewTransform(), - // u_CameraPosition: this.camera.getPosition(), - // u_DevicePixelRatio: this.contextService.getDPR(), - // }); - // } - // } } diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/Image.ts b/packages/g-plugin-webgl-renderer/src/drawcall/Image.ts index f18627514..60d4e3af5 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/Image.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/Image.ts @@ -1,16 +1,16 @@ import { injectable } from 'mana-syringe'; import { DisplayObject, Image, SHAPE } from '@antv/g'; import { Format, VertexBufferFrequency } from '../platform'; -import { Batch, AttributeLocation } from './Batch'; +import { Batch } from './Batch'; import { ShapeMesh, ShapeRenderer } from '../tokens'; import vert from '../shader/image.vert'; import frag from '../shader/image.frag'; import { BatchMesh } from './BatchMesh'; -import { CircleBatchMesh } from './Circle'; +import { VertexAttributeLocation } from '../geometries'; -enum ImageProgram { - a_Size = AttributeLocation.MAX, - a_Uv, +enum ImageVertexAttributeLocation { + SIZE = VertexAttributeLocation.MAX, + UV, } const IMAGE_TEXTURE_MAPPING = 'IMAGE_TEXTURE_MAPPING'; @@ -55,7 +55,7 @@ export class ImageBatchMesh extends BatchMesh { { format: Format.F32_RG, bufferByteOffset: 4 * 0, - location: ImageProgram.a_Uv, + location: ImageVertexAttributeLocation.UV, }, ], data: new Float32Array(interleaved), @@ -68,7 +68,7 @@ export class ImageBatchMesh extends BatchMesh { { format: Format.F32_RG, bufferByteOffset: 4 * 0, - location: ImageProgram.a_Size, + location: ImageVertexAttributeLocation.SIZE, }, ], data: new Float32Array(instanced), @@ -84,7 +84,7 @@ export class ImageBatchMesh extends BatchMesh { if (name === 'width' || name === 'height') { this.geometry.updateVertexBuffer( 2, - ImageProgram.a_Size, + ImageVertexAttributeLocation.SIZE, index, new Uint8Array(new Float32Array([width, height]).buffer), ); diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/InstancedLine.ts b/packages/g-plugin-webgl-renderer/src/drawcall/InstancedLine.ts index f36328fd0..1f8a02fdb 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/InstancedLine.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/InstancedLine.ts @@ -2,34 +2,25 @@ import { inject, injectable } from 'mana-syringe'; import { Line, LINE_CAP, - LINE_JOIN, ParsedColorStyleProperty, - Path, - Pattern, - PolygonShape, - Polyline, DisplayObject, PARSED_COLOR_TYPE, - Point, SHAPE, - Tuple4Number, } from '@antv/g'; -import { fillMatrix4x4, fillVec4, makeSortKeyOpaque, RendererLayer } from '../render/utils'; -import { CullMode, Format, VertexBufferFrequency } from '../platform'; -import { RenderInst } from '../render/RenderInst'; -import { DeviceProgram } from '../render/DeviceProgram'; -import { Batch, AttributeLocation } from './Batch'; +import { Format, VertexBufferFrequency } from '../platform'; +import { Batch } from './Batch'; import { ShapeMesh, ShapeRenderer } from '../tokens'; import vert from '../shader/instanced-line.vert'; import frag from '../shader/instanced-line.frag'; import { BatchMesh } from './BatchMesh'; +import { VertexAttributeLocation } from '../geometries'; export const segmentInstanceGeometry = [ 0, -0.5, 0, 0, 0, 1, -0.5, 1, 1, 0, 1, 0.5, 1, 1, 1, 0, 0.5, 0, 0, 1, ]; enum InstancedLineProgram { - a_Position = AttributeLocation.MAX, + a_Position = VertexAttributeLocation.MAX, a_PointA, a_PointB, a_Cap, diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/Line.ts b/packages/g-plugin-webgl-renderer/src/drawcall/Line.ts index c64cedc1f..b7bc93407 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/Line.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/Line.ts @@ -12,12 +12,12 @@ import { SHAPE, Tuple4Number, } from '@antv/g'; +import { Cubic as CubicUtil } from '@antv/g-math'; import earcut from 'earcut'; import { vec3, mat4 } from 'gl-matrix'; import { CullMode, Format, VertexBufferFrequency } from '../platform'; import { Batch, RENDER_ORDER_SCALE } from './Batch'; import { ShapeMesh, ShapeRenderer } from '../tokens'; -import { Renderable3D } from '../components/Renderable3D'; import { isNil } from '@antv/util'; import vert from '../shader/line.vert'; import frag from '../shader/line.frag'; @@ -79,16 +79,6 @@ enum MeshProgram { a_Position = 0, } -enum MeshUniform { - MODEL_MATRIX = 'u_ModelMatrix', - COLOR = 'u_Color', - PICKING_COLOR = 'u_PickingColor', - OPACITY = 'u_Opacity', - FILL_OPACITY = 'u_FillOpacity', - VISIBLE = 'u_Visible', - Z_INDEX = 'u_ZIndex', -} - @injectable({ token: [ { token: ShapeMesh, named: SHAPE.Polyline }, @@ -132,15 +122,25 @@ export class LineBatchMesh extends BatchMesh { if (stroke?.type === PARSED_COLOR_TYPE.Constant) { strokeColor = stroke.value; } - this.material.updateUniformData(Uniform.STROKE_COLOR, strokeColor); + this.material.setUniforms({ + [Uniform.STROKE_COLOR]: strokeColor, + }); } else if (name === 'opacity') { - this.material.updateUniformData(Uniform.OPACITY, opacity); + this.material.setUniforms({ + [Uniform.OPACITY]: opacity, + }); } else if (name === 'fillOpacity') { - this.material.updateUniformData(Uniform.FILL_OPACITY, fillOpacity); + this.material.setUniforms({ + [Uniform.FILL_OPACITY]: fillOpacity, + }); } else if (name === 'strokeOpacity') { - this.material.updateUniformData(Uniform.STROKE_OPACITY, strokeOpacity); + this.material.setUniforms({ + [Uniform.STROKE_OPACITY]: strokeOpacity, + }); } else if (name === 'lineWidth') { - this.material.updateUniformData(Uniform.STROKE_WIDTH, lineWidth); + this.material.setUniforms({ + [Uniform.STROKE_WIDTH]: lineWidth, + }); } else if (name === 'anchor' || name === 'modelMatrix') { let translateX = 0; let translateY = 0; @@ -156,28 +156,28 @@ export class LineBatchMesh extends BatchMesh { object.getWorldTransform(), // apply anchor mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), ); - - this.material.updateUniformData(Uniform.MODEL_MATRIX, [ - [m[0], m[1], m[2], m[3]], - [m[4], m[5], m[6], m[7]], - [m[8], m[9], m[10], m[11]], - [m[12], m[13], m[14], m[15]], - ]); + this.material.setUniforms({ + [Uniform.MODEL_MATRIX]: m, + }); } else if (name === 'visibility') { - this.material.updateUniformData(Uniform.VISIBLE, visibility === 'visible' ? 1 : 0); + this.material.setUniforms({ + [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, + }); } else if (name === 'lineDash') { - this.material.updateUniformData(Uniform.DASH, lineDash[0] || 0); - this.material.updateUniformData(Uniform.GAP, lineDash[1] || 0); + this.material.setUniforms({ + [Uniform.DASH]: lineDash[0] || 0, + [Uniform.GAP]: lineDash[1] || 0, + }); } else if (name === 'lineDashOffset') { - this.material.updateUniformData(Uniform.DASH_OFFSET, lineDashOffset); + this.material.setUniforms({ + [Uniform.DASH_OFFSET]: lineDashOffset, + }); } } changeRenderOrder(object: DisplayObject, index: number, renderOrder: number) { - this.material.addUniform({ - name: Uniform.Z_INDEX, - format: Format.F32_R, - data: renderOrder * RENDER_ORDER_SCALE, + this.material.setUniforms({ + [Uniform.Z_INDEX]: renderOrder * RENDER_ORDER_SCALE, }); } @@ -226,95 +226,24 @@ export class LineBatchMesh extends BatchMesh { mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), ); - this.material.addUniform({ - name: Uniform.MODEL_MATRIX, - format: Format.F32_RGBA, - data: [ - [m[0], m[1], m[2], m[3]], - [m[4], m[5], m[6], m[7]], - [m[8], m[9], m[10], m[11]], - [m[12], m[13], m[14], m[15]], - ], - }); - this.material.addUniform({ - name: Uniform.COLOR, - format: Format.F32_RGBA, - data: fillColor, - }); - this.material.addUniform({ - name: Uniform.STROKE_COLOR, - format: Format.F32_RGBA, - data: strokeColor, - }); - this.material.addUniform({ - name: Uniform.STROKE_WIDTH, - format: Format.F32_R, - data: lineWidth, - }); - this.material.addUniform({ - name: Uniform.OPACITY, - format: Format.F32_R, - data: opacity, - }); - this.material.addUniform({ - name: Uniform.FILL_OPACITY, - format: Format.F32_R, - data: fillOpacity, - }); - this.material.addUniform({ - name: Uniform.STROKE_OPACITY, - format: Format.F32_R, - data: strokeOpacity, - }); - this.material.addUniform({ - name: Uniform.EXPAND, - format: Format.F32_R, - data: 1, - }); - this.material.addUniform({ - name: Uniform.MITER_LIMIT, - format: Format.F32_R, - data: 5, - }); - this.material.addUniform({ - name: Uniform.SCALE_MODE, - format: Format.F32_R, - data: 1, - }); - this.material.addUniform({ - name: Uniform.ALIGNMENT, - format: Format.F32_R, - data: 0.5, - }); - this.material.addUniform({ - name: Uniform.PICKING_COLOR, - format: Format.F32_RGBA, - data: encodedPickingColor, - }); - this.material.addUniform({ - name: Uniform.DASH, - format: Format.F32_R, - data: lineDash[0] || 0, - }); - this.material.addUniform({ - name: Uniform.GAP, - format: Format.F32_R, - data: lineDash[1] || 0, - }); - this.material.addUniform({ - name: Uniform.DASH_OFFSET, - format: Format.F32_R, - data: lineDashOffset, - }); - this.material.addUniform({ - name: Uniform.VISIBLE, - format: Format.F32_R, - data: visibility === 'visible' ? 1 : 0, - }); - this.material.addUniform({ - name: Uniform.Z_INDEX, - format: Format.F32_R, - data: instance.sortable.renderOrder * RENDER_ORDER_SCALE, + this.material.setUniforms({ + [Uniform.MODEL_MATRIX]: m, + [Uniform.COLOR]: fillColor, + [Uniform.STROKE_COLOR]: strokeColor, + [Uniform.STROKE_WIDTH]: lineWidth, + [Uniform.OPACITY]: opacity, + [Uniform.FILL_OPACITY]: fillOpacity, + [Uniform.STROKE_OPACITY]: strokeOpacity, + [Uniform.EXPAND]: 1, + [Uniform.MITER_LIMIT]: 5, + [Uniform.SCALE_MODE]: 1, + [Uniform.ALIGNMENT]: 0.5, + [Uniform.PICKING_COLOR]: encodedPickingColor, + [Uniform.DASH]: lineDash[0] || 0, + [Uniform.GAP]: lineDash[1] || 0, + [Uniform.DASH_OFFSET]: lineDashOffset, + [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, + [Uniform.Z_INDEX]: instance.sortable.renderOrder * RENDER_ORDER_SCALE, }); this.material.cullMode = CullMode.None; } @@ -463,45 +392,14 @@ export class FillBatchMesh extends BatchMesh { mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), ); - this.material.addUniform({ - name: Uniform.MODEL_MATRIX, - format: Format.F32_RGBA, - data: [ - [m[0], m[1], m[2], m[3]], - [m[4], m[5], m[6], m[7]], - [m[8], m[9], m[10], m[11]], - [m[12], m[13], m[14], m[15]], - ], - }); - this.material.addUniform({ - name: Uniform.COLOR, - format: Format.F32_RGBA, - data: fillColor, - }); - this.material.addUniform({ - name: Uniform.PICKING_COLOR, - format: Format.F32_RGBA, - data: encodedPickingColor, - }); - this.material.addUniform({ - name: Uniform.OPACITY, - format: Format.F32_R, - data: opacity, - }); - this.material.addUniform({ - name: Uniform.FILL_OPACITY, - format: Format.F32_R, - data: fillOpacity, - }); - this.material.addUniform({ - name: Uniform.VISIBLE, - format: Format.F32_R, - data: visibility === 'visible' ? 1 : 0, - }); - this.material.addUniform({ - name: Uniform.Z_INDEX, - format: Format.F32_R, - data: instance.sortable.renderOrder * RENDER_ORDER_SCALE, + this.material.setUniforms({ + [Uniform.MODEL_MATRIX]: m, + [Uniform.COLOR]: fillColor, + [Uniform.PICKING_COLOR]: encodedPickingColor, + [Uniform.OPACITY]: opacity, + [Uniform.FILL_OPACITY]: fillOpacity, + [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, + [Uniform.Z_INDEX]: instance.sortable.renderOrder * RENDER_ORDER_SCALE, }); } protected updateMeshAttribute( @@ -528,11 +426,17 @@ export class FillBatchMesh extends BatchMesh { if (fill?.type === PARSED_COLOR_TYPE.Constant) { fillColor = fill.value; } - this.material.updateUniformData(Uniform.COLOR, fillColor); + this.material.setUniforms({ + [Uniform.COLOR]: fillColor, + }); } else if (name === 'opacity') { - this.material.updateUniformData(Uniform.OPACITY, opacity); + this.material.setUniforms({ + [Uniform.OPACITY]: opacity, + }); } else if (name === 'fillOpacity') { - this.material.updateUniformData(Uniform.FILL_OPACITY, fillOpacity); + this.material.setUniforms({ + [Uniform.FILL_OPACITY]: fillOpacity, + }); } else if (name === 'anchor' || name === 'modelMatrix') { let translateX = 0; let translateY = 0; @@ -548,22 +452,18 @@ export class FillBatchMesh extends BatchMesh { object.getWorldTransform(), // apply anchor mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), ); - - this.material.updateUniformData(Uniform.MODEL_MATRIX, [ - [m[0], m[1], m[2], m[3]], - [m[4], m[5], m[6], m[7]], - [m[8], m[9], m[10], m[11]], - [m[12], m[13], m[14], m[15]], - ]); + this.material.setUniforms({ + [Uniform.MODEL_MATRIX]: m, + }); } else if (name === 'visibility') { - this.material.updateUniformData(Uniform.VISIBLE, visibility === 'visible' ? 1 : 0); + this.material.setUniforms({ + [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, + }); } } changeRenderOrder(object: DisplayObject, index: number, renderOrder: number) { - this.material.addUniform({ - name: Uniform.Z_INDEX, - format: Format.F32_R, - data: renderOrder * RENDER_ORDER_SCALE, + this.material.setUniforms({ + [Uniform.Z_INDEX]: renderOrder * RENDER_ORDER_SCALE, }); } } @@ -593,7 +493,6 @@ function curveTo( cpY2: number, toX: number, toY: number, - curveLength: number, points: Array, ): void { const fromX = points[points.length - 2]; @@ -601,7 +500,8 @@ function curveTo( points.length -= 2; - const n = segmentsCount(curveLength); + const l = CubicUtil.length(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY); + const n = segmentsCount(l); let dt = 0; let dt2 = 0; @@ -630,21 +530,21 @@ function curveTo( const adaptive = true; const maxLength = 10; -// const minSegments = 8; -// const maxSegments = 2048; +const minSegments = 8; +const maxSegments = 2048; function segmentsCount(length: number, defaultSegments = 20) { - if (!adaptive || !length || isNaN(length)) { - return defaultSegments; - } + // if (!adaptive || !length || isNaN(length)) { + // return defaultSegments; + // } let result = Math.ceil(length / maxLength); - // if (result < minSegments) { - // result = minSegments; - // } else if (result > maxSegments) { - // result = maxSegments; - // } + if (result < minSegments) { + result = minSegments; + } else if (result > maxSegments) { + result = maxSegments; + } return result; } @@ -660,7 +560,7 @@ function updateBuffer(object: DisplayObject, needEarcut = false) { return prev; }, [] as number[]); - // TODO: close polygon, dealing with extra joint + // close polygon, dealing with extra joint if (object.nodeName === SHAPE.Polygon) { if (needEarcut) { // use earcut for triangulation @@ -673,17 +573,18 @@ function updateBuffer(object: DisplayObject, needEarcut = false) { }; } else { points.push(points[0], points[1]); + points.push(...addTailSegment(points[0], points[1], points[2], points[3])); } } } else if (object.nodeName === SHAPE.Path) { const { - path: { curve, totalLength }, + path: { curve }, } = (object as Path).parsedStyle; - let startPoint: [number, number]; + let startPointIndex = -1; curve.forEach(([command, ...params]) => { if (command === 'M') { + startPointIndex = points.length; points.push(params[0] - defX, params[1] - defY); - startPoint = [params[0] - defX, params[1] - defY]; } else if (command === 'C') { curveTo( params[0] - defX, @@ -692,11 +593,18 @@ function updateBuffer(object: DisplayObject, needEarcut = false) { params[3] - defY, params[4] - defX, params[5] - defY, - totalLength, points, ); } else if (command === 'Z') { - points.push(startPoint[0], startPoint[1]); + points.push(points[startPointIndex], points[startPointIndex + 1]); + points.push( + ...addTailSegment( + points[startPointIndex], + points[startPointIndex + 1], + points[startPointIndex + 2], + points[startPointIndex + 3], + ), + ); } }); @@ -812,3 +720,9 @@ function getCapType(lineCap: LINE_CAP) { return cap; } + +function addTailSegment(x1: number, y1: number, x2: number = x1, y2: number = y1) { + const vec = [x2 - x1, y2 - y1]; + const length = 0.01; + return [x1 + vec[0] * length, y1 + vec[1] * length]; +} diff --git a/packages/g-plugin-webgl-renderer/src/drawcall/Text.ts b/packages/g-plugin-webgl-renderer/src/drawcall/Text.ts index 3169b3bb9..aebf15222 100644 --- a/packages/g-plugin-webgl-renderer/src/drawcall/Text.ts +++ b/packages/g-plugin-webgl-renderer/src/drawcall/Text.ts @@ -3,7 +3,7 @@ import { mat4 } from 'gl-matrix'; import { DisplayObject, PARSED_COLOR_TYPE, SHAPE, Text, Tuple4Number } from '@antv/g'; import { Format, VertexBufferFrequency } from '../platform'; import { RenderInst } from '../render/RenderInst'; -import { Batch, AttributeLocation, RENDER_ORDER_SCALE } from './Batch'; +import { Batch, RENDER_ORDER_SCALE } from './Batch'; import { BASE_FONT_WIDTH, GlyphManager } from './symbol/GlyphManager'; import { getGlyphQuads } from './symbol/SymbolQuad'; import GlyphAtlas from './symbol/GlyphAtlas'; @@ -12,9 +12,10 @@ import vert from '../shader/text.vert'; import frag from '../shader/text.frag'; import { BatchMesh } from './BatchMesh'; import { Texture2D } from '../Texture2D'; +import { VertexAttributeLocation } from '../geometries'; -enum TextProgram { - a_Tex = AttributeLocation.MAX, +enum TextVertexAttributeLocation { + a_Tex = VertexAttributeLocation.MAX, a_Offset, } @@ -93,63 +94,63 @@ export class TextBatchMesh extends BatchMesh { { format: Format.F32_RGBA, bufferByteOffset: 4 * 0, - location: AttributeLocation.a_ModelMatrix0, + location: VertexAttributeLocation.MODEL_MATRIX0, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 4, - location: AttributeLocation.a_ModelMatrix1, + location: VertexAttributeLocation.MODEL_MATRIX1, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 8, - location: AttributeLocation.a_ModelMatrix2, + location: VertexAttributeLocation.MODEL_MATRIX2, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 12, - location: AttributeLocation.a_ModelMatrix3, + location: VertexAttributeLocation.MODEL_MATRIX3, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 16, - location: AttributeLocation.a_Color, + location: VertexAttributeLocation.COLOR, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 20, - location: AttributeLocation.a_StrokeColor, + location: VertexAttributeLocation.STROKE_COLOR, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 24, - location: AttributeLocation.a_StylePacked1, + location: VertexAttributeLocation.PACKED_STYLE1, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 28, - location: AttributeLocation.a_StylePacked2, + location: VertexAttributeLocation.PACKED_STYLE2, // byteStride: 4 * 4, // divisor: 1, }, { format: Format.F32_RGBA, bufferByteOffset: 4 * 32, - location: AttributeLocation.a_PickingColor, + location: VertexAttributeLocation.PICKING_COLOR, // byteStride: 4 * 4, // divisor: 1, }, @@ -165,12 +166,12 @@ export class TextBatchMesh extends BatchMesh { { format: Format.F32_RG, bufferByteOffset: 4 * 0, - location: TextProgram.a_Tex, + location: TextVertexAttributeLocation.a_Tex, }, { format: Format.F32_RG, bufferByteOffset: 4 * 2, - location: TextProgram.a_Offset, + location: TextVertexAttributeLocation.a_Offset, }, ], data: new Float32Array(uvOffsets), @@ -214,35 +215,19 @@ export class TextBatchMesh extends BatchMesh { const { width: atlasWidth, height: atlasHeight } = glyphAtlas.image; - this.material.addUniform({ - name: Uniform.SDF_MAP_SIZE, - format: Format.U32_RG, - data: [atlasWidth, atlasHeight], - }); - this.material.addUniform({ - name: Uniform.FONT_SIZE, - format: Format.U32_R, - data: fontSize, - }); - this.material.addUniform({ - name: Uniform.GAMMA_SCALE, - format: Format.U32_R, - data: 1, - }); - this.material.addUniform({ - name: Uniform.STROKE_BLUR, - format: Format.U32_R, - data: 0.2, - }); - this.material.addUniform({ - name: Uniform.HAS_STROKE, - format: Format.U32_R, - data: 1, + this.material.setUniforms({ + [Uniform.SDF_MAP_SIZE]: [atlasWidth, atlasHeight], + [Uniform.FONT_SIZE]: fontSize, + [Uniform.GAMMA_SCALE]: 1, + [Uniform.STROKE_BLUR]: 0.2, + [Uniform.HAS_STROKE]: 1, }); } beforeUploadUBO(renderInst: RenderInst, objects: DisplayObject[], index: number) { - this.material.updateUniformData(Uniform.HAS_STROKE, 1 - index); + this.material.setUniforms({ + [Uniform.HAS_STROKE]: 1 - index, + }); } shouldSubmitRenderInst(renderInst: RenderInst, objects: DisplayObject[], index: number) { diff --git a/packages/g-plugin-webgl-renderer/src/geometries/BufferGeometry.ts b/packages/g-plugin-webgl-renderer/src/geometries/BufferGeometry.ts index 06c2ec9d8..496a2d609 100644 --- a/packages/g-plugin-webgl-renderer/src/geometries/BufferGeometry.ts +++ b/packages/g-plugin-webgl-renderer/src/geometries/BufferGeometry.ts @@ -17,9 +17,18 @@ export interface VertexBufferToUpdateDescriptor { } export enum VertexAttributeLocation { - POSITION = 10, - NORMAL, - UV, + // TODO: bind mat4 in WebGL2 instead of decomposed 4 * vec4? + // @see https://stackoverflow.com/questions/38853096/webgl-how-to-bind-values-to-a-mat4-attribute/38853623#38853623 + MODEL_MATRIX0, + MODEL_MATRIX1, + MODEL_MATRIX2, + MODEL_MATRIX3, + COLOR, + STROKE_COLOR, + PACKED_STYLE1, // opacity fillOpacity strokeOpacity lineWidth + PACKED_STYLE2, // visibility + PICKING_COLOR, + ANCHOR, MAX, } diff --git a/packages/g-plugin-webgl-renderer/src/index.ts b/packages/g-plugin-webgl-renderer/src/index.ts index b0832f322..1d19529c8 100644 --- a/packages/g-plugin-webgl-renderer/src/index.ts +++ b/packages/g-plugin-webgl-renderer/src/index.ts @@ -12,7 +12,6 @@ import { WebGLRendererPluginOptions } from './interfaces'; import { RenderHelper } from './render/RenderHelper'; import { Batch, - AttributeLocation, CircleRenderer, ImageRenderer, TextRenderer, @@ -47,7 +46,6 @@ export function registerModelBuilder(builderClazz: new (...args: any[]) => Batch export { Renderable3D, Batch, - AttributeLocation, // ShaderModuleService, // ModelBuilder, TexturePool, @@ -57,6 +55,7 @@ export { Sampler, }; +export * from './interfaces'; export * from './platform'; export * from './render'; export * from './geometries'; diff --git a/packages/g-plugin-webgl-renderer/src/lights/index.ts b/packages/g-plugin-webgl-renderer/src/lights/index.ts index a128d03b8..4d79a2477 100644 --- a/packages/g-plugin-webgl-renderer/src/lights/index.ts +++ b/packages/g-plugin-webgl-renderer/src/lights/index.ts @@ -1,5 +1,5 @@ import { DisplayObject, DisplayObjectConfig, BaseStyleProps } from '@antv/g'; -import { Material } from '../materials'; +import { RenderInstUniform } from '../render'; export interface LightProps extends BaseStyleProps { intensity: number; @@ -21,9 +21,7 @@ export abstract class Light extends DisplayObject { }); } - abstract getUniformWordCount(): number; - - abstract uploadUBO(d: Float32Array, off: number): number; + abstract uploadUBO(uniforms: RenderInstUniform[], index: number): void; } export * from './Fog'; diff --git a/packages/g-plugin-webgl-renderer/src/materials/Material.ts b/packages/g-plugin-webgl-renderer/src/materials/Material.ts index 3c25765d0..fcb86639c 100644 --- a/packages/g-plugin-webgl-renderer/src/materials/Material.ts +++ b/packages/g-plugin-webgl-renderer/src/materials/Material.ts @@ -1,4 +1,5 @@ -import type { Tuple4Number } from '@antv/g'; +import { ElementEvent, Tuple4Number } from '@antv/g'; +import { isNil } from '@antv/util'; import { Mesh } from '../Mesh'; import { BlendFactor, @@ -309,7 +310,8 @@ export abstract class Material { // USE_XXX defines: Record = {}; - uniforms: MaterialUniform[] = []; + // uniforms: MaterialUniform[] = []; + uniforms: Record = {}; uboBuffer: number[] = []; textures: { @@ -361,8 +363,8 @@ export abstract class Material { blendEquationAlpha: BlendMode.Add, blendSrc: BlendFactor.SrcAlpha, blendDst: BlendFactor.OneMinusSrcAlpha, - blendSrcAlpha: null, - blendDstAlpha: null, + blendSrcAlpha: BlendFactor.Zero, + blendDstAlpha: BlendFactor.One, dithering: false, wireframe: false, wireframeColor: 'black', @@ -374,90 +376,30 @@ export abstract class Material { } /** - * calculate uniform word count, which will be used in Mesh's uploadUBO + * @example + * material.setUniforms({ + * u_ModelMatrix: [1, 2, 3, 4], + * u_Time: 1, + * }) */ - private updateUniformOffset() { - let offset = 0; - this.uboBuffer = []; - this.uniforms.forEach((uniform) => { - const { format, data } = uniform; - const array = typeof data === 'number' ? [data] : data; - const formatByteSize = getFormatByteSize(format); - const matrix = isMatrix(array); - uniform.size = matrix ? formatByteSize * array.length : formatByteSize; - // std140 UBO layout - const emptySpace = 4 - (offset % 4); - if (emptySpace !== 4) { - if (emptySpace >= formatByteSize) { - } else { - offset += emptySpace; - for (let j = 0; j < emptySpace; j++) { - this.uboBuffer.push(0); // padding - } - } - } - - uniform.offset = offset; - offset += uniform.size; + setUniforms(uniforms: Record) { + this.uniforms = { + ...this.uniforms, + ...uniforms, + }; - for (let j = 0; j < formatByteSize / 4; j++) { - if (isMatrix(array)) { - this.uboBuffer.push(...array[j]); - } else { - this.uboBuffer.push(array[j]); - } + Object.keys(this.uniforms).forEach((key) => { + if (isNil(this.uniforms[key])) { + delete this.uniforms[key]; } }); - // padding - const emptySpace = 4 - (this.uboBuffer.length % 4); - if (emptySpace !== 4) { - for (let j = 0; j < emptySpace; j++) { - this.uboBuffer.push(0); - } - } - } - - /** - * add uniform - * - * @example - * material.addUniform({ - * name: 'u_U1', - * component: FormatCompFlags.RGB, - * value: [1, 1, 1], - * }); - */ - addUniform(uniform: MaterialUniform) { - this.removeUniform(uniform.name); - this.uniforms.push(uniform); - this.updateUniformOffset(); - } - - removeUniform(uniformName: string) { - const index = this.uniforms.findIndex(({ name }) => name === uniformName); - if (index > -1) { - this.uniforms.splice(index, 1); - this.updateUniformOffset(); - } - } - - updateUniformData(uniformName: string, data: MaterialUniformData) { - const existed = this.uniforms.find(({ name }) => name === uniformName); - if (existed) { - const array = typeof data === 'number' ? [data] : data; - const { offset, size } = existed; - if (isMatrix(array)) { - this.uboBuffer.splice( - offset / 4, - size / 4, - // @ts-ignore - ...array.reduce((accumulator, value) => accumulator.concat(value), []), - ); - } else { - this.uboBuffer.splice(offset / 4, size / 4, ...array); - } - } + // trigger re-render + this.meshes.forEach((mesh) => { + mesh.emit(ElementEvent.ATTRIBUTE_CHANGED, { + attributeName: 'geometry', + }); + }); } addTexture(map: string | TexImageSource | Texture2D, textureName: string, order = 0) { diff --git a/packages/g-plugin-webgl-renderer/src/platform/utils/hash.ts b/packages/g-plugin-webgl-renderer/src/platform/utils/hash.ts index 3834dbf4d..8c36cf5ff 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/utils/hash.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/utils/hash.ts @@ -1,3 +1,4 @@ +import { isNil } from '@antv/util'; import { BufferBinding, SamplerBinding, @@ -150,8 +151,8 @@ export function inputLayoutBufferDescriptorEquals( a: Readonly, b: Readonly, ): boolean { - if (a === null) return b === null; - if (b === null) return false; + if (isNil(a)) return isNil(b); + if (isNil(b)) return false; return a.byteStride === b.byteStride && a.frequency === b.frequency; } @@ -276,12 +277,12 @@ export function vertexAttributeDescriptorCopy( export function inputLayoutBufferDescriptorCopy( a: Readonly, ): InputLayoutBufferDescriptor | null { - if (a !== null) { + if (!isNil(a)) { const byteStride = a.byteStride; const frequency = a.frequency; return { byteStride, frequency }; } else { - return null; + return a; } } diff --git a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Device.ts b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Device.ts index 592dd9f32..46e4b4da8 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Device.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Device.ts @@ -8,6 +8,7 @@ import { getFormatFlags, FormatFlags, } from '..'; +import { makeStaticDataBuffer } from '../../geometries'; import { CopyProgram } from '../../passes/Copy'; import { TextureMapping } from '../../render'; import { preprocessProgramObj_GLSL } from '../../shader/compiler'; @@ -205,6 +206,11 @@ export class Device_GL implements SwapChain, Device { readonly supportMRT: boolean = false; + private inBlitRenderPass = false; + private blitRenderPipeline: RenderPipeline; + private blitInputState: InputState; + private blitBindings: Bindings; + // GLimits /** * @see https://github.com/shrekshao/MoveWebGL1EngineToWebGL2/blob/master/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-2.md#uniform-buffer @@ -213,6 +219,7 @@ export class Device_GL implements SwapChain, Device { uniformBufferWordAlignment: number; uniformBufferMaxPageWordSize: number; supportedSampleCounts: number[] = []; + maxVertexAttribs: number; gl: WebGLRenderingContext | WebGL2RenderingContext; @@ -233,6 +240,8 @@ export class Device_GL implements SwapChain, Device { gl.getExtension('EXT_frag_depth'); // @see https://developer.mozilla.org/en-US/docs/Web/API/OES_element_index_uint gl.getExtension('OES_element_index_uint'); + // @see https://developer.mozilla.org/en-US/docs/Web/API/OES_standard_derivatives + gl.getExtension('OES_standard_derivatives'); if (this.WEBGL_draw_buffers) { this.supportMRT = true; @@ -370,9 +379,11 @@ export class Device_GL implements SwapChain, Device { private checkLimits(): void { const gl = this.gl; + this.maxVertexAttribs = gl.getParameter(GL.MAX_VERTEX_ATTRIBS); + if (isWebGL2(gl)) { this.uniformBufferMaxPageByteSize = Math.min( - gl.getParameter(gl.MAX_UNIFORM_BLOCK_SIZE), + gl.getParameter(GL.MAX_UNIFORM_BLOCK_SIZE), UBO_PAGE_MAX_BYTE_SIZE, ); this.uniformBufferWordAlignment = gl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT) / 4; @@ -435,82 +446,12 @@ export class Device_GL implements SwapChain, Device { const { r, g, b, a } = OpaqueWhite; if (isWebGL2(gl)) { - // gl.clearColor(0, 0, 0, 1); - // gl.clear(gl.COLOR_BUFFER_BIT); gl.clearBufferfv(gl.COLOR, 0, [r, g, b, a]); } else { + this.submitBlitRenderPass(); // // gl.colorMask(true, true, true, true); // // gl.clearColor(r, g, b, a); // // gl.clear(gl.COLOR_BUFFER_BIT); - // this.inPresent = true; - // const vertexBuffer = makeStaticDataBuffer( - // this, - // BufferUsage.Vertex, - // // translateBufferUsage(BufferUsage.Vertex), - // new Float32Array([-4, -4, 4, -4, 0, 4]).buffer, - // ); - // const inputLayout = this.createInputLayout({ - // vertexBufferDescriptors: [ - // { byteStride: 4 * 2, frequency: VertexBufferFrequency.PerVertex }, - // ], - // vertexAttributeDescriptors: [ - // { - // format: Format.F32_RG, - // bufferIndex: 0, - // bufferByteOffset: 4 * 0, - // location: 0, - // }, - // ], - // indexBufferFormat: null, - // }); - // const bindingLayouts: BindingLayoutDescriptor[] = [{ numSamplers: 1, numUniformBuffers: 0 }]; - // const program = this.createProgram(preprocessProgramObj_GLSL(this, new CopyProgram())); - // const inputState = this.createInputState( - // inputLayout, - // [{ buffer: vertexBuffer, byteOffset: 0 }], - // null, - // program, - // ); - // const renderPipeline = this.createRenderPipeline({ - // topology: PrimitiveTopology.Triangles, - // sampleCount: 1, - // program, - // bindingLayouts, - // colorAttachmentFormats: [Format.U8_RGBA_RT], - // depthStencilAttachmentFormat: null, - // inputLayout, - // megaStateDescriptor: defaultMegaState, - // }); - // const renderPass = this.createRenderPass({ - // colorAttachment: [this.currentColorAttachments[0]], - // colorResolveTo: [this.getOnscreenTexture()], - // colorClearColor: [OpaqueBlack], - // depthStencilAttachment: null, - // depthStencilResolveTo: null, - // depthClearValue: 0, - // stencilClearValue: 0, - // }); - // const bindings = this.createBindings({ - // bindingLayout: bindingLayouts[0], - // samplerBindings: [ - // { - // sampler: null, - // texture: null, - // lateBinding: null, - // }, - // ], - // uniformBufferBindings: [], - // }); - // renderPass.setPipeline(renderPipeline); - // renderPass.setBindings(0, bindings, [0]); - // renderPass.setInputState(inputState); - // renderPass.setViewport(0, 0, 1200, 1000); - // program.setUniforms({ - // u_Texture: 0, - // }); - // renderPass.draw(3, 0); - // this.submitPass(renderPass); - // this.inPresent = false; } } //#endregion @@ -585,11 +526,11 @@ export class Device_GL implements SwapChain, Device { case Format.BC5_SNORM: return this.EXT_texture_compression_rgtc!.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; case Format.D32F_S8: - return GL.DEPTH32F_STENCIL8; + return isWebGL2(this.gl) ? GL.DEPTH32F_STENCIL8 : GL.DEPTH_STENCIL; case Format.D24_S8: - return GL.DEPTH24_STENCIL8; + return isWebGL2(this.gl) ? GL.DEPTH24_STENCIL8 : GL.DEPTH_STENCIL; case Format.D32F: - return GL.DEPTH_COMPONENT32F; + return isWebGL2(this.gl) ? GL.DEPTH_COMPONENT32F : GL.DEPTH_COMPONENT; case Format.D24: return isWebGL2(this.gl) ? GL.DEPTH_COMPONENT24 : GL.DEPTH_COMPONENT; default: @@ -1223,14 +1164,19 @@ export class Device_GL implements SwapChain, Device { if (isWebGL2(gl)) { gl.bindFramebuffer(GL.DRAW_FRAMEBUFFER, this.renderPassDrawFramebuffer); } else { - gl.bindFramebuffer(GL.FRAMEBUFFER, this.renderPassDrawFramebuffer); + if (!this.inBlitRenderPass) { + gl.bindFramebuffer(GL.FRAMEBUFFER, this.renderPassDrawFramebuffer); + } } - for (let i = numColorAttachments; i < this.currentColorAttachments.length; i++) { - const target = isWebGL2(gl) ? GL.DRAW_FRAMEBUFFER : GL.FRAMEBUFFER; - const attachment = isWebGL2(gl) ? GL.COLOR_ATTACHMENT0 : GL.COLOR_ATTACHMENT0_WEBGL; - gl.framebufferRenderbuffer(target, attachment + i, GL.RENDERBUFFER, null); - gl.framebufferTexture2D(target, attachment + i, GL.TEXTURE_2D, null, 0); + if (!this.inBlitRenderPass) { + for (let i = numColorAttachments; i < this.currentColorAttachments.length; i++) { + const target = isWebGL2(gl) ? GL.DRAW_FRAMEBUFFER : GL.FRAMEBUFFER; + const attachment = isWebGL2(gl) ? GL.COLOR_ATTACHMENT0 : GL.COLOR_ATTACHMENT0_WEBGL; + + gl.framebufferRenderbuffer(target, attachment + i, GL.RENDERBUFFER, null); + gl.framebufferTexture2D(target, attachment + i, GL.TEXTURE_2D, null, 0); + } } this.currentColorAttachments.length = numColorAttachments; @@ -1242,13 +1188,15 @@ export class Device_GL implements SwapChain, Device { GL.COLOR_ATTACHMENT3, ]); } else { - // MRT @see https://github.com/shrekshao/MoveWebGL1EngineToWebGL2/blob/master/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#multiple-render-targets - this.WEBGL_draw_buffers.drawBuffersWEBGL([ - GL.COLOR_ATTACHMENT0_WEBGL, // gl_FragData[0] - GL.COLOR_ATTACHMENT1_WEBGL, // gl_FragData[1] - GL.COLOR_ATTACHMENT2_WEBGL, // gl_FragData[2] - GL.COLOR_ATTACHMENT3_WEBGL, // gl_FragData[3] - ]); + if (!this.inBlitRenderPass) { + // MRT @see https://github.com/shrekshao/MoveWebGL1EngineToWebGL2/blob/master/Move-a-WebGL-1-Engine-To-WebGL-2-Blog-1.md#multiple-render-targets + this.WEBGL_draw_buffers.drawBuffersWEBGL([ + GL.COLOR_ATTACHMENT0_WEBGL, // gl_FragData[0] + GL.COLOR_ATTACHMENT1_WEBGL, // gl_FragData[1] + GL.COLOR_ATTACHMENT2_WEBGL, // gl_FragData[2] + GL.COLOR_ATTACHMENT3_WEBGL, // gl_FragData[3] + ]); + } } } @@ -1287,10 +1235,12 @@ export class Device_GL implements SwapChain, Device { if (this.currentDepthStencilAttachment !== depthStencilAttachment) { this.currentDepthStencilAttachment = depthStencilAttachment as RenderTarget_GL | null; - this.bindFramebufferDepthStencilAttachment( - isWebGL2(gl) ? GL.DRAW_FRAMEBUFFER : GL.FRAMEBUFFER, - this.currentDepthStencilAttachment, - ); + if (!this.inBlitRenderPass) { + this.bindFramebufferDepthStencilAttachment( + isWebGL2(gl) ? GL.DRAW_FRAMEBUFFER : GL.FRAMEBUFFER, + this.currentDepthStencilAttachment, + ); + } this.resolveDepthStencilAttachmentsChanged = true; } @@ -1438,12 +1388,15 @@ export class Device_GL implements SwapChain, Device { if (this.currentTextures[samplerIndex] !== gl_texture) { this.setActiveTexture(gl.TEXTURE0 + samplerIndex); if (gl_texture !== null) { - const { gl_target, formatKind } = assertExists(binding).texture as Texture_GL; + // update index + (binding.texture as Texture_GL).textureIndex = samplerIndex; + const { gl_target, formatKind, width, height } = assertExists(binding) + .texture as Texture_GL; gl.bindTexture(gl_target, gl_texture); // In WebGL1 set tex's parameters @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texParameter if (!isWebGL2(gl)) { - (binding.sampler as Sampler_GL)?.setTextureParameters(gl_target, gl_texture); + (binding.sampler as Sampler_GL)?.setTextureParameters(gl_target, width, height); } this.debugGroupStatisticsTextureBind(); @@ -2057,4 +2010,91 @@ export class Device_GL implements SwapChain, Device { else if (gl_target === GL.TEXTURE_CUBE_MAP) return this.fallbackTextureCube; else throw 'whoops'; } + + private submitBlitRenderPass() { + if (!this.blitRenderPipeline) { + const vertexBuffer = makeStaticDataBuffer( + this, + BufferUsage.Vertex, + new Float32Array([-4, -4, 4, -4, 0, 4]).buffer, + ); + const inputLayout = this.createInputLayout({ + vertexBufferDescriptors: [ + { byteStride: 4 * 2, frequency: VertexBufferFrequency.PerVertex }, + ], + vertexAttributeDescriptors: [ + { + format: Format.F32_RG, + bufferIndex: 0, + bufferByteOffset: 4 * 0, + location: 0, + }, + ], + indexBufferFormat: null, + }); + const bindingLayouts: BindingLayoutDescriptor[] = [{ numSamplers: 1, numUniformBuffers: 0 }]; + const program = this.createProgram({ + ...preprocessProgramObj_GLSL(this, new CopyProgram()), + ensurePreprocessed: () => {}, + associate: () => {}, + }); + this.blitInputState = this.createInputState( + inputLayout, + [{ buffer: vertexBuffer, byteOffset: 0 }], + null, + program, + ); + this.blitRenderPipeline = this.createRenderPipeline({ + topology: PrimitiveTopology.Triangles, + sampleCount: 1, + program, + bindingLayouts, + colorAttachmentFormats: [Format.U8_RGBA_RT], + depthStencilAttachmentFormat: null, + inputLayout, + megaStateDescriptor: defaultMegaState, + }); + + const colorTexture = this.currentColorAttachments[0].texture; + this.blitBindings = this.createBindings({ + bindingLayout: bindingLayouts[0], + samplerBindings: [ + { + sampler: null, + texture: colorTexture, + lateBinding: null, + }, + ], + uniformBufferBindings: [], + }); + + program.setUniforms({ + u_Texture: colorTexture, + }); + } + + this.inBlitRenderPass = true; + + const blitRenderPass = this.createRenderPass({ + colorAttachment: [this.currentColorAttachments[0]], + colorResolveTo: [this.getOnscreenTexture()], + colorClearColor: [OpaqueBlack], + colorStore: [true], + depthStencilAttachment: null, + depthStencilResolveTo: null, + depthStencilStore: true, + depthClearValue: 'load', + stencilClearValue: 'load', + occlusionQueryPool: null, + }); + + const { width, height } = this.getCanvas(); + blitRenderPass.setPipeline(this.blitRenderPipeline); + blitRenderPass.setBindings(0, this.blitBindings, [0]); + blitRenderPass.setInputState(this.blitInputState); + blitRenderPass.setViewport(0, 0, width, height); + blitRenderPass.draw(3, 0); + this.submitPass(blitRenderPass); + this.inBlitRenderPass = false; + } } diff --git a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Program.ts b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Program.ts index 9009a71e3..6f9eebd9b 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Program.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Program.ts @@ -1,8 +1,10 @@ -import { getAttributeLocations } from '../../shader/compiler'; +import { isNil } from '@antv/util'; +import { getAttributeLocations, getDefines } from '../../shader/compiler'; import { ResourceType, Program, ProgramDescriptorSimple } from '../interfaces'; import { assert, getUniformSetter, parseUniformName } from '../utils'; import { Device_GL } from './Device'; import { ResourceBase_GL } from './ResourceBase'; +import { Texture_GL } from './Texture'; import { isWebGL2 } from './utils'; export enum ProgramCompileState_GL { @@ -86,7 +88,8 @@ export class Program_GL extends ResourceBase_GL implements Program { const gl = this.device.gl; const count = gl.getProgramParameter(this.gl_program, gl.ACTIVE_ATTRIBUTES); - const locations = getAttributeLocations(this.descriptor.vert); + const defines = getDefines(this.descriptor.preprocessedVert); + const locations = getAttributeLocations(this.descriptor.vert, defines); for (let index = 0; index < count; index++) { const { name, type, size } = gl.getActiveAttrib(this.gl_program, index); const location = gl.getAttribLocation(this.gl_program, name); @@ -94,7 +97,7 @@ export class Program_GL extends ResourceBase_GL implements Program { const definedLocation = locations.find((l) => l.name === name)?.location; // Add only user provided attributes, for built-in attributes like // `gl_InstanceID` locaiton will be < 0 - if (location >= 0) { + if (location >= 0 && !isNil(definedLocation)) { this.attributes[definedLocation] = { name, location, @@ -103,8 +106,6 @@ export class Program_GL extends ResourceBase_GL implements Program { }; } } - - // this.attributes.sort((a, b) => a.location - b.location); } private readUniformLocationsFromLinkedProgram() { @@ -135,50 +136,24 @@ export class Program_GL extends ResourceBase_GL implements Program { setUniforms(uniforms: Record = {}) { const gl = this.device.gl; - gl.useProgram(this.gl_program); - - for (const uniformName in uniforms) { - const uniform = uniforms[uniformName]; - const uniformSetter = this.uniformSetters[uniformName]; - - if (uniformSetter) { - let value = uniform; - let textureUpdate = false; - - uniformSetter(value); - - // if (value instanceof Framebuffer) { - // value = value.texture; - // } - // if (value instanceof Texture) { - // textureUpdate = this.uniforms[uniformName] !== uniform; - - // if (textureUpdate) { - // // eslint-disable-next-line max-depth - // if (uniformSetter.textureIndex === undefined) { - // uniformSetter.textureIndex = this._textureIndexCounter++; - // } - - // // Bind texture to index - // const texture = value; - // const {textureIndex} = uniformSetter; - - // texture.bind(textureIndex); - // value = textureIndex; - - // this._textureUniforms[uniformName] = texture; - // } else { - // value = uniformSetter.textureIndex; - // } - // } else if (this._textureUniforms[uniformName]) { - // delete this._textureUniforms[uniformName]; - // } - - // NOTE(Tarek): uniformSetter returns whether - // value had to be updated or not. - // if (uniformSetter(value) || textureUpdate) { - // // copyUniform(this.uniforms, uniformName, uniform); - // } + + if (!isWebGL2(gl)) { + let programUsed = false; + for (const uniformName in uniforms) { + if (!programUsed) { + gl.useProgram(this.gl_program); + programUsed = true; + } + + const uniform = uniforms[uniformName]; + const uniformSetter = this.uniformSetters[uniformName]; + if (uniformSetter) { + let value = uniform; + if (value instanceof Texture_GL) { + value = value.textureIndex; + } + uniformSetter(value); + } } } diff --git a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Readback.ts b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Readback.ts index 40f56185f..a9f4fdf50 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Readback.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Readback.ts @@ -115,7 +115,15 @@ export class Readback_GL extends ResourceBase_GL implements Readback { length, ); } else { - // TODO: + gl.bindFramebuffer(GL.FRAMEBUFFER, this.device.readbackFramebuffer); + gl.framebufferTexture2D( + GL.FRAMEBUFFER, + GL.COLOR_ATTACHMENT0, + GL.TEXTURE_2D, + texture.gl_texture, + 0, + ); + // slow requires roundtrip to GPU // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/pixelStorei gl.pixelStorei(gl.PACK_ALIGNMENT, 4); gl.readPixels(x, y, width, height, gl.RGBA, gl_type, dstBuffer); diff --git a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Sampler.ts b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Sampler.ts index 8d66641ac..085953cbd 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Sampler.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Sampler.ts @@ -6,7 +6,7 @@ import { SamplerDescriptor, TexFilterMode, } from '../interfaces'; -import { assert } from '../utils'; +import { assert, isPowerOfTwo } from '../utils'; import { Device_GL } from './Device'; import { ResourceBase_GL } from './ResourceBase'; import { getPlatformSampler, isWebGL2, translateFilterMode, translateWrapMode } from './utils'; @@ -86,21 +86,36 @@ export class Sampler_GL extends ResourceBase_GL implements Sampler { } } - setTextureParameters(gl_target: number, gl_texture: WebGLTexture): void { + setTextureParameters(gl_target: number, width: number, height: number): void { const gl = this.device.gl; const descriptor = this.descriptor; - gl.texParameteri(gl_target, GL.TEXTURE_WRAP_S, translateWrapMode(descriptor.wrapS)); - gl.texParameteri(gl_target, GL.TEXTURE_WRAP_T, translateWrapMode(descriptor.wrapT)); - gl.texParameteri( - gl_target, - GL.TEXTURE_MIN_FILTER, - translateFilterMode(descriptor.minFilter, descriptor.mipFilter), - ); + + // @see https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL#%E9%9D%9E2%E7%9A%84%E5%B9%82%E7%BA%B9%E7%90%86 + if (this.isNPOT(width, height)) { + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR); + } else { + gl.texParameteri( + gl_target, + GL.TEXTURE_MIN_FILTER, + translateFilterMode(descriptor.minFilter, descriptor.mipFilter), + ); + } + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, translateWrapMode(descriptor.wrapS)); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, translateWrapMode(descriptor.wrapT)); + gl.texParameteri( gl_target, GL.TEXTURE_MAG_FILTER, translateFilterMode(descriptor.magFilter, MipFilterMode.NoMip), ); + + // if (descriptor.minLOD !== undefined) { + // gl.texParameterf(gl_target, GL.TEXTURE_MIN_LOD, descriptor.minLOD); + // } + // if (descriptor.maxLOD !== undefined) { + // gl.texParameterf(gl_target, GL.TEXTURE_MAX_LOD, descriptor.maxLOD); + // } + const maxAnisotropy = descriptor.maxAnisotropy ?? 1; if (maxAnisotropy > 1 && this.device.EXT_texture_filter_anisotropic !== null) { assert( @@ -123,4 +138,8 @@ export class Sampler_GL extends ResourceBase_GL implements Sampler { this.device.gl.deleteSampler(getPlatformSampler(this)); } } + + isNPOT(width: number, height: number): boolean { + return !isPowerOfTwo(width) || !isPowerOfTwo(height); + } } diff --git a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Texture.ts b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Texture.ts index 62559f4f9..5dcab36b6 100644 --- a/packages/g-plugin-webgl-renderer/src/platform/webgl2/Texture.ts +++ b/packages/g-plugin-webgl-renderer/src/platform/webgl2/Texture.ts @@ -31,6 +31,7 @@ export class Texture_GL extends ResourceBase_GL implements Texture { }>; mipmaps: boolean; formatKind: SamplerFormatKind; + textureIndex: number; // used in WebGL1 constructor({ id, @@ -71,8 +72,8 @@ export class Texture_GL extends ResourceBase_GL implements Texture { if (descriptor.dimension === TextureDimension.n2D) { gl_target = GL.TEXTURE_2D; gl.bindTexture(gl_target, gl_texture); - if (isWebGL2(gl)) { - if (this.immutable) { + if (this.immutable) { + if (isWebGL2(gl)) { // texStorage2D will create an immutable texture(fixed size) // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/texStorage2D // @see https://github.com/visgl/luma.gl/issues/193 @@ -84,11 +85,10 @@ export class Texture_GL extends ResourceBase_GL implements Texture { descriptor.width, descriptor.height, ); - } - } else { - if (this.immutable) { + } else { // texImage2D: level must be 0 for DEPTH_COMPONENT format - const level = internalformat === GL.DEPTH_COMPONENT || this.isNPOT() ? 0 : numLevels; + // const level = internalformat === GL.DEPTH_COMPONENT || this.isNPOT() ? 0 : numLevels; + const level = internalformat === GL.DEPTH_COMPONENT || this.isNPOT() ? 0 : 0; // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D gl.texImage2D( @@ -97,7 +97,6 @@ export class Texture_GL extends ResourceBase_GL implements Texture { internalformat, descriptor.width, descriptor.height, - // texImage2D: border != 0 0, internalformat, gl_type, @@ -166,10 +165,6 @@ export class Texture_GL extends ResourceBase_GL implements Texture { this.gl_texture = gl_texture; this.gl_target = gl_target; this.numLevels = numLevels; - - if (this.mipmaps) { - this.generateMipmap(); - } } setImageData(data: TexImageSource | ArrayBufferView[], level: number) { @@ -190,6 +185,9 @@ export class Texture_GL extends ResourceBase_GL implements Texture { } else { width = (data as TexImageSource).width; height = (data as TexImageSource).height; + // update size + this.width = width; + this.height = height; } gl.bindTexture(this.gl_target, this.gl_texture); @@ -209,7 +207,7 @@ export class Texture_GL extends ResourceBase_GL implements Texture { // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D gl.texSubImage2D( this.gl_target, - level, + 0, 0, 0, width, @@ -224,7 +222,8 @@ export class Texture_GL extends ResourceBase_GL implements Texture { // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D gl.texImage2D( this.gl_target, - level, + // level, + 0, gl_format, width, height, @@ -235,102 +234,35 @@ export class Texture_GL extends ResourceBase_GL implements Texture { isArray ? data[0] : data, ); } else { - // WebGL1: - (gl as WebGLRenderingContext).texImage2D( - this.gl_target, - level, - gl_format, - gl_format, - gl_type, - data as ImageData, - ); + // WebGL1: upload Array & Image separately + if (isArray) { + (gl as WebGLRenderingContext).texImage2D( + this.gl_target, + 0, + gl_format, + width, + height, + 0, + gl_format, + gl_type, + data[0], + ); + } else { + (gl as WebGLRenderingContext).texImage2D( + this.gl_target, + 0, + gl_format, + gl_format, + gl_type, + data as TexImageSource, + ); + } } } if (this.mipmaps) { this.generateMipmap(); } - - // for (let i = 0; i < maxMipLevel; i++) { - // if (i >= firstMipLevel) { - // const levelData = levelDatas[levelDatasOffs++] as ArrayBufferView; - // const compByteSize = isCompressed ? 1 : getFormatCompByteSize(this.pixelFormat); - // const sliceElementSize = levelData.byteLength / compByteSize / this.depth; - - // // TODO: Buffer - - // if (is3D && isCompressed) { - // // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1004511 - // for (let z = 0; z < this.depth; z++) { - // if (isWebGL2(gl)) { - // gl.compressedTexSubImage3D( - // this.gl_target, - // i, - // 0, - // 0, - // z, - // w, - // h, - // 1, - // gl_format, - // levelData, - // z * sliceElementSize, - // sliceElementSize, - // ); - // } - // } - // } else if (isCube) { - // for (let z = 0; z < this.depth; z++) { - // const face_target = GL.TEXTURE_CUBE_MAP_POSITIVE_X + (z % 6); - // if (isCompressed) { - // gl.compressedTexSubImage2D( - // face_target, - // i, - // 0, - // 0, - // w, - // h, - // gl_format, - // levelData, - // z * sliceElementSize, - // sliceElementSize, - // ); - // } else { - // gl.texSubImage2D( - // face_target, - // i, - // 0, - // 0, - // w, - // h, - // gl_format, - // gl_type, - // levelData, - // z * sliceElementSize, - // ); - // } - // } - // } else if (is3D) { - // if (isWebGL2(gl)) { - // if (isCompressed) { - // gl.compressedTexSubImage3D(this.gl_target, i, 0, 0, 0, w, h, d, gl_format, levelData); - // } else { - // gl.texSubImage3D(this.gl_target, i, 0, 0, 0, w, h, d, gl_format, gl_type, levelData); - // } - // } - // } else { - // if (isCompressed) { - // gl.compressedTexSubImage2D(this.gl_target, i, 0, 0, w, h, gl_format, levelData); - // } else { - // // @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texSubImage2D - // gl.texSubImage2D(this.gl_target, i, 0, 0, w, h, gl_format, gl_type, levelData); - // } - // } - // } - - // w = Math.max((w / 2) | 0, 1); - // h = Math.max((h / 2) | 0, 1); - // } } destroy() { @@ -362,28 +294,29 @@ export class Texture_GL extends ResourceBase_GL implements Texture { const gl = this.device.gl; if (this.pixelStore) { if (this.pixelStore.unpackFlipY) { - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.pixelStorei(GL.UNPACK_FLIP_Y_WEBGL, true); } if (this.pixelStore.packAlignment) { - gl.pixelStorei(gl.PACK_ALIGNMENT, this.pixelStore.packAlignment); + gl.pixelStorei(GL.PACK_ALIGNMENT, this.pixelStore.packAlignment); } if (this.pixelStore.unpackAlignment) { - gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.pixelStore.unpackAlignment); + gl.pixelStorei(GL.UNPACK_ALIGNMENT, this.pixelStore.unpackAlignment); } } } private generateMipmap(): this { const gl = this.device.gl; - if (this.isNPOT()) { + if (!isWebGL2(gl) && this.isNPOT()) { return this; } - // if (this.gl_texture && this.gl_target) { - // gl.bindTexture(this.gl_target, this.gl_texture); - // gl.generateMipmap(this.gl_target); - // gl.bindTexture(this.gl_target, null); - // } + if (this.gl_texture && this.gl_target) { + gl.bindTexture(this.gl_target, this.gl_texture); + gl.generateMipmap(this.gl_target); + gl.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.NEAREST_MIPMAP_LINEAR); + gl.bindTexture(this.gl_target, null); + } return this; } diff --git a/packages/g-plugin-webgl-renderer/src/render/DynamicUniformBuffer.ts b/packages/g-plugin-webgl-renderer/src/render/DynamicUniformBuffer.ts index f9861d6b5..e54069483 100644 --- a/packages/g-plugin-webgl-renderer/src/render/DynamicUniformBuffer.ts +++ b/packages/g-plugin-webgl-renderer/src/render/DynamicUniformBuffer.ts @@ -1,6 +1,5 @@ import { Device, BufferUsage, BufferFrequencyHint, Buffer } from '../platform'; import { alignNonPowerOfTwo, assert, assertExists } from '../platform/utils'; -import { GPUBufferUsage } from '../platform/webgpu/constants'; // This is a very basic linear allocator. We allocate offsets in-order. export class DynamicUniformBuffer { diff --git a/packages/g-plugin-webgl-renderer/src/render/RenderInst.ts b/packages/g-plugin-webgl-renderer/src/render/RenderInst.ts index 772952f13..9e1130781 100644 --- a/packages/g-plugin-webgl-renderer/src/render/RenderInst.ts +++ b/packages/g-plugin-webgl-renderer/src/render/RenderInst.ts @@ -20,8 +20,10 @@ import { setBitFlagEnabled, setMegaStateFlags, } from '../platform/utils'; +import { Program_GL } from '../platform/webgl2/Program'; import { DynamicUniformBuffer } from './DynamicUniformBuffer'; import { RenderCache } from './RenderCache'; +import { fillVec4 } from './utils'; export enum RenderInstFlags { Indexed = 1 << 0, @@ -35,6 +37,11 @@ export enum RenderInstFlags { InheritedFlags = Indexed | AllowSkippingIfPipelineNotReady, } +export interface RenderInstUniform { + name: string; + value: number | number[] | Float32Array; +} + export class RenderInst { sortKey: number = 0; @@ -46,6 +53,9 @@ export class RenderInst { // Bindings building. private uniformBuffer: DynamicUniformBuffer; + + uniforms: RenderInstUniform[][] = []; + private bindingDescriptors: BindingsDescriptor[] = nArray(1, () => ({ bindingLayout: null, samplerBindings: [], @@ -109,6 +119,7 @@ export class RenderInst { this.renderPipelineDescriptor.sampleCount = o.renderPipelineDescriptor.sampleCount; this.inputState = o.inputState; this.uniformBuffer = o.uniformBuffer; + this.uniforms = [...o.uniforms]; this.drawCount = o.drawCount; this.drawStart = o.drawStart; this.drawInstanceCount = o.drawInstanceCount; @@ -221,6 +232,54 @@ export class RenderInst { this.drawInstanceCount = 1; } + /** + * account for WebGL1 + */ + setUniforms(bufferIndex: number, uniforms: RenderInstUniform[]) { + // use later in WebGL1 + this.uniforms[bufferIndex] = uniforms; + + // calc buffer size + let offset = 0; + const uboBuffer = []; + uniforms.forEach((uniform) => { + const { name, value } = uniform; + const array = typeof value === 'number' ? [value] : value; + const formatByteSize = array.length > 4 ? 4 : array.length; + + // std140 UBO layout + const emptySpace = 4 - (offset % 4); + if (emptySpace !== 4) { + if (emptySpace >= formatByteSize) { + } else { + offset += emptySpace; + for (let j = 0; j < emptySpace; j++) { + uboBuffer.push(0); // padding + } + } + } + + offset += array.length; + + uboBuffer.push(...array); + }); + + // padding + const emptySpace = 4 - (uboBuffer.length % 4); + if (emptySpace !== 4) { + for (let j = 0; j < emptySpace; j++) { + uboBuffer.push(0); + } + } + + // upload UBO + let offs = this.allocateUniformBuffer(bufferIndex, uboBuffer.length); + let d = this.mapUniformBufferF32(bufferIndex); + for (let i = 0; i < uboBuffer.length; i += 4) { + offs += fillVec4(d, offs, uboBuffer[i], uboBuffer[i + 1], uboBuffer[i + 2], uboBuffer[i + 3]); + } + } + setUniformBuffer(uniformBuffer: DynamicUniformBuffer): void { this.uniformBuffer = uniformBuffer; } @@ -421,11 +480,22 @@ export class RenderInst { passRenderer.setInputState(this.inputState); + // upload uniforms for (let i = 0; i < this.bindingDescriptors[0].uniformBufferBindings.length; i++) this.bindingDescriptors[0].uniformBufferBindings[i].buffer = assertExists( this.uniformBuffer.buffer, ); + if ((this.renderPipelineDescriptor.program as Program_GL).gl_program) { + this.uniforms.forEach((uniforms) => { + const uniformsMap = {}; + uniforms.forEach(({ name, value }) => { + uniformsMap[name] = value; + }); + (this.renderPipelineDescriptor.program as Program_GL).setUniforms(uniformsMap); + }); + } + // TODO: Support multiple binding descriptors. const gfxBindings = cache.createBindings({ ...this.bindingDescriptors[0], diff --git a/packages/g-plugin-webgl-renderer/src/render/utils/shader.ts b/packages/g-plugin-webgl-renderer/src/render/utils/shader.ts index e49ea54d9..fb9df27f1 100644 --- a/packages/g-plugin-webgl-renderer/src/render/utils/shader.ts +++ b/packages/g-plugin-webgl-renderer/src/render/utils/shader.ts @@ -35,7 +35,6 @@ varying vec2 v_TexCoord; void main() { gl_FragColor = texture(SAMPLER_2D(u_Texture), v_TexCoord); - gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); } `; diff --git a/packages/g-plugin-webgl-renderer/src/shader/circle.frag b/packages/g-plugin-webgl-renderer/src/shader/circle.frag index e9e939bd5..1eb9d1141 100644 --- a/packages/g-plugin-webgl-renderer/src/shader/circle.frag +++ b/packages/g-plugin-webgl-renderer/src/shader/circle.frag @@ -52,6 +52,6 @@ void main() { gl_FragColor = mix(vec4(diffuseColor.rgb, diffuseColor.a * u_FillOpacity), strokeColor * u_StrokeOpacity, color_t); gl_FragColor.a = gl_FragColor.a * u_Opacity * opacity_t; - if (gl_FragColor.a < 0.01) + if (gl_FragColor.a < 0.001) discard; } \ No newline at end of file diff --git a/packages/g-plugin-webgl-renderer/src/shader/compiler.ts b/packages/g-plugin-webgl-renderer/src/shader/compiler.ts index b4d35c14c..f2a4bf644 100644 --- a/packages/g-plugin-webgl-renderer/src/shader/compiler.ts +++ b/packages/g-plugin-webgl-renderer/src/shader/compiler.ts @@ -26,14 +26,26 @@ function defineStr(k: string, v: string): string { return `#define ${k} ${v}`; } -export function getAttributeLocations(vert: string): { location: number; name: string }[] { - 'layout(location = 0) attribute vec4 a_ModelMatrix0;'; +export function getDefines(shader: string): Record { + const defines = {}; + shader.replace(/^\s*#define\s*(\S*)\s*(\S*)\s*$/gm, (_, name, value) => { + const v = Number(value); + defines[name] = isNaN(v) ? value : v; + return ''; + }); + return defines; +} +export function getAttributeLocations( + vert: string, + defines: Record, +): { location: number; name: string }[] { const locations = []; vert.replace( - /^\s*layout\(location\s*=\s*(\d*)\)\s*attribute\s*vec\d*\s*(.*);$/gm, + /^\s*layout\(location\s*=\s*(\S*)\)\s*attribute\s*\S+\s*(.*);$/gm, (_, location, name) => { - locations.push({ location: Number(location), name }); + const l = Number(location); + locations.push({ location: isNaN(l) ? defines[location] : l, name }); return ''; }, ); @@ -50,7 +62,6 @@ export function preprocessShader_GLSL( const isGLSL100 = vendorInfo.glslVersion === '#version 100'; const supportMRT = vendorInfo.supportMRT && !!features.MRT; - // Garbage WebGL2 shader compiler until I get something better down the line... const lines = source .split('\n') .map((n) => { @@ -153,6 +164,7 @@ layout(set = ${set}, binding = ${binding++}) uniform sampler S_${samplerName}; let concat = ` ${vendorInfo.glslVersion} ${isGLSL100 && supportMRT ? '#extension GL_EXT_draw_buffers : require' : ''} +${isGLSL100 && type === 'frag' ? '#extension GL_OES_standard_derivatives : enable' : ''} ${precision} #define ${type.toUpperCase()} ${ @@ -171,13 +183,12 @@ ${ ${ (type === 'frag' && supportMRT && - // !isGLSL100 && `#define gl_FragColor gbuf_color layout(location = 0) out vec4 gbuf_color; +layout(location = 1) out vec4 gbuf_picking; `) || '' } -${(type === 'frag' && supportMRT && `layout(location = 1) out vec4 gbuf_picking;`) || ''} `) || '' } @@ -196,7 +207,12 @@ ${rest} // interface blocks supported in GLSL ES 3.00 and above only concat = concat.replace(/\s*uniform\s*.*\s*{((?:\s*.*\s*)*?)};/g, (substr, uniforms) => { return uniforms.trim().replace(/^.*$/gm, (uniform: string) => { - return uniform ? `uniform ${uniform.trim()}` : ''; + // eg. #ifdef + const trimmed = uniform.trim(); + if (trimmed.startsWith('#')) { + return trimmed; + } + return uniform ? `uniform ${trimmed}` : ''; }); }); @@ -213,7 +229,7 @@ ${rest} ); // append at the end of fragment shader - concat = concat.replace(/^void\s*main\(\)\s*{$/gm, () => { + concat = concat.replace(/^\s*void\s*main\(\)\s*{\s*$/gm, () => { return `void main() { ${gBuffers.map((gBuffer) => `vec4 ${gBuffer};`).join('\n')} `; diff --git a/packages/g-shader-components/batch.declaration.vert b/packages/g-shader-components/batch.declaration.vert index 7d44bdfca..617181860 100644 --- a/packages/g-shader-components/batch.declaration.vert +++ b/packages/g-shader-components/batch.declaration.vert @@ -8,7 +8,6 @@ layout(location = 6) attribute vec4 a_StylePacked1; layout(location = 7) attribute vec4 a_StylePacked2; layout(location = 8) attribute vec4 a_PickingColor; layout(location = 9) attribute vec2 a_Anchor; -// layout(location = {AttributeLocation.a_Uv}) attribute vec2 a_Uv; varying vec4 v_PickingResult; varying vec4 v_Color; diff --git a/packages/g-shader-components/common.glsl b/packages/g-shader-components/common.glsl index cc34d6167..bcff9266c 100644 --- a/packages/g-shader-components/common.glsl +++ b/packages/g-shader-components/common.glsl @@ -25,6 +25,37 @@ highp float rand( const in vec2 uv ) { return fract( sin( sn ) * c ); } +mat3 transposeMat3(mat3 inMatrix) { + vec3 i0 = inMatrix[0]; + vec3 i1 = inMatrix[1]; + vec3 i2 = inMatrix[2]; + + mat3 outMatrix = mat3( + vec3(i0.x, i1.x, i2.x), + vec3(i0.y, i1.y, i2.y), + vec3(i0.z, i1.z, i2.z) + ); + + return outMatrix; +} + +// https://github.com/glslify/glsl-inverse/blob/master/index.glsl +mat3 inverseMat3(mat3 inMatrix) { + float a00 = inMatrix[0][0], a01 = inMatrix[0][1], a02 = inMatrix[0][2]; + float a10 = inMatrix[1][0], a11 = inMatrix[1][1], a12 = inMatrix[1][2]; + float a20 = inMatrix[2][0], a21 = inMatrix[2][1], a22 = inMatrix[2][2]; + + float b01 = a22 * a11 - a12 * a21; + float b11 = -a22 * a10 + a12 * a20; + float b21 = a21 * a10 - a11 * a20; + + float det = a00 * b01 + a01 * b11 + a02 * b21; + + return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11), + b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10), + b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det; +} + struct DirectionalLight { vec3 direction; float intensity; diff --git a/packages/g-shader-components/line.both.glsl b/packages/g-shader-components/line.both.glsl index 0554f09f6..a5e607d47 100644 --- a/packages/g-shader-components/line.both.glsl +++ b/packages/g-shader-components/line.both.glsl @@ -10,7 +10,7 @@ layout(std140) uniform ub_ObjectParams { float u_MiterLimit; float u_ScaleMode; float u_Alignment; - vec4 u_PickingColor; + vec3 u_PickingColor; float u_Dash; float u_Gap; float u_DashOffset; diff --git a/packages/g-shader-components/mesh.both.glsl b/packages/g-shader-components/mesh.both.glsl index dad7e04a2..2cc0e31d9 100644 --- a/packages/g-shader-components/mesh.both.glsl +++ b/packages/g-shader-components/mesh.both.glsl @@ -1,7 +1,7 @@ layout(std140) uniform ub_ObjectParams { mat4 u_ModelMatrix; vec4 u_Color; - vec4 u_PickingColor; + vec3 u_PickingColor; float u_Opacity; float u_FillOpacity; float u_Visible; diff --git a/packages/g-webgl/src/index.ts b/packages/g-webgl/src/index.ts index 0c7b3864d..746834355 100644 --- a/packages/g-webgl/src/index.ts +++ b/packages/g-webgl/src/index.ts @@ -5,12 +5,24 @@ import { ContextRegisterPlugin } from './ContextRegisterPlugin'; export { DomInteraction, WebGLRenderer }; +interface WebGLRendererConfig extends RendererConfig { + targets: ('webgl1' | 'webgl2' | 'webgpu')[]; +} + export class Renderer extends AbstractRenderer { - constructor(config?: Partial) { + constructor(config?: Partial) { super(config); this.registerPlugin(new ContextRegisterPlugin()); - this.registerPlugin(new WebGLRenderer.Plugin()); + this.registerPlugin( + new WebGLRenderer.Plugin( + config.targets + ? { + targets: config.targets, + } + : {}, + ), + ); this.registerPlugin(new DomInteraction.Plugin()); } } diff --git a/packages/site/docs/api/3d/material.en.md b/packages/site/docs/api/3d/material.en.md index e3a2e7588..410e43de2 100644 --- a/packages/site/docs/api/3d/material.en.md +++ b/packages/site/docs/api/3d/material.en.md @@ -75,6 +75,14 @@ const basicMaterial = new MeshBasicMaterial({ }); ``` +## wireframeColor + +开启 wireframe 后可指定颜色,默认为 `'black'`。 + +## wireframeLineWidth + +开启 wireframe 后可指定线宽,默认为 1。 + ## cullMode 支持以下枚举值,默认使用 `CullMode.NONE`,即不开启背面剔除: @@ -192,73 +200,25 @@ export enum BlendFactor { # 基础方法 -## addUniform +## setUniforms -添加一个 MaterialUniform +添加一组 Uniform 参数列表: -- uniform: MaterialUniform - -```js -type MaterialUniformData = - | number - | [number] - | [number, number] - | [number, number, number] - | Tuple4Number; -export interface MaterialUniform { - name: string; - format: Format; - data: MaterialUniformData; -} -``` - -其中 Format 支持以下枚举值,与 Shader 中基础数据类型对应关系如下: - -```js -export enum Format { - F32_R, // float - F32_RG, // vec2 - F32_RGB, // vec3 - F32_RGBA, // vec4 -} -``` +- uniforms: `Record` 例如 MeshPhongMaterial 在初始化时会添加如下: ```js -material.addUniform({ - name: 'u_BumpScale', - format: Format.F32_R, - data: 5, +material.setUniform({ + u_BumpScale: 5, }); // 对应 shader 中的: // uniform float u_BumpScale; ``` -## removeUniform - -按名称删除 MaterialUniform。 - -参数列表: - -- uniformName: string - -## updateUniformData - -更新 MaterialUniform 的数据。 - -参数列表: - -- uniformName: string Shader 中使用的 uniform 名称 -- data: MaterialUniformData 数据 - -```js -material.updateUniformData('u_BumpScale', 5); -``` - ## addTexture 添加一个纹理。 diff --git a/packages/site/docs/api/3d/material.zh.md b/packages/site/docs/api/3d/material.zh.md index 8c303e4be..410e43de2 100644 --- a/packages/site/docs/api/3d/material.zh.md +++ b/packages/site/docs/api/3d/material.zh.md @@ -200,73 +200,25 @@ export enum BlendFactor { # 基础方法 -## addUniform +## setUniforms -添加一个 MaterialUniform +添加一组 Uniform 参数列表: -- uniform: MaterialUniform - -```js -type MaterialUniformData = - | number - | [number] - | [number, number] - | [number, number, number] - | Tuple4Number; -export interface MaterialUniform { - name: string; - format: Format; - data: MaterialUniformData; -} -``` - -其中 Format 支持以下枚举值,与 Shader 中基础数据类型对应关系如下: - -```js -export enum Format { - F32_R, // float - F32_RG, // vec2 - F32_RGB, // vec3 - F32_RGBA, // vec4 -} -``` +- uniforms: `Record` 例如 MeshPhongMaterial 在初始化时会添加如下: ```js -material.addUniform({ - name: 'u_BumpScale', - format: Format.F32_R, - data: 5, +material.setUniform({ + u_BumpScale: 5, }); // 对应 shader 中的: // uniform float u_BumpScale; ``` -## removeUniform - -按名称删除 MaterialUniform。 - -参数列表: - -- uniformName: string - -## updateUniformData - -更新 MaterialUniform 的数据。 - -参数列表: - -- uniformName: string Shader 中使用的 uniform 名称 -- data: MaterialUniformData 数据 - -```js -material.updateUniformData('u_BumpScale', 5); -``` - ## addTexture 添加一个纹理。 diff --git a/packages/site/examples/3d/demo/buffer-geometry.js b/packages/site/examples/3d/demo/buffer-geometry.js index 2927531b9..98b829143 100644 --- a/packages/site/examples/3d/demo/buffer-geometry.js +++ b/packages/site/examples/3d/demo/buffer-geometry.js @@ -35,7 +35,7 @@ bufferGeometry.setVertexBuffer({ { format: Format.F32_RGB, bufferByteOffset: 4 * 0, - location: VertexAttributeLocation.POSITION, + location: VertexAttributeLocation.MAX, }, ], // use 6 vertices diff --git a/packages/site/examples/3d/demo/shader-material.js b/packages/site/examples/3d/demo/shader-material.js index a8ba9520f..10917b2e3 100644 --- a/packages/site/examples/3d/demo/shader-material.js +++ b/packages/site/examples/3d/demo/shader-material.js @@ -9,14 +9,12 @@ import { VertexAttributeLocation, Plugin as Plugin3D, } from '@antv/g-plugin-3d'; -import { Plugin as PluginControl } from '@antv/g-plugin-control'; import Stats from 'stats.js'; import * as dat from 'dat.gui'; // create a renderer const renderer = new Renderer(); renderer.registerPlugin(new Plugin3D()); -renderer.registerPlugin(new PluginControl()); // create a canvas const canvas = new Canvas({ @@ -36,7 +34,7 @@ bufferGeometry.setVertexBuffer({ { format: Format.F32_RGB, bufferByteOffset: 4 * 0, - location: VertexAttributeLocation.POSITION, + location: VertexAttributeLocation.MAX, }, ], // use 6 vertices @@ -63,45 +61,15 @@ const shaderMaterial = new ShaderMaterial({ // float u_NoiseMode; }; - layout(location = 0) attribute vec4 a_ModelMatrix0; - layout(location = 1) attribute vec4 a_ModelMatrix1; - layout(location = 2) attribute vec4 a_ModelMatrix2; - layout(location = 3) attribute vec4 a_ModelMatrix3; - layout(location = 4) attribute vec4 a_Color; - layout(location = 5) attribute vec4 a_StrokeColor; - layout(location = 6) attribute vec4 a_StylePacked1; - layout(location = 7) attribute vec4 a_StylePacked2; - layout(location = 8) attribute vec4 a_PickingColor; - layout(location = 9) attribute vec2 a_Anchor; - varying vec4 v_PickingResult; - varying vec4 v_Color; - varying vec4 v_StrokeColor; - varying vec4 v_StylePacked1; - varying vec4 v_StylePacked2; - #define COLOR_SCALE 1. / 255. - void setPickingColor(vec3 pickingColor) { - v_PickingResult.rgb = pickingColor * COLOR_SCALE; - } - vec4 project(vec4 pos, mat4 pm, mat4 vm, mat4 mm) { - return pm * vm * mm * pos; - } - layout(location = 10) attribute vec3 a_Position; + layout(location = ${VertexAttributeLocation.MODEL_MATRIX0}) attribute vec4 a_ModelMatrix0; + layout(location = ${VertexAttributeLocation.MODEL_MATRIX1}) attribute vec4 a_ModelMatrix1; + layout(location = ${VertexAttributeLocation.MODEL_MATRIX2}) attribute vec4 a_ModelMatrix2; + layout(location = ${VertexAttributeLocation.MODEL_MATRIX3}) attribute vec4 a_ModelMatrix3; + layout(location = ${VertexAttributeLocation.MAX}) attribute vec3 a_Position; void main() { mat4 u_ModelMatrix = mat4(a_ModelMatrix0, a_ModelMatrix1, a_ModelMatrix2, a_ModelMatrix3); - vec4 u_StrokeColor = a_StrokeColor; - float u_Opacity = a_StylePacked1.x; - float u_FillOpacity = a_StylePacked1.y; - float u_StrokeOpacity = a_StylePacked1.z; - float u_StrokeWidth = a_StylePacked1.w; - float u_ZIndex = a_PickingColor.w; - setPickingColor(a_PickingColor.xyz); - v_Color = a_Color; - v_StrokeColor = a_StrokeColor; - v_StylePacked1 = a_StylePacked1; - v_StylePacked2 = a_StylePacked2; - - gl_Position = project(vec4(a_Position, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * vec4(a_Position, 1.0); } `, fragmentShader: ` @@ -119,12 +87,6 @@ const shaderMaterial = new ShaderMaterial({ // float u_NoiseMode; }; - varying vec4 v_PickingResult; - varying vec4 v_Color; - varying vec4 v_StrokeColor; - varying vec4 v_StylePacked1; - varying vec4 v_StylePacked2; - float random (vec2 st) { return fract(sin( dot(st.xy,vec2(12.9898,78.233)))* @@ -163,20 +125,6 @@ const shaderMaterial = new ShaderMaterial({ // } void main() { - vec4 u_Color = v_Color; - vec4 u_StrokeColor = v_StrokeColor; - float u_Opacity = v_StylePacked1.x; - float u_FillOpacity = v_StylePacked1.y; - float u_StrokeOpacity = v_StylePacked1.z; - float u_StrokeWidth = v_StylePacked1.w; - float u_Visible = v_StylePacked2.x; - gbuf_picking = vec4(v_PickingResult.rgb, 1.0); - if (u_Visible < 1.0) { - discard; - } - gl_FragColor = u_Color; - gl_FragColor.a = gl_FragColor.a * u_Opacity; - vec2 st = gl_FragCoord.xy / u_Viewport; vec2 pos = vec2(st * u_Level); float n = noise(pos); @@ -184,17 +132,10 @@ const shaderMaterial = new ShaderMaterial({ } `, }); -shaderMaterial.addUniform({ - name: 'u_Level', - format: Format.F32_R, - data: 5, +shaderMaterial.setUniforms({ + u_Level: 5, + u_NoiseMode: 0, }); -// shaderMaterial.addUniform({ -// name: 'u_NoiseMode', -// format: Format.F32_R, -// data: 0, -// }); - const mesh = new Mesh({ style: { fill: '#1890FF', @@ -230,6 +171,6 @@ const noiseConfig = { level: 5, }; noiseFolder.add(noiseConfig, 'level', 1, 100, 1).onChange((level) => { - shaderMaterial.updateUniformData('u_Level', level); + shaderMaterial.setUniforms({ u_Level: level }); }); noiseFolder.open(); diff --git a/packages/site/examples/scenegraph/demo/hierarchy.js b/packages/site/examples/scenegraph/demo/hierarchy.js index b0ca339a0..853119dad 100644 --- a/packages/site/examples/scenegraph/demo/hierarchy.js +++ b/packages/site/examples/scenegraph/demo/hierarchy.js @@ -82,6 +82,9 @@ moonOrbit.translate(100, 0); canvas.appendChild(solarSystem); +// use AntV G devtools +window.__g_instances__ = [canvas]; + // stats const stats = new Stats(); stats.showPanel(0); diff --git a/packages/site/examples/scenegraph/demo/visibility.js b/packages/site/examples/scenegraph/demo/visibility.js index 8e5a12a67..830d042ab 100644 --- a/packages/site/examples/scenegraph/demo/visibility.js +++ b/packages/site/examples/scenegraph/demo/visibility.js @@ -82,6 +82,9 @@ moonOrbit.translate(50, 0); canvas.appendChild(solarSystem); +// use AntV G devtools +window.__g_instances__ = [canvas]; + // stats const stats = new Stats(); stats.showPanel(0); diff --git a/packages/site/examples/shape/demo/circle.js b/packages/site/examples/shape/demo/circle.js index 27041c2e2..14ef71128 100644 --- a/packages/site/examples/shape/demo/circle.js +++ b/packages/site/examples/shape/demo/circle.js @@ -35,6 +35,9 @@ const circle = new Circle({ // add a circle to canvas canvas.appendChild(circle); +// use AntV G devtools +window.__g_instances__ = [canvas]; + // stats const stats = new Stats(); stats.showPanel(0); @@ -70,6 +73,8 @@ const circleConfig = { fill: '#1890FF', stroke: '#F04864', lineWidth: 4, + lineDash: 0, + lineDashOffset: 0, fillOpacity: 1, strokeOpacity: 1, anchorX: 0.5, @@ -103,6 +108,12 @@ circleFolder.add(circleConfig, 'shadowOffsetY', -50, 50).onChange((shadowOffsetY circleFolder.add(circleConfig, 'lineWidth', 1, 20).onChange((lineWidth) => { circle.attr('lineWidth', lineWidth); }); +circleFolder.add(circleConfig, 'lineDash', 0, 100).onChange((lineDash) => { + circle.style.lineDash = [lineDash]; +}); +circleFolder.add(circleConfig, 'lineDashOffset', 0, 100).onChange((lineDashOffset) => { + circle.style.lineDashOffset = lineDashOffset; +}); circleFolder.add(circleConfig, 'fillOpacity', 0, 1, 0.1).onChange((opacity) => { circle.attr('fillOpacity', opacity); }); diff --git a/packages/site/examples/shape/demo/path.js b/packages/site/examples/shape/demo/path.js index 09eab5a79..df912ba23 100644 --- a/packages/site/examples/shape/demo/path.js +++ b/packages/site/examples/shape/demo/path.js @@ -21,9 +21,10 @@ const path1 = new Path({ style: { path: [ ['M', 100, 100], - ['L', 200, 200], + ['L', 200, 100], ], stroke: '#F04864', + lineDash: [10], }, }); const path2 = new Path({ @@ -115,8 +116,20 @@ rendererFolder.open(); const circleFolder = gui.addFolder('circle'); const circleConfig = { r: 100, + lineWidth: 1, + lineDash: 0, + lineDashOffset: 0, }; circleFolder.add(circleConfig, 'r', 0, 200).onChange((r) => { circlePath.style.path = getCirclePath(0, 0, r, r); }); +circleFolder.add(circleConfig, 'lineWidth', 1, 20).onChange((lineWidth) => { + circlePath.style.lineWidth = lineWidth; +}); +circleFolder.add(circleConfig, 'lineDash', 0, 100).onChange((lineDash) => { + circlePath.style.lineDash = [lineDash]; +}); +circleFolder.add(circleConfig, 'lineDashOffset', 0, 100).onChange((lineDashOffset) => { + circlePath.style.lineDashOffset = lineDashOffset; +}); circleFolder.open();