From e5152df138456696547605f18b526b2ccc977fc4 Mon Sep 17 00:00:00 2001 From: OldGentleMan <397939361@qq.com> Date: Thu, 27 Jul 2023 13:51:07 +0800 Subject: [PATCH] chore: fix error (#258) add grass system fix render pass frame time wrong fix grass segment fix pbr shader fix clear coat lighting specular fix clear coat lighting specular fix grass size and vertex animation fix grass size and vertex animation fix muilt layer clearcoat fix clear coat shader add physic car sample add terrain sample change collect render node add lambert material commit gpu buffer by buffer mapasync fix shadow render node fix point shadow remove ssh chore transform fix fog shader. fix pbr metallic map and ao map add draw call sample fix shadow maping at mac error fix transform notifyLocalChange error fix instanceDraw fix pbr color fix change material not use --- .gitignore | 1 + package.json | 2 +- packages/effect/grass/GrassNode.ts | 5 + .../effect/grass/component/GrassComponent.ts | 46 +++ .../effect/grass/geometry/GrassGeometry.ts | 117 ++++++ .../effect/grass/material/GrassMaterial.ts | 212 ++++++++++ .../effect/grass/shader/GrassBaseShader.ts | 51 +++ .../grass/shader/GrassCastShadowShader.ts | 109 +++++ packages/effect/grass/shader/GrassShader.ts | 166 ++++++++ .../shader/GrassVertexAttributeShader.ts | 70 ++++ packages/effect/index.ts | 5 + packages/effect/package.json | 24 ++ .../terrain/geometry/TerrainGeometry.ts | 66 +++ packages/effect/tsconfig.json | 29 ++ packages/uiTool/package.json | 36 ++ public | 2 +- samples/animation/Sample_CurveAnimation.ts | 3 +- samples/animation/Sample_Skeleton3.ts | 2 - samples/base/Sample_UseComponent.ts | 18 + samples/benchmark/Sample_SphereDraw.ts | 125 ++++++ samples/benchmark/Sample_drawCall.ts | 149 +++++++ samples/ext/Sample_Grass.ts | 177 +++++++++ samples/ext/Sample_Terrain.ts | 93 +++++ samples/gi/Sample_GI.ts | 19 +- samples/gi/Sample_GICornellBox.ts | 5 +- samples/loader/Sample_LoadGLB2.ts | 57 +++ samples/loader/Sample_LoadGLB3.ts | 49 +++ samples/material/Sample_ChangeMaterial.ts | 115 ++++++ samples/material/Sample_ClearCoat.ts | 114 ++++++ samples/physics/Sample_PhysicsCar.ts | 376 ++++++++++++++++++ samples/utils/GUIUtil.ts | 1 + src/Engine3D.ts | 64 ++- src/assets/shader/ShaderLib.ts | 6 +- src/assets/shader/core/base/Common_frag.ts | 2 + src/assets/shader/core/inline/Inline_vert.ts | 1 + .../{LightStruct.ts => ClusterLight.ts} | 2 +- .../shader/core/struct/LightStructFrag.ts | 109 ----- src/assets/shader/glsl/Quad_glsl.ts | 2 +- src/assets/shader/lighting/BRDF_frag.ts | 78 ++-- src/assets/shader/lighting/BxDF_frag.ts | 127 +++--- src/assets/shader/lighting/Irradiance_frag.ts | 3 +- .../shader/lighting/LightingFunction_frag.ts | 39 +- src/assets/shader/lighting/UnLit_frag.ts | 1 - src/assets/shader/materials/LambertShader.ts | 59 +++ src/assets/shader/materials/Lambert_shader.ts | 74 ---- src/assets/shader/materials/PBRLItShader.ts | 46 ++- .../materials/program/Clearcoat_frag.ts | 35 +- .../materials/program/NormalMap_frag.ts | 2 +- .../materials/program/ShadowMapping_frag.ts | 166 ++++---- src/assets/shader/math/MatrixShader.ts | 107 +++++ src/assets/shader/post/GlobalFog_shader.ts | 1 + src/assets/shader/utils/ColorUtil.ts | 24 +- src/components/ColliderComponent.ts | 9 + src/components/Transform.ts | 46 ++- .../controller/FlyCameraController.ts | 2 +- src/components/gui/core/GUIRenderer.ts | 2 +- src/components/lights/DirectLight.ts | 1 + src/components/lights/PointLight.ts | 2 +- src/components/lights/SpotLight.ts | 2 +- .../renderer/InstanceDrawComponent.ts | 139 ++++--- src/components/renderer/RenderNode.ts | 125 +++--- src/components/renderer/SkyRenderer.ts | 10 +- src/core/Camera3D.ts | 2 +- src/core/geometry/GeometryBase.ts | 6 +- src/core/geometry/GeometryVertexBuffer.ts | 2 + src/core/geometry/VertexAttributeName.ts | 1 + src/core/geometry/VertexAttributeStride.ts | 1 + src/gfx/graphics/webGpu/Context3D.ts | 24 +- .../core/bindGroups/GlobalUniformGroup.ts | 49 ++- .../webGpu/core/bindGroups/MatrixBindGroup.ts | 38 +- .../webGpu/core/buffer/GPUBufferBase.ts | 14 +- .../webGpu/core/buffer/MatrixGPUBuffer.ts | 65 +++ .../graphics/webGpu/core/texture/Texture.ts | 4 + .../graphics/webGpu/shader/RenderShader.ts | 8 + src/gfx/graphics/webGpu/shader/ShaderBase.ts | 9 +- src/gfx/renderJob/collect/ComponentCollect.ts | 25 ++ .../renderJob/collect/EntityBatchCollect.ts | 2 +- src/gfx/renderJob/collect/EntityCollect.ts | 14 + .../renderJob/collect/RenderShaderCollect.ts | 61 +++ .../renderJob/collect/ShadowLightsCollect.ts | 2 +- .../renderJob/occlusion/OcclusionSystem.ts | 50 ++- .../passRenderer/color/ColorPassRenderer.ts | 45 ++- .../passRenderer/ddgi/DDGIProbeRenderer.ts | 30 +- .../shadow/PointLightShadowRenderer.ts | 77 ++-- .../shadow/ShadowMapPassRenderer.ts | 53 ++- src/index.ts | 8 +- .../parser/gltf/GLTFSubParserConverter.ts | 5 + src/materials/LambertMaterial.ts | 31 +- src/materials/MaterialBase.ts | 1 + src/materials/PhysicMaterial.ts | 10 +- src/math/Color.ts | 6 +- src/math/MathUtil.ts | 2 +- src/math/Matrix4.ts | 23 +- src/math/Quaternion.ts | 6 +- src/shape/CylinderGeometry.ts | 2 +- src/shape/PlaneGeometry.ts | 9 +- src/textures/BitmapTexture2D.ts | 6 +- src/textures/VirtualTexture.ts | 1 + src/util/GeometryUtil.ts | 5 +- src/util/Vector3Ex.ts | 18 +- test/math/MatrixDO.test.ts | 2 +- vite.config.js | 7 +- 102 files changed, 3499 insertions(+), 755 deletions(-) create mode 100644 packages/effect/grass/GrassNode.ts create mode 100644 packages/effect/grass/component/GrassComponent.ts create mode 100644 packages/effect/grass/geometry/GrassGeometry.ts create mode 100644 packages/effect/grass/material/GrassMaterial.ts create mode 100644 packages/effect/grass/shader/GrassBaseShader.ts create mode 100644 packages/effect/grass/shader/GrassCastShadowShader.ts create mode 100644 packages/effect/grass/shader/GrassShader.ts create mode 100644 packages/effect/grass/shader/GrassVertexAttributeShader.ts create mode 100644 packages/effect/index.ts create mode 100644 packages/effect/package.json create mode 100644 packages/effect/terrain/geometry/TerrainGeometry.ts create mode 100644 packages/effect/tsconfig.json create mode 100644 packages/uiTool/package.json create mode 100644 samples/benchmark/Sample_SphereDraw.ts create mode 100644 samples/benchmark/Sample_drawCall.ts create mode 100644 samples/ext/Sample_Grass.ts create mode 100644 samples/ext/Sample_Terrain.ts create mode 100644 samples/loader/Sample_LoadGLB2.ts create mode 100644 samples/loader/Sample_LoadGLB3.ts create mode 100644 samples/material/Sample_ChangeMaterial.ts create mode 100644 samples/material/Sample_ClearCoat.ts create mode 100644 samples/physics/Sample_PhysicsCar.ts rename src/assets/shader/core/struct/{LightStruct.ts => ClusterLight.ts} (98%) delete mode 100644 src/assets/shader/core/struct/LightStructFrag.ts create mode 100644 src/assets/shader/materials/LambertShader.ts delete mode 100644 src/assets/shader/materials/Lambert_shader.ts create mode 100644 src/assets/shader/math/MatrixShader.ts create mode 100644 src/gfx/graphics/webGpu/core/buffer/MatrixGPUBuffer.ts create mode 100644 src/gfx/renderJob/collect/RenderShaderCollect.ts diff --git a/.gitignore b/.gitignore index fa8e268a..fc21e3ee 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ dist /js /.vscode +/.labe diff --git a/package.json b/package.json index a489447f..43850457 100644 --- a/package.json +++ b/package.json @@ -54,4 +54,4 @@ "vite": "^4.3.9", "xvfb-maybe": "^0.2.1" } -} \ No newline at end of file +} diff --git a/packages/effect/grass/GrassNode.ts b/packages/effect/grass/GrassNode.ts new file mode 100644 index 00000000..5f77d432 --- /dev/null +++ b/packages/effect/grass/GrassNode.ts @@ -0,0 +1,5 @@ +import { Transform } from "@orillusion/core"; + +export class GrassNode extends Transform { + +} \ No newline at end of file diff --git a/packages/effect/grass/component/GrassComponent.ts b/packages/effect/grass/component/GrassComponent.ts new file mode 100644 index 00000000..db1e08c4 --- /dev/null +++ b/packages/effect/grass/component/GrassComponent.ts @@ -0,0 +1,46 @@ +import { BoundingBox, Color, ComponentBase, GPUPrimitiveTopology, LightingFunction_frag, MeshRenderer, Texture, UnLitMaterial, Vector3, VertexAttributeName } from "@orillusion/core"; +import { GrassMaterial } from "../material/GrassMaterial"; +import { GrassGeometry } from "../geometry/GrassGeometry"; +import { GrassNode } from "../GrassNode"; + +export class GrassComponent extends MeshRenderer { + + + public grassMaterial: GrassMaterial; + public grassGeometry: GrassGeometry; + + constructor() { + super(); + this.grassMaterial = new GrassMaterial(); + this.alwaysRender = true; + } + + public init(param?: any): void { + super.init(); + } + + public setGrass(grassWidth: number, grassHeight: number, segment: number, density: number, count: number = 1000) { + this.grassGeometry = this.geometry = new GrassGeometry(grassWidth, grassHeight, 1, segment, count); + this.material = this.grassMaterial; + // this.material.topology = GPUPrimitiveTopology.line_list; + // this.material = this.grassMaterial; + } + + setWindNoiseTexture(gustNoiseTexture: Texture) { + this.grassMaterial.windMap = gustNoiseTexture; + } + + + public setMinMax(min: Vector3, max: Vector3) { + this.grassGeometry.bounds = new BoundingBox(new Vector3(), new Vector3(1, 1, 1)); + this.grassGeometry.bounds.setFromMinMax(min, max); + } + + public setGrassTexture(grassTexture: Texture) { + this.grassMaterial.baseMap = grassTexture; + } + + public get nodes(): GrassNode[] { + return this.grassGeometry.nodes; + } +} \ No newline at end of file diff --git a/packages/effect/grass/geometry/GrassGeometry.ts b/packages/effect/grass/geometry/GrassGeometry.ts new file mode 100644 index 00000000..fe8c89d7 --- /dev/null +++ b/packages/effect/grass/geometry/GrassGeometry.ts @@ -0,0 +1,117 @@ +import { BoundingBox, GeometryBase, Vector3, VertexAttributeName } from "@orillusion/core"; +import { GrassNode } from "../GrassNode"; + + + + +export class GrassGeometry extends GeometryBase { + public width: number; + public height: number; + public segmentW: number; + public segmentH: number; + public nodes: GrassNode[]; + + constructor(width: number, height: number, segmentW: number = 1, segmentH: number = 1, count: number) { + super(); + this.width = width; + this.height = height; + this.segmentW = segmentW; + this.segmentH = segmentH; + this.nodes = []; + this.buildGrass(count); + } + + private buildGrass(count: number) { + var tw: number = this.segmentW + 1; + var singleCont: number = tw * (this.segmentH + 1); + let vertexCount = singleCont * count; + let position_arr = new Float32Array(vertexCount * 3); + let normal_arr = new Float32Array(vertexCount * 3); + let uv_arr = new Float32Array(vertexCount * 2); + let weights_arr = new Float32Array(vertexCount * 4); + let modelID_arr = new Float32Array(vertexCount); + + let faceIndexCount = this.segmentW * this.segmentH * 2 * 3; + let indexes: Uint32Array = new Uint32Array(faceIndexCount * count); + var indexP: number = 0; + var indexN: number = 0; + var indexU: number = 0; + var indexW: number = 0; + var indexI: number = 0; + let numIndices = 0; + let cacheIndex = 0; + + let pi = 3.1415926 * 0.5; + for (let gi = 0; gi < count; gi++) { + let node = new GrassNode(); + this.nodes.push(node); + + let dir = new Vector3(1 * Math.random() - 0.5, 0.0, 1 * Math.random() - 0.5); + let curvature = 0.5 * Math.random(); + + for (var yi: number = 0; yi <= this.segmentH; ++yi) { + for (var xi: number = 0; xi <= this.segmentW; ++xi) { + let weight = yi / this.segmentH; + let x = this.width * (xi / this.segmentW); + let y = this.height * (weight); + position_arr[indexP++] = (x - this.width * 0.5) * (1.0 - weight); + position_arr[indexP++] = 0; + position_arr[indexP++] = 0; + + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 0; + normal_arr[indexN++] = 1; + + uv_arr[indexU++] = xi / this.segmentW; + uv_arr[indexU++] = 1.0 - yi / this.segmentH; + + weights_arr[indexW++] = dir.x; + weights_arr[indexW++] = dir.y; + weights_arr[indexW++] = dir.z; + weights_arr[indexW++] = curvature; + + modelID_arr[indexI++] = node.worldMatrix.index; + } + } + + for (let i = 0; i < this.segmentH; i++) { + for (let j = 0; j < this.segmentW; j++) { + let base = j + i * tw + cacheIndex; + let i1 = (base + 1); + let i2 = base; + let i3 = (base + tw); + + let i4 = (base + 1);; + let i5 = (base + tw); + let i6 = (base + tw + 1); + + indexes[numIndices++] = i1; + indexes[numIndices++] = i2; + indexes[numIndices++] = i3; + indexes[numIndices++] = i4; + indexes[numIndices++] = i5; + indexes[numIndices++] = i6; + } + } + + cacheIndex += singleCont; + } + + this.setIndices(indexes); + this.setAttribute(VertexAttributeName.position, position_arr); + this.setAttribute(VertexAttributeName.normal, normal_arr); + this.setAttribute(VertexAttributeName.uv, uv_arr); + this.setAttribute(VertexAttributeName.TEXCOORD_1, uv_arr); + this.setAttribute(VertexAttributeName.vIndex, modelID_arr); + this.setAttribute(VertexAttributeName.weights0, weights_arr); + + this.addSubGeometry({ + indexStart: 0, + indexCount: indexes.length, + vertexStart: 0, + index: 0, + }); + + this.bounds = new BoundingBox(Vector3.ZERO, new Vector3(9999, 9999, 9999)); + } +} \ No newline at end of file diff --git a/packages/effect/grass/material/GrassMaterial.ts b/packages/effect/grass/material/GrassMaterial.ts new file mode 100644 index 00000000..e7a1b214 --- /dev/null +++ b/packages/effect/grass/material/GrassMaterial.ts @@ -0,0 +1,212 @@ +import { BlendMode, Color, Engine3D, GPUAddressMode, MaterialBase, MaterialPass, RendererType, ShaderLib, Texture, Vector2, Vector3, Vector4 } from "@orillusion/core"; +import { GrassShader } from "../shader/GrassShader"; +import { GrassVertexAttributeShader } from "../shader/GrassVertexAttributeShader"; +import { GrassCastShadowShader } from "../shader/GrassCastShadowShader"; + +export class GrassMaterial extends MaterialBase { + constructor() { + super(); + + ShaderLib.register("GrassVertexAttributeShader", GrassVertexAttributeShader); + ShaderLib.register("GrassShader", GrassShader); + + let shader = this.setShader(`GrassShader`, `GrassShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setDefine("TRANSFORMVERTEX", true); + let shaderState = shader.shaderState; + shaderState.acceptShadow = true; + shaderState.receiveEnv = true; + shaderState.acceptGI = false; + shaderState.useLight = true; + shaderState.castShadow = false; + shaderState.blendMode = BlendMode.NONE; + + ShaderLib.register("GrassCastShadowShader", GrassCastShadowShader); + let shadowPass = new MaterialBase(); + shadowPass.isPassMaterial = true; + let shadowShader = shadowPass.setShader(`GrassCastShadowShader`, `GrassCastShadowShader`); + shadowPass.setDefine("USE_ALPHACUT", true); + shadowPass.setDefine("TRANSFORMVERTEX", true); + shadowShader.setShaderEntry(`VertMain`) + shadowShader.shaderState.blendMode = BlendMode.NONE; + shadowShader.shaderState.receiveEnv = false; + shader.setPassShader(RendererType.SHADOW, shadowPass); + this.addPass(RendererType.SHADOW, shadowPass); + + + shader.setUniformColor("baseColor", new Color(0.0, 1.0, 0.0, 1.0)); + shader.setUniformColor("grassBottomColor", new Color(3 / 255, 16 / 255, 3 / 255)); + shader.setUniformColor("grassTopColor", new Color(45 / 255, 154 / 255, 74 / 255, 1.0)); + shader.setUniformColor("materialF0", new Color(0.04, 0.04, 0.04, 1.0 - 0.04)); + shader.setUniformVector4("windBound", new Vector4(0, 0, 2000, 2000)); + shader.setUniformVector2("windDirection", new Vector2(0.6, 0.8)); + shader.setUniformFloat("windPower", 0.8); + shader.setUniformFloat("windSpeed", 12); + shader.setUniformFloat("translucent", 0.35); + shader.setUniformFloat("roughness", 0.35); + shader.setUniformFloat("curvature", 0.4068); + shader.setUniformFloat("grassHeight", 10); + shader.setUniformFloat("soft", 5); + shader.setUniformFloat("specular", 0.15); + + shadowShader.setUniformColor("baseColor", new Color(0.0, 1.0, 0.0, 1.0)); + shadowShader.setUniformColor("grassBottomColor", new Color(39 / 255, 87 / 255, 36 / 255)); + shadowShader.setUniformColor("grassTopColor", new Color(74 / 255, 163 / 255, 93 / 255, 1.0)); + shadowShader.setUniformColor("materialF0", new Color(0.04, 0.04, 0.04, 1.0 - 0.04)); + shadowShader.setUniformVector4("windBound", new Vector4(0, 0, 2000, 2000)); + shadowShader.setUniformVector2("windDirection", new Vector2(0.6, 0.8)); + shadowShader.setUniformFloat("windPower", 0.8); + shadowShader.setUniformFloat("windSpeed", 10); + shadowShader.setUniformFloat("translucent", 0.35); + shadowShader.setUniformFloat("roughness", 0.35); + shadowShader.setUniformFloat("curvature", 0.4068); + shadowShader.setUniformFloat("grassHeight", 10); + shadowShader.setUniformFloat("soft", 5); + shadowShader.setUniformFloat("specular", 0.15); + + // default value + // this.baseMap = Engine3D.res.whiteTexture; + this.doubleSide = true; + shadowPass.doubleSide = true; + } + + public set baseMap(texture: Texture) { + texture.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT; + super.baseMap = texture; + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.baseMap = texture; + } + + public get baseMap(): Texture { + return super.baseMap; + } + + public set windMap(texture: Texture) { + texture.visibility = GPUShaderStage.VERTEX; + texture.addressModeU = GPUAddressMode.repeat; + texture.addressModeV = GPUAddressMode.repeat; + this.renderShader.setTexture("windMap", texture); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setTexture("windMap", texture); + } + + public set windBound(v: Vector4) { + this.renderShader.setUniformVector4("windBound", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformVector4("windBound", v); + } + + public get windBound(): Vector4 { + return this.renderShader.uniforms["windBound"].vector4; + } + + public set grassBaseColor(v: Color) { + this.renderShader.setUniformColor("grassBottomColor", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformColor("grassBottomColor", v); + } + + public get grassBaseColor(): Color { + return this.renderShader.uniforms["grassBottomColor"].color; + } + + public set grassTopColor(v: Color) { + this.renderShader.setUniformColor("grassTopColor", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformColor("grassTopColor", v); + } + + public get grassTopColor(): Color { + return this.renderShader.uniforms["grassTopColor"].color; + } + + public set windDirection(v: Vector2) { + this.renderShader.setUniformVector2("windDirection", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformVector2("windDirection", v); + } + + public get windDirection(): Vector2 { + return this.renderShader.uniforms["windDirection"].vector2; + } + + public set windPower(v: number) { + this.renderShader.setUniformFloat("windPower", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("windPower", v); + } + + public get windPower(): number { + return this.renderShader.uniforms["windPower"].data; + } + + public set windSpeed(v: number) { + this.renderShader.setUniformFloat("windSpeed", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("windSpeed", v); + } + + public get windSpeed(): number { + return this.renderShader.uniforms["windSpeed"].data; + } + + public set grassHeight(v: number) { + this.renderShader.setUniformFloat("grassHeight", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("grassHeight", v); + } + + public get grassHeight(): number { + return this.renderShader.uniforms["grassHeight"].data; + } + + public set curvature(v: number) { + this.renderShader.setUniformFloat("curvature", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("curvature", v); + } + + public get curvature(): number { + return this.renderShader.uniforms["curvature"].data; + } + + public set roughness(v: number) { + this.renderShader.setUniformFloat("roughness", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("roughness", v); + } + + public get roughness(): number { + return this.renderShader.uniforms["roughness"].data; + } + + public set translucent(v: number) { + this.renderShader.setUniformFloat("translucent", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("translucent", v); + } + + public get translucent(): number { + return this.renderShader.uniforms["translucent"].data; + } + + public set soft(v: number) { + this.renderShader.setUniformFloat("soft", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("soft", v); + } + + public get soft(): number { + return this.renderShader.uniforms["soft"].data; + } + + public set specular(v: number) { + this.renderShader.setUniformFloat("specular", v); + let shadowShader = this.renderShader.getPassShader(RendererType.SHADOW); + shadowShader.renderShader.setUniformFloat("specular", v); + } + + public get specular(): number { + return this.renderShader.uniforms["specular"].data; + } +} \ No newline at end of file diff --git a/packages/effect/grass/shader/GrassBaseShader.ts b/packages/effect/grass/shader/GrassBaseShader.ts new file mode 100644 index 00000000..b3490c1b --- /dev/null +++ b/packages/effect/grass/shader/GrassBaseShader.ts @@ -0,0 +1,51 @@ +export let GrassBaseShader = /*wgsl*/ ` + #include "GlobalUniform" + #include "ColorPassFragmentOutput" + #include "ShadingInput" + + struct FragmentVarying { + @location(0) fragUV0: vec2, + @location(1) fragUV1: vec2, + @location(2) viewPosition: vec4, + @location(3) fragPosition: vec4, + @location(4) vWorldPos: vec4, + @location(5) vWorldNormal: vec3, + @location(6) vColor: vec4, + + #if USE_SHADOWMAPING + @location(7) vShadowPos: vec4, + #endif + + #if USE_TANGENT + @location(8) TANGENT: vec4, + #endif + + @builtin(front_facing) face: bool, + @builtin(position) fragCoord : vec4 + }; + + var ORI_FragmentOutput: FragmentOutput; + var ORI_VertexVarying: FragmentVarying; + var ORI_ShadingInput: ShadingInput; + + @fragment + fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { + ORI_VertexVarying = vertex_varying; + ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + #if USE_WORLDPOS + ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; + #endif + + #if USEGBUFFER + ORI_FragmentOutput.worldNormal = vec4(ORI_ShadingInput.Normal.rgb ,1.0); + ORI_FragmentOutput.material = vec4(0.0,1.0,0.0,0.0); + #endif + + frag(); + + #if USE_DEBUG + debugFragmentOut(); + #endif + + return ORI_FragmentOutput ; +` \ No newline at end of file diff --git a/packages/effect/grass/shader/GrassCastShadowShader.ts b/packages/effect/grass/shader/GrassCastShadowShader.ts new file mode 100644 index 00000000..57eeb1db --- /dev/null +++ b/packages/effect/grass/shader/GrassCastShadowShader.ts @@ -0,0 +1,109 @@ +export let GrassCastShadowShader = /* wgsl */` + #include "WorldMatrixUniform" + #include "GrassVertexAttributeShader" + #include "FragmentVarying" + #include "GlobalUniform" + #include "Inline_vert" + #include "MatrixShader" + + struct MaterialUniform { + baseColor: vec4, + grassBottomColor: vec4, + grassTopColor: vec4, + windBound: vec4, + windDirection: vec2, + windPower: f32, + windSpeed: f32, + translucent: f32, + grassHeight: f32, + curvature: f32, + roughness: f32, + soft: f32, + specular: f32, + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var windMapSampler: sampler; + @group(1) @binding(auto) + var windMap: texture_2d; + + const DEGREES_TO_RADIANS : f32 = 3.1415926 / 180.0 ; + + @vertex + fn VertMain( vertex:VertexAttributes ) -> VertexOutput { + var vertexData = vertex ; + vertex_inline(vertexData); + vert(vertexData); + return ORI_VertexOut ; + } + + fn transformVertex(position:vec3,normal:vec3,vertex:VertexAttributes) -> TransformVertex { + var transformVertex:TransformVertex; + let windDirection = normalize( vec3(materialUniform.windDirection.x,0.0,materialUniform.windDirection.y)) ; + let windPower = materialUniform.windPower ; + let localMatrix = models.matrix[i32(vertex.vIndex)] ; + let grassPivot = localMatrix[3].xyz ; + let bound = materialUniform.windBound ; + + let time = TIME.y * 0.001 ; + let cycleTime = sin(time) ; + + //sampler wind noise texture by vertex shader + let size = textureDimensions(windMap); + let cyclePos = ( abs(grassPivot.xz + windDirection.xz * time * 100.0 * materialUniform.windSpeed ) % vec2(size) ) ; + var windNoise = textureLoad(windMap,vec2( cyclePos ),0); + + // weights0 x,y,z is grass blend dir , w is curvature random + let weights = vertex.weights0 ; + var speed = windDirection.xz * ( windNoise.rg ) ; + + var roat = localMatrix ; + roat[3].x = 0.0 ; + roat[3].y = 0.0 ; + roat[3].z = 0.0 ; + var finalMatrix:mat4x4 = buildMatrix4x4() ; + var uv = vertex.uv ; + let weight = ( 1.0 - uv.y ) ; + let limitAngle = 90.0 / 8.0 * DEGREES_TO_RADIANS + PI * 0.35 ; + // if(uv.y < 1.0 ){ + for (var index:i32 = 1; index <= 5 ; index+=1) { + let bios = f32(index) / 5.0 ; + if(weight >= bios){ + let rx = weights.x * weights.w + clamp(speed.y * windPower * pow(weight,materialUniform.curvature),-1.0,1.0) ; + let rz = weights.z * weights.w + clamp(-speed.x * windPower * pow(weight,materialUniform.curvature),-1.0,1.0) ; + + var rot = buildRotateXYZMat4(rx,0.0,rz,0.0,materialUniform.grassHeight*bios,0.0); + finalMatrix *= rot ; + } + } + // } + + finalMatrix *= roat; + //create grass pivot matrix + var translate = bulidTranslateMat4(grassPivot.x,grassPivot.y,grassPivot.z); + transformVertex.position = ( translate * finalMatrix * vec4(position,1.0)).xyz; + + //generate vertex normal + //build vertex normal matrix + let nMat = mat3x3(finalMatrix[0].xyz,finalMatrix[1].xyz,finalMatrix[2].xyz) ; + ORI_NORMALMATRIX = transpose(inverse( nMat )); + transformVertex.normal = ORI_NORMALMATRIX * normal; + + return transformVertex ; + } + + fn vert(inputData:VertexAttributes) -> VertexOutput { + let input = inputData ; + ORI_Vert(input) ; + return ORI_VertexOut ; + } +` + diff --git a/packages/effect/grass/shader/GrassShader.ts b/packages/effect/grass/shader/GrassShader.ts new file mode 100644 index 00000000..36f6bf5d --- /dev/null +++ b/packages/effect/grass/shader/GrassShader.ts @@ -0,0 +1,166 @@ +export let GrassShader = /* wgsl */` + #include "WorldMatrixUniform" + #include "GrassVertexAttributeShader" + #include "GlobalUniform" + #include "Inline_vert" + #include "BRDF_frag" + + #include "Common_frag" + #include "UnLit_frag" + #include "MatrixShader" + #include "BrdfLut_frag" + #include "LightingFunction_frag" + + struct MaterialUniform { + baseColor: vec4, + grassBottomColor: vec4, + grassTopColor: vec4, + materialF0: vec4, + windBound: vec4, + windDirection: vec2, + windPower: f32, + windSpeed: f32, + translucent: f32, + grassHeight: f32, + curvature: f32, + roughness: f32, + soft: f32, + specular: f32, + }; + + @group(2) @binding(0) + var materialUniform: MaterialUniform; + + @group(1) @binding(auto) + var baseMapSampler: sampler; + @group(1) @binding(auto) + var baseMap: texture_2d; + + @group(1) @binding(auto) + var windMapSampler: sampler; + @group(1) @binding(auto) + var windMap: texture_2d; + + const DEGREES_TO_RADIANS : f32 = 3.1415926 / 180.0 ; + + @vertex + fn VertMain( vertex:VertexAttributes ) -> VertexOutput { + var vertexData = vertex ; + vertex_inline(vertexData); + vert(vertexData); + return ORI_VertexOut ; + } + + fn transformVertex(position:vec3,normal:vec3,vertex:VertexAttributes) -> TransformVertex { + var transformVertex:TransformVertex; + let windDirection = normalize( vec3(materialUniform.windDirection.x,0.0,materialUniform.windDirection.y)) ; + let windPower = materialUniform.windPower ; + let localMatrix = models.matrix[i32(vertex.vIndex)] ; + let grassPivot = localMatrix[3].xyz ; + let bound = materialUniform.windBound ; + + let time = TIME.y * 0.001 ; + let cycleTime = sin(time) ; + + //sampler wind noise texture by vertex shader + let size = textureDimensions(windMap); + let cyclePos = ( abs(grassPivot.xz + windDirection.xz * time * 100.0 * materialUniform.windSpeed ) % vec2(size) ) ; + var windNoise = textureLoad(windMap,vec2( cyclePos ),0); + + // weights0 x,y,z is grass blend dir , w is curvature random + let weights = vertex.weights0 ; + var speed = windDirection.xz * ( windNoise.rg ) ; + + var roat = localMatrix ; + roat[3].x = 0.0 ; + roat[3].y = 0.0 ; + roat[3].z = 0.0 ; + var finalMatrix:mat4x4 = buildMatrix4x4() ; + var uv = vertex.uv ; + let weight = ( 1.0 - uv.y ) ; + let limitAngle = 90.0 / 8.0 * DEGREES_TO_RADIANS + PI * 0.35 ; + // if(uv.y < 1.0 ){ + for (var index:i32 = 1; index <= 5 ; index+=1) { + let bios = f32(index) / 5.0 ; + if(weight >= bios){ + let rx = weights.x * weights.w + clamp(speed.y * windPower * pow(weight,materialUniform.curvature),-1.0,1.0) ; + let rz = weights.z * weights.w + clamp(-speed.x * windPower * pow(weight,materialUniform.curvature),-1.0,1.0) ; + + var rot = buildRotateXYZMat4(rx,0.0,rz,0.0,materialUniform.grassHeight*bios,0.0); + finalMatrix *= rot ; + } + } + // } + + finalMatrix *= roat; + //create grass pivot matrix + var translate = bulidTranslateMat4(grassPivot.x,grassPivot.y,grassPivot.z); + transformVertex.position = ( translate * finalMatrix * vec4(position,1.0)).xyz; + + //generate vertex normal + //build vertex normal matrix + let nMat = mat3x3(finalMatrix[0].xyz,finalMatrix[1].xyz,finalMatrix[2].xyz) ; + ORI_NORMALMATRIX = transpose(inverse( nMat )); + transformVertex.normal = ORI_NORMALMATRIX * normal; + + return transformVertex ; + } + + fn vert(inputData:VertexAttributes) -> VertexOutput { + let input = inputData ; + ORI_Vert(input) ; + return ORI_VertexOut ; + } + + fn frag(){ + + var normal = ORI_VertexVarying.vWorldNormal ; + if(!ORI_VertexVarying.face){ + normal = -normal ; + } + normal = normalize(normal); + + useShadow(); + + var uv = ORI_VertexVarying.fragUV0 ; + + let color = textureSampleLevel(baseMap,baseMapSampler,uv,0.0) ; + + let discardValue = 0.25 ; + + if(color.w < 0.3){ + discard ; + } + + //generate view directtion + let viewDir = normalize(globalUniform.CameraPos.xyz - ORI_VertexVarying.vWorldPos.xyz) ; + + //get main light at first lightBuffer + let sunLight = lightBuffer[0] ; + let sunDir = sunLight.direction.xyz ; + // let H = normalize(viewDir.xyz + sunDir); + let R = 2.0 * dot( viewDir , normal ) * normal - viewDir ; + // let NoH = max(dot(normal,H),0.0); + let reflectDir = reflect(sunDir, normal); + let NoV = max(dot(normal,viewDir),0.0); + + var mainLightColor:vec3 = sunLight.intensity / LUMEN * sunLight.lightColor.rgb ; + let att = clamp(dot(-sunDir,normal) * 0.5 + 0.5 ,0.0,1.0) ;// + materialUniform.translucent ; + + let grassColor = mix(materialUniform.grassBottomColor,materialUniform.grassTopColor * att * vec4(mainLightColor,1.0) , 1.0 - uv.y ); + + var roughness = materialUniform.roughness ; + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + var irradiance = LinearToGammaSpace(globalUniform.skyExposure * textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + let specular = vec3( pow(max(dot(viewDir, reflectDir), 0.0), (1.0 - roughness + 0.001) * 200.0 ) ) * mainLightColor * materialUniform.specular; + + var diffuse = color.rgb / PI * grassColor.rgb * shadowStrut.directShadowVisibility[0] ; + var finalColor = diffuse + specular + irradiance * grassColor.rgb * sunLight.quadratic;//+ backColor; + + ORI_ShadingInput.BaseColor = vec4(finalColor.rgb,1.0) ; + UnLit(); + } + + +` + diff --git a/packages/effect/grass/shader/GrassVertexAttributeShader.ts b/packages/effect/grass/shader/GrassVertexAttributeShader.ts new file mode 100644 index 00000000..61269e7e --- /dev/null +++ b/packages/effect/grass/shader/GrassVertexAttributeShader.ts @@ -0,0 +1,70 @@ + +export let GrassVertexAttributeShader: string = /*wgsl*/ ` + #include "WorldMatrixUniform" + struct VertexAttributes{ + @builtin(instance_index) index : u32, + + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) TEXCOORD_1: vec2, + @location(4) vIndex: f32, + @location(5) weights0: vec4, + } + + struct VertexOutput { + @location(0) varying_UV0: vec2, + @location(1) varying_UV1: vec2, + @location(2) varying_ViewPos: vec4, + @location(3) varying_Clip: vec4, + @location(4) varying_WPos: vec4, + @location(5) varying_WNormal: vec3, + @location(6) varying_Color: vec4, + #if USE_SHADOWMAPING + @location(7) varying_ShadowPos: vec4, + #endif + @builtin(position) member: vec4 + }; + + struct TransformVertex{ + position:vec3, + normal:vec3, + } + + var ORI_VertexOut: VertexOutput ; + var worldMatrix: mat4x4 ; + + fn ORI_Vert(vertex:VertexAttributes){ + var vertexPosition = vertex.position; + var vertexNormal = vec3(0.0,0.0,-1.0); + + #if USE_TANGENT + ORI_VertexOut.varying_Tangent = vertex.TANGENT ; + #endif + + worldMatrix = ORI_MATRIX_M ; + + let nMat = mat3x3(ORI_MATRIX_M[0].xyz,ORI_MATRIX_M[1].xyz,ORI_MATRIX_M[2].xyz) ; + ORI_NORMALMATRIX = transpose(inverse( nMat )); + + var worldPos = (ORI_MATRIX_M * vec4(vertexPosition.xyz, 1.0)); + + #if TRANSFORMVERTEX + var transformVertex = transformVertex(worldPos.xyz,vertexNormal,vertex); + worldPos = vec4(transformVertex.position ,worldPos.w); + vertexNormal = transformVertex.normal ; + #endif + + var viewPosition = ORI_MATRIX_V * worldPos; + var clipPosition = ORI_MATRIX_P * viewPosition ; + + + ORI_VertexOut.varying_UV0 = vertex.uv.xy ; + ORI_VertexOut.varying_UV1 = vertex.TEXCOORD_1.xy; + ORI_VertexOut.varying_ViewPos = viewPosition / viewPosition.w; + ORI_VertexOut.varying_Clip = clipPosition; + ORI_VertexOut.varying_WPos = worldPos; + ORI_VertexOut.varying_WNormal = normalize( vertexNormal.xyz); + ORI_VertexOut.member = clipPosition ; + } +` \ No newline at end of file diff --git a/packages/effect/index.ts b/packages/effect/index.ts new file mode 100644 index 00000000..39a2fef9 --- /dev/null +++ b/packages/effect/index.ts @@ -0,0 +1,5 @@ +export * from "./grass/GrassNode"; +export * from "./grass/component/GrassComponent"; +export * from "./grass/geometry/GrassGeometry"; +export * from "./grass/material/GrassMaterial"; +export * from "./terrain/geometry/TerrainGeometry"; diff --git a/packages/effect/package.json b/packages/effect/package.json new file mode 100644 index 00000000..2c6a073d --- /dev/null +++ b/packages/effect/package.json @@ -0,0 +1,24 @@ +{ + "name": "@orillusion/effect", + "version": "0.1.0", + "author": "Orillusion", + "description": "Orillusion effect Effects", + "main": "./dist/effect.umd.js", + "module": "./dist/effect.es.js", + "module:dev": "./index.ts", + "types": "./dist/index.d.ts", + "files": ["dist"], + "scripts": { + "build": "vite build && npm run build:types && npm run build:clean", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.json", + "build:clean": "mv dist/packages/effect/* dist && rm -rf dist/src && rm -rf dist/packages" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/Orillusion/orillusion.git" + }, + "dependencies": { + "@orillusion/core": "^0.6.3" + } +} diff --git a/packages/effect/terrain/geometry/TerrainGeometry.ts b/packages/effect/terrain/geometry/TerrainGeometry.ts new file mode 100644 index 00000000..6cb29cd7 --- /dev/null +++ b/packages/effect/terrain/geometry/TerrainGeometry.ts @@ -0,0 +1,66 @@ +import { BitmapTexture2D, Plane, PlaneGeometry, Texture, Vector3, VertexAttributeName } from "@orillusion/core" + +export class TerrainGeometry extends PlaneGeometry { + + private _heightData: number[][]; + private _greenList: Vector3[]; + + + constructor(width: number, height: number, segmentW: number = 199, segmentH: number = 199) { + super(width, height, segmentW, segmentH, Vector3.Y_AXIS); + } + + public setHeight(texture: BitmapTexture2D, height: number) { + var offscreen = new OffscreenCanvas(texture.width, texture.height); + let context = offscreen.getContext(`2d`); + context.drawImage(texture.sourceImageData as ImageBitmap, 0, 0); + + let posAttrData = this.getAttribute(VertexAttributeName.position); + let pixelData = context.getImageData(0, 0, texture.width, texture.height); + + this._greenList = []; + + let tw = this.segmentW + 1; + let th = this.segmentH + 1; + for (let ppy = 0; ppy < this.segmentH; ppy++) { + for (let ppx = 0; ppx < this.segmentW; ppx++) { + let px = Math.floor(ppx / tw * texture.width); + let py = Math.floor(ppy / th * texture.height); + + let index = py * texture.width + px; + let r = pixelData.data[index * 4]; + + // if (r < 200 && g > 50 && b < 200) { + // this._greenList.push(new Vector3(ppx, 0, ppy)); + // } + + let sc = 0.05; + if (r > 45 && r < 150) { + this._greenList.push(new Vector3(ppx, 0, ppy)); + } + + let posIndex = tw * ppy + ppx; + let hd = r / 256 * height; + posAttrData.data[posIndex * 3 + 1] = hd; + + this._heightData ||= []; + this._heightData[ppy] ||= []; + this._heightData[ppy][ppx] = hd; + } + } + + // position attr need to be upload + this.vertexBuffer.upload(VertexAttributeName.position, posAttrData); + + //update normals + this.computeNormals(); + } + + public get heightData(): number[][] { + return this._heightData; + } + + public get greenData(): Vector3[] { + return this._greenList; + } +} \ No newline at end of file diff --git a/packages/effect/tsconfig.json b/packages/effect/tsconfig.json new file mode 100644 index 00000000..07928127 --- /dev/null +++ b/packages/effect/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "sourceMap": false, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client", "@webgpu/types"], + // for build + // "noEmit": true, + "declaration": true, + "declarationDir": "dist", + "outDir": "dist", + "skipLibCheck": true, + "noImplicitAny": false, + "noUnusedLocals": false, + "noUnusedParameters":false, + "noImplicitReturns": false, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "strict": false, + "paths": { + "@orillusion/core": ["../../src"], + } + } +} \ No newline at end of file diff --git a/packages/uiTool/package.json b/packages/uiTool/package.json new file mode 100644 index 00000000..67e65595 --- /dev/null +++ b/packages/uiTool/package.json @@ -0,0 +1,36 @@ +{ + "name": "@orillusion/uitool", + "version": "0.1.7", + "author": "Orillusion", + "description": "Orillusion ui tool", + "main": "./dist/uitool.umd.js", + "module": "./dist/uitool.es.js", + "types": "./dist/UITool.d.ts", + "files": [ + "dist", + "tsconfig.json", + "tsconfig.node.json" + ], + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", + "build:publish": "npm run build && npm run build:types && npm publish", + "preview": "vite preview" + }, + "devDependencies": { + "@types/node": "^18.15.11", + "@vitejs/plugin-vue": "^4.1.0", + "element-plus": "^2.3.1", + "nanoid": "^4.0.2", + "typescript": "^4.9.3", + "unplugin-auto-import": "^0.15.3", + "unplugin-vue-components": "^0.24.1", + "vite": "^4.2.0", + "vite-plugin-css-injected-by-js": "^3.1.0", + "vue": "^3.2.47", + "vue-tsc": "^1.2.0", + "@orillusion/core": "^0.6.2" + } +} diff --git a/public b/public index e8a37300..1e9b664b 160000 --- a/public +++ b/public @@ -1 +1 @@ -Subproject commit e8a373004200c8ce340f5d886250747cb27712d2 +Subproject commit 1e9b664bf6b6fc2985cfa5608463b57eed1324e5 diff --git a/samples/animation/Sample_CurveAnimation.ts b/samples/animation/Sample_CurveAnimation.ts index 73780d9c..008de852 100644 --- a/samples/animation/Sample_CurveAnimation.ts +++ b/samples/animation/Sample_CurveAnimation.ts @@ -49,7 +49,7 @@ class Sample_AnimCurve { let directLight = this.lightObj3D.addComponent(DirectLight); directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); directLight.castShadow = true; - directLight.intensity = 10; + directLight.intensity = 30; this.scene.addChild(this.lightObj3D); //create animation curve 1 @@ -88,6 +88,7 @@ class Sample_AnimCurve { // load a gltf model this.Duck = (await Engine3D.res.loadGltf('PBR/Duck/Duck.gltf')) as Object3D; this.Duck.scaleX = this.Duck.scaleY = this.Duck.scaleZ = 0.3; + this.Duck.name = "Duck" this.scene.addChild(this.Duck); } diff --git a/samples/animation/Sample_Skeleton3.ts b/samples/animation/Sample_Skeleton3.ts index 3faf9199..e2df05b2 100644 --- a/samples/animation/Sample_Skeleton3.ts +++ b/samples/animation/Sample_Skeleton3.ts @@ -37,7 +37,6 @@ class Sample_Skeleton3 { this.view.camera = mainCamera; Engine3D.startRenderView(this.view); - sky.relativeTransform = this.lightObj3D.transform; } async initScene(scene: Scene3D) { @@ -51,7 +50,6 @@ class Sample_Skeleton3 { scene.addChild(this.character); - let animation = this.character.getComponentsInChild(SkeletonAnimationComponent)[0]; const runClip = animation.getAnimationClip("Run"); diff --git a/samples/base/Sample_UseComponent.ts b/samples/base/Sample_UseComponent.ts index 809252ca..ed7fac54 100644 --- a/samples/base/Sample_UseComponent.ts +++ b/samples/base/Sample_UseComponent.ts @@ -1,5 +1,6 @@ import { Engine3D, Scene3D, CameraUtil, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController } from "@orillusion/core"; import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { GUIUtil } from "@samples/utils/GUIUtil"; // sample use component class Sample_UseComponent { @@ -37,6 +38,23 @@ class Sample_UseComponent { GUIHelp.init(); GUIHelp.add(component, 'enable'); GUIHelp.open(); + + /******** light *******/ + { + let lightObj3D = new Object3D(); + lightObj3D.x = 0; + lightObj3D.y = 30; + lightObj3D.z = -40; + lightObj3D.rotationX = 45; + lightObj3D.rotationY = 0; + lightObj3D.rotationZ = 0; + let directLight = lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 40; + GUIUtil.renderDirLight(directLight); + scene.addChild(lightObj3D); + } } } diff --git a/samples/benchmark/Sample_SphereDraw.ts b/samples/benchmark/Sample_SphereDraw.ts new file mode 100644 index 00000000..f08aea23 --- /dev/null +++ b/samples/benchmark/Sample_SphereDraw.ts @@ -0,0 +1,125 @@ +import { GUIHelp } from '@orillusion/debug/GUIHelp'; +import { Stats } from '@orillusion/stats' +import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D, Vector3, Vector3Ex, UnLitMaterial, InstanceDrawComponent, LambertMaterial, Time, BoundingBox, Color } from '@orillusion/core'; +import { GUIUtil } from '@samples/utils/GUIUtil'; + +// simple base demo +class Sample_SphereDraw { + scene: Scene3D; + + public anim: boolean = false; + async run() { + // init engine + await Engine3D.init({ renderLoop: () => this.renderLoop() }); + // create new Scene + this.scene = new Scene3D(); + + // add performance stats + this.scene.addComponent(Stats); + + // add an Atmospheric sky enviroment + let sky = this.scene.addComponent(AtmosphericComponent); + sky.sunY = 0.6 + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); + + // add a basic camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -15, 100); + + // add a basic direct light + let lightObj = new Object3D(); + lightObj.rotationX = 45; + lightObj.rotationY = 60; + lightObj.rotationZ = 150; + let dirLight = lightObj.addComponent(DirectLight); + dirLight.lightColor = KelvinUtil.color_temperature_to_rgb(53355); + dirLight.intensity = 60; + this.scene.addChild(lightObj); + + sky.relativeTransform = dirLight.transform; + + // create a view with target this.scene and camera + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + + GUIHelp.init(); + + GUIHelp.add(this, "anim").onChange = () => { + this.anim != this.anim; + }; + + this.initScene(); + } + + + private _list: Object3D[] = []; + initScene() { + let shareGeometry = new BoxGeometry(); + let materials = [ + new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + ]; + + for (let i = 0; i < materials.length; i++) { + const element = materials[i]; + element.baseColor = Color.random(); + } + + // let material = new LitMaterial(); + + let group = new Object3D(); + this.scene.addChild(group); + // let count = 150000; + let count = 10000; + for (let i = 0; i < count; i++) { + let pos = Vector3Ex.sphere(100); + // let pos = Vector3Ex.getRandomXYZ(-2, 2); + let obj = new Object3D(); + let mr = obj.addComponent(MeshRenderer); + mr.geometry = shareGeometry; + mr.material = materials[Math.floor(Math.random() * materials.length)]; + obj.localPosition = pos; + group.addChild(obj); + this._list.push(obj); + + let d = obj.transform.worldPosition.subtract(group.transform.worldPosition); + d.normalize(); + + let sc = Math.random() * 0.5 + 0.1; + obj.transform.scaleX = sc; + obj.transform.scaleY = sc; + obj.transform.scaleZ = Math.random() * 5 + 1; + + obj.transform.forward = d; + // obj.transform.rotationX = Math.random() * 360; + // obj.transform.rotationY = Math.random() * 360; + // obj.transform.rotationZ = Math.random() * 360; + + obj["rot"] = (Math.random() * 1 - 1 * 0.5) * 2.0 * Math.random() * 20; + } + group.addComponent(InstanceDrawComponent); + group["rot"] = 1.0; + group.bound = new BoundingBox(Vector3.SAFE_MIN, Vector3.SAFE_MAX); + this._list.push(group); + } + + renderLoop() { + if (this.anim) { + this._list[this._list.length - 1].rotationY += Time.delta * 0.01; + this._list.forEach((v) => { + // v.transform.rotationY += Time.delta * 0.01 * v["rot"]; + }) + } + } +} + +new Sample_SphereDraw().run() \ No newline at end of file diff --git a/samples/benchmark/Sample_drawCall.ts b/samples/benchmark/Sample_drawCall.ts new file mode 100644 index 00000000..747832d9 --- /dev/null +++ b/samples/benchmark/Sample_drawCall.ts @@ -0,0 +1,149 @@ +import { GUIHelp } from '@orillusion/debug/GUIHelp'; +import { Stats } from '@orillusion/stats' +import { Engine3D, Scene3D, AtmosphericComponent, CameraUtil, HoverCameraController, Object3D, MeshRenderer, BoxGeometry, LitMaterial, DirectLight, KelvinUtil, View3D, Vector3, Vector3Ex, UnLitMaterial, InstanceDrawComponent, LambertMaterial, Time, BoundingBox, Color, OcclusionSystem, PostProcessingComponent, GlobalFog } from '@orillusion/core'; +import { GUIUtil } from '@samples/utils/GUIUtil'; + +// simple base demo +class Sample_drawCall { + scene: Scene3D; + public anim: boolean = false; + async run() { + // init engine + await Engine3D.init({ renderLoop: () => this.renderLoop() }); + + OcclusionSystem.enable = false; + // create new Scene + this.scene = new Scene3D(); + + // add performance stats + this.scene.addComponent(Stats); + + // add an Atmospheric sky enviroment + let sky = this.scene.addComponent(AtmosphericComponent); + sky.sunY = 0.6 + + // init camera3D + let mainCamera = CameraUtil.createCamera3D(null, this.scene); + mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0); + + // add a basic camera controller + let hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController); + hoverCameraController.setCamera(15, -15, 100); + + // add a basic direct light + let lightObj = new Object3D(); + lightObj.rotationX = 45; + lightObj.rotationY = 60; + lightObj.rotationZ = 150; + let dirLight = lightObj.addComponent(DirectLight); + dirLight.lightColor = KelvinUtil.color_temperature_to_rgb(5500); + dirLight.intensity = 100; + dirLight.indirect = 1; + this.scene.addChild(lightObj); + + sky.relativeTransform = dirLight.transform; + + // create a view with target this.scene and camera + let view = new View3D(); + view.scene = this.scene; + view.camera = mainCamera; + + // start render + Engine3D.startRenderView(view); + GUIHelp.init(); + + // let post = view.scene.addComponent(PostProcessingComponent); + // let fog = post.addPost(GlobalFog); + // fog.fogColor = new Color(136 / 255, 215 / 255, 236 / 255, 1); + // fog.start = 0; + // fog.overrideSkyFactor = 0.0764; + // fog.ins = 1; + // fog.falloff = 0.626; + // fog.scatteringExponent = 3; + // fog.dirHeightLine = 10; + // GUIUtil.renderGlobalFog(fog); + + GUIHelp.add(this, "anim").onChange = () => { + this.anim != this.anim; + }; + + this.initScene(); + } + + + private _list: Object3D[] = []; + private _rotList: number[] = []; + initScene() { + let shareGeometry = new BoxGeometry(); + // let material = new UnLitMaterial(); + let materials = [ + // new LitMaterial(), + new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + // new LambertMaterial(), + ]; + + for (let i = 0; i < materials.length; i++) { + const element = materials[i]; + // element.metallic = 0.97; + // element.roughness = 0.15; + element.baseColor = new Color().hexToRGB(Color.GOLD); + } + + // let material = new LitMaterial(); + + let group = new Object3D(); + let count = 10000; + // let count = 70000; + for (let i = 0; i < count; i++) { + let pos = Vector3Ex.sphereXYZ(50, 100, 100, 10, 100); + // let pos = Vector3Ex.getRandomXYZ(-2, 2); + let obj = new Object3D(); + let mr = obj.addComponent(MeshRenderer); + mr.geometry = shareGeometry; + mr.material = materials[Math.floor(Math.random() * materials.length)]; + obj.localPosition = pos; + group.addChild(obj); + this._list.push(obj); + + obj.transform.scaleX = Math.random() * 2 + 0.2; + obj.transform.scaleY = Math.random() * 2 + 0.2; + obj.transform.scaleZ = Math.random() * 2 + 0.2; + + obj.transform.rotationX = Math.random() * 360; + obj.transform.rotationY = Math.random() * 360; + obj.transform.rotationZ = Math.random() * 360; + + this._rotList.push((Math.random() * 1 - 1 * 0.5) * 2.0 * Math.random() * 100); + obj.transform.rotatingY = 16 * 0.01 * this._rotList[i]; + } + + // group.addComponent(InstanceDrawComponent); + this._rotList.push(1.0); + group.transform.rotatingY = 16 * 0.01 * 1; + + group.bound = new BoundingBox(Vector3.SAFE_MIN, Vector3.SAFE_MAX); + this._list.push(group); + this.scene.addChild(group); + } + + renderLoop() { + if (this.anim) { + let i = 0; + for (let i = 0; i < this._list.length; i++) { + const element = this._list[i]; + // element.transform.rotationY += Time.delta * 0.01 * this._rotList[i]; + element.transform._localRot.y += Time.delta * 0.01 * this._rotList[i]; + element.transform._localChange = true; + } + } + } +} + +new Sample_drawCall().run() \ No newline at end of file diff --git a/samples/ext/Sample_Grass.ts b/samples/ext/Sample_Grass.ts new file mode 100644 index 00000000..e14988d2 --- /dev/null +++ b/samples/ext/Sample_Grass.ts @@ -0,0 +1,177 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, HoverCameraController, Object3D, DirectLight, KelvinUtil, PlaneGeometry, VertexAttributeName, LitMaterial, MeshRenderer, Vector4, Vector3, Matrix3, PostProcessingComponent, TAAPost, BitmapTexture2D, GlobalFog, Color } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; +import { GrassComponent, TerrainGeometry } from "@orillusion/effect"; + +// An sample of custom vertex attribute of geometry +class Sample_Grass { + view: View3D; + post: PostProcessingComponent; + async run() { + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.updateFrameRate = 1; + Engine3D.setting.shadow.shadowBias = 0.0003; + Engine3D.setting.shadow.shadowBound = 500; + Engine3D.setting.shadow.shadowSize = 1024; + // Engine3D.setting.render.zPrePass = true; + + GUIHelp.init(); + + await Engine3D.init(); + this.view = new View3D(); + this.view.scene = new Scene3D(); + this.view.scene.addComponent(AtmosphericComponent); + + this.view.camera = CameraUtil.createCamera3DObject(this.view.scene); + this.view.camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + this.view.camera.object3D.z = -15; + this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 500); + + Engine3D.startRenderView(this.view); + + this.post = this.view.scene.addComponent(PostProcessingComponent); + let fog = this.post.addPost(GlobalFog); + fog.fogColor = new Color(136 / 255, 215 / 255, 236 / 255, 1); + fog.start = 0; + fog.overrideSkyFactor = 0.0764; + fog.ins = 1; + fog.falloff = 0.626; + fog.scatteringExponent = 3; + fog.dirHeightLine = 10; + // post.addPost(TAAPost); + + this.createScene(this.view.scene); + } + + private async createScene(scene: Scene3D) { + //bitmap + let bitmapTexture = await Engine3D.res.loadTexture('terrain/test01/bitmap.png'); + let heightTexture = await Engine3D.res.loadTexture('terrain/test01/height.png'); + let grassTexture = await Engine3D.res.loadTexture('terrain/grass/GrassThick.png'); + let gustNoiseTexture = await Engine3D.res.loadTexture('terrain/grass/displ_noise_curl_1.png'); + let sunObj = new Object3D(); + let sunLight = sunObj.addComponent(DirectLight); + sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553); + sunLight.castShadow = true; + sunLight.intensity = 49; + sunObj.transform.rotationX = 50; + sunObj.transform.rotationY = 50; + GUIUtil.renderDirLight(sunLight); + scene.addChild(sunObj); + + let terrainSize = 1000; + let size = 1000; + let grassCount = 6795; + // let grassCount = 10; + let des = 1; + let space = 2; + let terrainGeometry: TerrainGeometry; + { + let mat = new LitMaterial(); + terrainGeometry = new TerrainGeometry(terrainSize, terrainSize); + terrainGeometry.setHeight(heightTexture as BitmapTexture2D, 100); + let floor = new Object3D(); + let mr = floor.addComponent(MeshRenderer); + mr.geometry = terrainGeometry; + mat.baseMap = bitmapTexture; + mr.material = mat; + scene.addChild(floor); + } + + let grassCom: GrassComponent; + { + let grass = new Object3D(); + grassCom = grass.addComponent(GrassComponent); + grassCom.setGrassTexture(Engine3D.res.whiteTexture); + // grassCom.setGrassTexture(grassTexture); + grassCom.setWindNoiseTexture(gustNoiseTexture); + grassCom.setGrass(18, 1, 5, 1, grassCount); + + let tsw = terrainSize / terrainGeometry.segmentW; + let tsh = terrainSize / terrainGeometry.segmentH; + let index = 0; + terrainGeometry.greenData.forEach((data) => { + for (let d = 0; d < des; d++) { + let node = grassCom.nodes[index++]; + if (node) { + let px = data.x * tsw - terrainSize * 0.5 + Math.random() * space - space * 0.5; + let pz = data.z * tsh - terrainSize * 0.5 + Math.random() * space - space * 0.5; + let pos = new Vector3(px, 0, pz); + + let tw = terrainGeometry.segmentW; + let th = terrainGeometry.segmentH; + let tx = Math.floor(((pos.x + size * 0.5) / size) * (terrainGeometry.segmentW)); + let tz = Math.floor(((pos.z + size * 0.5) / size) * (terrainGeometry.segmentH)); + + if (terrainGeometry.heightData.length > tz && terrainGeometry.heightData[tz].length > tx) { + pos.y = terrainGeometry.heightData[tz][tx]; + } + + let gassSize = 0.8 + let scale = (Math.random() * 0.75 + 0.25) * gassSize; + node.localPosition = pos; + node.localRotation.y = Math.random() * 360; + node.localScale = new Vector3(scale, scale, scale); + node.updateWorldMatrix(true); + } + } + }); + scene.addChild(grass); + } + + GUIHelp.addFolder("grass-wind"); + // GUIHelp.add(grassCom.grassMaterial.windBound, "x", -terrainSize * 0.5, terrainSize * 0.5, 0.0001).onChange((v) => { + // let bound = grassCom.grassMaterial.windBound; + // bound.x = v; + // grassCom.grassMaterial.windBound = bound; + // }); + // GUIHelp.add(grassCom.grassMaterial.windBound, "y", -terrainSize * 0.5, terrainSize * 0.5, 0.0001).onChange((v) => { + // let bound = grassCom.grassMaterial.windBound; + // bound.y = v; + // grassCom.grassMaterial.windBound = bound; + // }); + // GUIHelp.add(grassCom.grassMaterial.windBound, "z", 0, terrainSize, 0.0001).onChange((v) => { + // let bound = grassCom.grassMaterial.windBound; + // bound.z = v; + // grassCom.grassMaterial.windBound = bound; + // }); + // GUIHelp.add(grassCom.grassMaterial.windBound, "w", 0, terrainSize, 0.0001).onChange((v) => { + // let bound = grassCom.grassMaterial.windBound; + // bound.w = v; + // grassCom.grassMaterial.windBound = bound; + // }); + + GUIHelp.addColor(grassCom.grassMaterial, "grassBaseColor"); + GUIHelp.addColor(grassCom.grassMaterial, "grassTopColor"); + GUIHelp.add(grassCom.grassMaterial.windDirection, "x", -1.0, 1, 0.0001).onChange((v) => { + let tv = grassCom.grassMaterial.windDirection; + tv.x = v; + grassCom.grassMaterial.windDirection = tv; + }); + GUIHelp.add(grassCom.grassMaterial.windDirection, "y", -1.0, 1, 0.0001).onChange((v) => { + let tv = grassCom.grassMaterial.windDirection; + tv.y = v; + grassCom.grassMaterial.windDirection = tv; + }); + GUIHelp.add(grassCom.grassMaterial, "windPower", 0.0, 20, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "windSpeed", 0.0, 20, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "curvature", 0.0, 1, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "grassHeight", 0.0, 100, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "roughness", 0.0, 1, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "translucent", 0.0, 1, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "soft", 0.0, 10, 0.0001); + GUIHelp.add(grassCom.grassMaterial, "specular", 0.0, 10, 0.0001); + GUIHelp.endFolder(); + + GUIHelp.addFolder("shadow"); + GUIHelp.add(Engine3D.setting.shadow, "shadowBound", 0.0, 3000, 0.0001); + GUIHelp.add(Engine3D.setting.shadow, "shadowBias", 0.0, 1, 0.0001); + GUIHelp.endFolder(); + + let globalFog = this.post.getPost(GlobalFog); + // GUIUtil.renderFog(globalFog); + } + +} + +new Sample_Grass().run(); \ No newline at end of file diff --git a/samples/ext/Sample_Terrain.ts b/samples/ext/Sample_Terrain.ts new file mode 100644 index 00000000..233ed02b --- /dev/null +++ b/samples/ext/Sample_Terrain.ts @@ -0,0 +1,93 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, HoverCameraController, Object3D, DirectLight, KelvinUtil, PlaneGeometry, VertexAttributeName, LitMaterial, MeshRenderer, Vector4, Vector3, Matrix3, PostProcessingComponent, TAAPost, BitmapTexture2D, GlobalFog, Color } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; +import { GrassComponent, TerrainGeometry } from "@orillusion/effect"; + +// An sample of custom vertex attribute of geometry +class Sample_Terrain { + view: View3D; + post: PostProcessingComponent; + async run() { + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.updateFrameRate = 1; + Engine3D.setting.shadow.shadowBias = 0.0003; + Engine3D.setting.shadow.shadowBound = 500; + Engine3D.setting.shadow.shadowSize = 1024; + // Engine3D.setting.render.zPrePass = true; + + GUIHelp.init(); + + await Engine3D.init(); + this.view = new View3D(); + this.view.scene = new Scene3D(); + this.view.scene.addComponent(AtmosphericComponent); + + this.view.camera = CameraUtil.createCamera3DObject(this.view.scene); + this.view.camera.perspective(60, webGPUContext.aspect, 1, 5000.0); + this.view.camera.object3D.z = -15; + this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 500); + + Engine3D.startRenderView(this.view); + + this.post = this.view.scene.addComponent(PostProcessingComponent); + let fog = this.post.addPost(GlobalFog); + fog.start = 116; + fog.end = 0; + fog.fogHeightScale = 0.116; + fog.density = 0.094; + fog.ins = 0.1041; + fog.skyFactor = 0.35; + fog.overrideSkyFactor = 0.7; + + fog.fogColor = new Color(136 / 255, 215 / 255, 236 / 255, 1); + fog.fogHeightScale = 0.1; + fog.falloff = 0.626; + fog.scatteringExponent = 8; + fog.dirHeightLine = 6.5; + // post.addPost(TAAPost); + + this.createScene(this.view.scene); + } + + private async createScene(scene: Scene3D) { + //bitmap + let bitmapTexture = await Engine3D.res.loadTexture('terrain/test01/bitmap.png'); + let heightTexture = await Engine3D.res.loadTexture('terrain/test01/height.png'); + let grassTexture = await Engine3D.res.loadTexture('terrain/grass/GrassThick.png'); + let gustNoiseTexture = await Engine3D.res.loadTexture('terrain/grass/displ_noise_curl_1.png'); + let sunObj = new Object3D(); + let sunLight = sunObj.addComponent(DirectLight); + sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553); + sunLight.castShadow = true; + sunLight.intensity = 49; + sunObj.transform.rotationX = 50; + sunObj.transform.rotationY = 50; + GUIUtil.renderDirLight(sunLight); + scene.addChild(sunObj); + + let terrainSize = 1000; + let terrainGeometry: TerrainGeometry; + { + let mat = new LitMaterial(); + terrainGeometry = new TerrainGeometry(terrainSize, terrainSize); + terrainGeometry.setHeight(heightTexture as BitmapTexture2D, 300); + let floor = new Object3D(); + let mr = floor.addComponent(MeshRenderer); + mr.geometry = terrainGeometry; + mat.baseMap = bitmapTexture; + mr.material = mat; + scene.addChild(floor); + } + + GUIHelp.addFolder("shadow"); + GUIHelp.add(Engine3D.setting.shadow, "shadowBound", 0.0, 3000, 0.0001); + GUIHelp.add(Engine3D.setting.shadow, "shadowBias", 0.0, 1, 0.0001); + GUIHelp.endFolder(); + + let globalFog = this.post.getPost(GlobalFog); + GUIUtil.renderGlobalFog(globalFog); + } + +} + +new Sample_Terrain().run(); \ No newline at end of file diff --git a/samples/gi/Sample_GI.ts b/samples/gi/Sample_GI.ts index bc9c4be2..fb4b48de 100644 --- a/samples/gi/Sample_GI.ts +++ b/samples/gi/Sample_GI.ts @@ -55,12 +55,12 @@ class Sample_GI { let job = Engine3D.getRenderJob(exampleScene.view); await this.initScene(); this.addGIProbes(); - GUIUtil.renderAtomosphericSky(exampleScene.atmosphericSky); + // GUIUtil.renderAtomosphericSky(exampleScene.atmosphericSky); GUIUtil.renderDirLight(exampleScene.light); let postProcessing = this.scene.addComponent(PostProcessingComponent); postProcessing.addPost(TAAPost); - // postProcessing.addPost(GTAOPost); + postProcessing.addPost(GTAOPost); postProcessing.addPost(HDRBloomPost); } @@ -82,12 +82,12 @@ class Sample_GI { this.scene.addChild(floor); } - + let obj3dList: Object3D[] = []; { let greenBall = Object3DUtil.GetSingleSphere(30, 0.1, 0.8, 0.2); - this.scene.addChild(greenBall); greenBall.x = -70; greenBall.y = 40; + obj3dList.push(greenBall); } { @@ -95,7 +95,7 @@ class Sample_GI { chair.scaleX = chair.scaleY = chair.scaleZ = 100; chair.rotationZ = chair.rotationX = 130; chair.z = -120; - this.scene.addChild(chair); + obj3dList.push(chair); } { @@ -104,15 +104,18 @@ class Sample_GI { Duck.transform.y = 0; Duck.transform.x = 0; Duck.transform.z = 80; - this.scene.addChild(Duck); + obj3dList.push(Duck); } - { let car = await Engine3D.res.loadGltf('gltfs/pbrCar/pbrCar.gltf'); car.scaleX = car.scaleY = car.scaleZ = 1.5; - this.scene.addChild(car); car.x = 20; + obj3dList.push(car); + } + + for (let obj3D of obj3dList) { + this.scene.addChild(obj3D); } } } diff --git a/samples/gi/Sample_GICornellBox.ts b/samples/gi/Sample_GICornellBox.ts index cf60b3ab..7bd08ee6 100644 --- a/samples/gi/Sample_GICornellBox.ts +++ b/samples/gi/Sample_GICornellBox.ts @@ -30,8 +30,8 @@ class Sample_GICornellBox { Engine3D.setting.gi.depthSharpness = 1; Engine3D.setting.gi.autoRenderProbe = true; - Engine3D.setting.shadow.shadowBound = 50; - Engine3D.setting.shadow.shadowBias = 0.001; + Engine3D.setting.shadow.shadowBound = 80; + Engine3D.setting.shadow.shadowBias = 0.000035; Engine3D.setting.shadow.debug = true; Engine3D.setting.shadow.autoUpdate = true; @@ -53,6 +53,7 @@ class Sample_GICornellBox { param.camera.distance = 40; let exampleScene = createExampleScene(param); + exampleScene.hoverCtrl.setCamera(0, 0, 20); this.scene = exampleScene.scene; this.addGIProbes(); Engine3D.startRenderViews([exampleScene.view]); diff --git a/samples/loader/Sample_LoadGLB2.ts b/samples/loader/Sample_LoadGLB2.ts new file mode 100644 index 00000000..d513c20d --- /dev/null +++ b/samples/loader/Sample_LoadGLB2.ts @@ -0,0 +1,57 @@ +import { Engine3D, LitMaterial, MeshRenderer, Object3D, PlaneGeometry, Scene3D } from "@orillusion/core"; +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { GUI } from "@orillusion/debug/dat.gui.module"; +import { createExampleScene } from "@samples/utils/ExampleScene"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +// Sample to load glb file +export class Sample_LoadGLB2 { + scene: Scene3D; + + async run() { + await Engine3D.init(); + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.shadowBias = 0.0001; + let exampleScene = createExampleScene(); + exampleScene.atmosphericSky.displaySun = false; + exampleScene.atmosphericSky.sunRadiance = 1; + this.scene = exampleScene.scene; + + exampleScene.hoverCtrl.setCamera(-45, -45, 10); + exampleScene.light.intensity = 10; + Engine3D.startRenderView(exampleScene.view); + await this.initScene(); + + GUIHelp.init(); + GUIUtil.renderAtomosphericSky(exampleScene.atmosphericSky); + } + + async initScene() { + /******** floor *******/ + // { + // let mat = new LitMaterial(); + // mat.baseMap = Engine3D.res.whiteTexture; + // mat.roughness = 0.85; + // mat.metallic = 0.1; + // let floor = new Object3D(); + // let mr = floor.addComponent(MeshRenderer); + // mr.geometry = new PlaneGeometry(200, 200); + // mr.material = mat; + // this.scene.addChild(floor); + // } + + /******** load glb file *******/ + let model = (await Engine3D.res.loadGltf('gltfs/glb/BuildingWithCharacters.glb', { onProgress: (e) => this.onLoadProgress(e), onComplete: (e) => this.onComplete(e) })) as Object3D; + this.scene.addChild(model); + model.scaleX = model.scaleY = model.scaleZ = 0.01; + } + + onLoadProgress(e) { + console.log(e); + } + + onComplete(e) { + console.log(e); + } + +} diff --git a/samples/loader/Sample_LoadGLB3.ts b/samples/loader/Sample_LoadGLB3.ts new file mode 100644 index 00000000..24298cde --- /dev/null +++ b/samples/loader/Sample_LoadGLB3.ts @@ -0,0 +1,49 @@ +import { Engine3D, LitMaterial, MeshRenderer, Object3D, PlaneGeometry, Scene3D } from "@orillusion/core"; +import { createExampleScene } from "@samples/utils/ExampleScene"; + +// Sample to load glb file +export class Sample_LoadGLB3 { + scene: Scene3D; + + async run() { + await Engine3D.init(); + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.shadowBias = 0.0001; + let exampleScene = createExampleScene(); + this.scene = exampleScene.scene; + + exampleScene.hoverCtrl.setCamera(-45, -45, 10); + exampleScene.light.intensity = 10; + Engine3D.startRenderView(exampleScene.view); + await this.initScene(); + } + + async initScene() { + /******** floor *******/ + // { + // let mat = new LitMaterial(); + // mat.baseMap = Engine3D.res.whiteTexture; + // mat.roughness = 0.85; + // mat.metallic = 0.1; + // let floor = new Object3D(); + // let mr = floor.addComponent(MeshRenderer); + // mr.geometry = new PlaneGeometry(200, 200); + // mr.material = mat; + // this.scene.addChild(floor); + // } + + /******** load glb file *******/ + let model = (await Engine3D.res.loadGltf('gltfs/glb/modelNew.glb', { onProgress: (e) => this.onLoadProgress(e), onComplete: (e) => this.onComplete(e) })) as Object3D; + this.scene.addChild(model); + model.scaleX = model.scaleY = model.scaleZ = 0.001; + } + + onLoadProgress(e) { + console.log(e); + } + + onComplete(e) { + console.log(e); + } + +} diff --git a/samples/material/Sample_ChangeMaterial.ts b/samples/material/Sample_ChangeMaterial.ts new file mode 100644 index 00000000..d5c7da5b --- /dev/null +++ b/samples/material/Sample_ChangeMaterial.ts @@ -0,0 +1,115 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, Object3D, DirectLight, KelvinUtil, MeshRenderer, UnLitMaterial, PlaneGeometry, LitMaterial, Color, BoxGeometry } from "@orillusion/core"; +import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + + +class Sample_ChangeMaterial { + scene: Scene3D; + lightObj: Object3D; + async run() { + await Engine3D.init(); + + Engine3D.setting.material.materialChannelDebug = true; + Engine3D.setting.shadow.shadowBound = 5; + Engine3D.setting.shadow.shadowBias = 0.002; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + luminosityThreshold: 0.8, + strength: 0.86, + radius: 4, + debug: false + }; + + this.scene = new Scene3D(); + let sky = this.scene.addComponent(AtmosphericComponent); + + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, Engine3D.aspect, 0.01, 5000.0); + + camera.object3D.addComponent(HoverCameraController).setCamera(25, -25, 200); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + + await this.initScene(); + sky.relativeTransform = this.lightObj.transform; + } + + async initScene() { + /******** sky *******/ + { + this.scene.exposure = 1; + this.scene.roughness = 0.0; + } + /******** light *******/ + { + let lightObj = this.lightObj = new Object3D(); + lightObj.rotationX = 57; + lightObj.rotationY = 347; + lightObj.rotationZ = 0; + + let directLight = lightObj.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 6; + this.scene.addChild(lightObj); + } + + { + // add floor + let floor = new Object3D(); + let material = new LitMaterial(); + material.doubleSide = true; + material.baseMap = await Engine3D.res.loadTexture("textures/diffuse.jpg"); + + let renderer = floor.addComponent(MeshRenderer); + renderer.material = material; + renderer.geometry = new PlaneGeometry(200, 200, 1, 1); + + floor.y = -10; + this.scene.addChild(floor); + } + + { + let tex1 = await Engine3D.res.loadTexture("textures/cell.png"); + let tex2 = await Engine3D.res.loadTexture("textures/grid.jpg"); + let tex3 = await Engine3D.res.loadTexture("textures/KB3D_NTT_Ads_basecolor.png"); + + let mat1 = new LitMaterial(); + let mat2 = new LitMaterial(); + let mat3 = new LitMaterial(); + + mat1.baseMap = tex1; + mat2.baseMap = tex2; + mat3.baseMap = tex3; + + let obj = new Object3D(); + let mr = obj.addComponent(MeshRenderer); + mr.geometry = new BoxGeometry(100, 100, 100); + mr.material = mat1; + this.scene.addChild(obj); + + GUIHelp.init(); + GUIHelp.addButton("change-mat1", () => { + mr.material = mat1; + }); + + GUIHelp.addButton("change-mat2", () => { + mr.material = mat2; + }); + + GUIHelp.addButton("change-mat3", () => { + mr.material = mat3; + }); + } + } + +} + +new Sample_ChangeMaterial().run(); \ No newline at end of file diff --git a/samples/material/Sample_ClearCoat.ts b/samples/material/Sample_ClearCoat.ts new file mode 100644 index 00000000..7a5f0d7a --- /dev/null +++ b/samples/material/Sample_ClearCoat.ts @@ -0,0 +1,114 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Object3D, Scene3D, Engine3D, CameraUtil, HoverCameraController, View3D, AtmosphericComponent, DirectLight, KelvinUtil, MeshRenderer, LitMaterial, SphereGeometry, Color, SkyRenderer } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_ClearCoat { + lightObj3D: Object3D; + scene: Scene3D; + + async run() { + Engine3D.setting.pick.enable = true; + Engine3D.setting.pick.mode = `pixel`; + Engine3D.setting.render.debug = true; + GUIHelp.init(); + + await Engine3D.init(); + + //config settings + Engine3D.setting.shadow.shadowBound = 300; + Engine3D.setting.shadow.shadowBias = 0.0004; + Engine3D.setting.render.postProcessing.bloom = { + enable: true, + blurX: 4, + blurY: 4, + luminosityThreshold: 0.8, + strength: 0.86, + radius: 4, + debug: false + }; + + + this.scene = new Scene3D(); + let camera = CameraUtil.createCamera3DObject(this.scene); + camera.perspective(60, Engine3D.aspect, 1, 5000.0); + + + camera.object3D.addComponent(HoverCameraController).setCamera(-25, -5, 300); + + let view = new View3D(); + view.scene = this.scene; + view.camera = camera; + + Engine3D.startRenderView(view); + await this.initScene(); + + } + + async initScene() { + /******** sky *******/ + { + // let tex = await Engine3D.res.loadHDRTextureCube("hdri/T_Panorama05_HDRI.HDR"); + // let sky = this.scene.addComponent(SkyRenderer); + // sky.map = tex; + // sky.enable = true; + let sky = this.scene.getOrAddComponent(SkyRenderer); + sky.map = await Engine3D.res.loadHDRTextureCube('/hdri/sunset.hdr'); + this.scene.envMap = sky.map; + } + /******** light *******/ + { + this.lightObj3D = new Object3D(); + this.lightObj3D.rotationX = 124; + this.lightObj3D.rotationY = 327; + this.lightObj3D.rotationZ = 265.38; + let directLight = this.lightObj3D.addComponent(DirectLight); + directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355); + directLight.castShadow = true; + directLight.intensity = 43; + GUIUtil.renderDirLight(directLight); + this.scene.addChild(this.lightObj3D); + } + + { + // let model = (await Engine3D.res.loadGltf('gltfs/apple_vision_pro/scene.gltf', {})) as Object3D; + // let renderList = model.getComponentsInChild(MeshRenderer); + // for (const item of renderList) { + // let material = item.material; + // if (material instanceof LitMaterial) { + // material.metallic = 1; + // } + // } + // model.transform.scaleX = 10; + // model.transform.scaleY = 10; + // model.transform.scaleZ = 10; + // model.transform.y = -5; + + let clearCoatRoughnessTex = await Engine3D.res.loadTexture("PBR/ClearCoatTest/T_Imperfections_Wipe_Mask.PNG"); + + // this.scene.addChild(model); + let space = 50; + let geo = new SphereGeometry(15, 35, 35); + for (let i = 0; i < 10; i++) { + var obj = new Object3D(); + let mr = obj.addComponent(MeshRenderer); + mr.geometry = geo; + let mat = new LitMaterial(); + mat.baseColor = new Color(1.0, 0.0, 0.0); + mat.metallic = 0; + mat.roughness = 1; + mat.clearCoatRoughnessMap = clearCoatRoughnessTex; + // mat.clearcoatFactor = i / 10; + mat.clearcoatColor = new Color(0.0, 0.0, 0.0); + mat.clearcoatWeight = 0.65; + mat.clearcoatFactor = 1; + mat.clearcoatRoughnessFactor = i / 10; + mr.material = mat; + this.scene.addChild(obj); + + obj.x = space * i - space * 10 * 0.5; + } + } + } +} + +new Sample_ClearCoat().run(); \ No newline at end of file diff --git a/samples/physics/Sample_PhysicsCar.ts b/samples/physics/Sample_PhysicsCar.ts new file mode 100644 index 00000000..370a8ce4 --- /dev/null +++ b/samples/physics/Sample_PhysicsCar.ts @@ -0,0 +1,376 @@ +import { GUIHelp } from "@orillusion/debug/GUIHelp"; +import { Ammo, Physics, Rigidbody } from "@orillusion/physics"; +import { createExampleScene, createSceneParam } from "@samples/utils/ExampleScene"; +import { Scene3D, Object3D, LitMaterial, Engine3D, BoxGeometry, MeshRenderer, ColliderComponent, BoxColliderShape, Vector3, PlaneGeometry, Color, ComponentBase, KeyCode, KeyEvent, Quaternion, CylinderGeometry } from "@orillusion/core"; +import { GUIUtil } from "@samples/utils/GUIUtil"; + +class Sample_PhysicsCar { + private scene: Scene3D; + private materials: LitMaterial[]; + private boxGeometry: BoxGeometry; + + async run() { + Engine3D.setting.shadow.autoUpdate = true; + Engine3D.setting.shadow.updateFrameRate = 1; + Engine3D.setting.shadow.shadowSize = 2048; + Engine3D.setting.shadow.shadowBound = 150; + Engine3D.setting.shadow.shadowBias = 0.0001; + + await Physics.init(); + await Engine3D.init({ renderLoop: () => this.loop() }); + + let sceneParam = createSceneParam(); + sceneParam.camera.distance = 50; + let exampleScene = createExampleScene(sceneParam); + + GUIHelp.init(); + GUIUtil.renderDirLight(exampleScene.light, false); + + this.scene = exampleScene.scene; + await this.initScene(this.scene); + + Engine3D.startRenderView(exampleScene.view); + } + + async initScene(scene: Scene3D) { + this.createGround(); + } + + private createGround() { + let floorMat = new LitMaterial(); + floorMat.baseMap = Engine3D.res.grayTexture; + floorMat.roughness = 0.85; + floorMat.metallic = 0.01; + floorMat.envIntensity = 0.01; + + let floor = new Object3D(); + let renderer = floor.addComponent(MeshRenderer); + + renderer.castShadow = true; + renderer.receiveShadow = true; + renderer.geometry = new PlaneGeometry(200, 200, 1, 1); + renderer.material = floorMat; + + let rigidBody = floor.addComponent(Rigidbody); + rigidBody.mass = 0; + rigidBody.friction = 2; + // rigidBody.restitution = 0.1; + + let collider = floor.addComponent(ColliderComponent); + collider.shape = new BoxColliderShape(); + collider.shape.size = new Vector3(200, 1, 200); + this.scene.addChild(floor); + + class CarController extends ComponentBase { + actions = {}; + syncList = []; + keysActions = { + KeyUp: 'acceleration', + KeyDown: 'braking', + KeyLeft: 'left', + KeyRight: 'right', + }; + start() { + Engine3D.inputSystem.addEventListener(KeyEvent.KEY_UP, this.keyUp, this); + Engine3D.inputSystem.addEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); + } + + stop() { + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_UP, this.keyUp, this); + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); + } + + destroy(force) { + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_UP, this.keyUp, this); + Engine3D.inputSystem.removeEventListener(KeyEvent.KEY_DOWN, this.keyDown, this); + } + + keyUp(e) { + switch (e.keyCode) { + case KeyCode.Key_Up: + this.actions[this.keysActions['KeyUp']] = false; + break; + case KeyCode.Key_Down: + this.actions[this.keysActions['KeyDown']] = false; + break; + case KeyCode.Key_Left: + this.actions[this.keysActions['KeyLeft']] = false; + break; + case KeyCode.Key_Right: + this.actions[this.keysActions['KeyRight']] = false; + break; + } + } + + keyDown(e) { + console.log(e.keyCode); + switch (e.keyCode) { + case KeyCode.Key_Up: + this.actions[this.keysActions['KeyUp']] = true; + break; + case KeyCode.Key_Down: + this.actions[this.keysActions['KeyDown']] = true; + break; + case KeyCode.Key_Left: + this.actions[this.keysActions['KeyLeft']] = true; + break; + case KeyCode.Key_Right: + this.actions[this.keysActions['KeyRight']] = true; + break; + } + } + + onUpdate(view) { + if (Physics.isInited) { + for (let i = 0; i < this.syncList.length; i++) { + this.syncList[i](16); + } + } + } + } + + let url = "gltfs/pbrCar/pbrCar.glb" + Engine3D.res.loadGltf(url).then((e) => { + let body = e.getChildByName("Exoplanet-Rover_Exoplanet-Rover_0") as Object3D; + let scene = this.scene; + let bodyMass = 1300; + + + var chassisWidth = 2.8; + var chassisHeight = .6; + var chassisLength = 4; + var massVehicle = 800; + + var wheelAxisPositionBack = -1.3; + var wheelAxisHeightBack = .3; + var wheelRadiusBack = .4; + var wheelWidthBack = .4; + var wheelHalfTrackBack = 1.2; + + var wheelAxisFrontPosition = 1.7; + var wheelAxisHeightFront = .3; + var wheelRadiusFront = .4; + var wheelWidthFront = .4; + var wheelHalfTrackFront = 1.2; + + var friction = 1000; + var suspensionStiffness = 10.0; + var suspensionDamping = 6.3; + var suspensionCompression = 2.4; + var suspensionRestLength = 0.45; + var rollInfluence = 0.1; + + var steeringIncrement = .04; + var steeringClamp = .5; + var maxEngineForce = 2000; + var maxBreakingForce = 100; + + let bodyObj = new Object3D(); + let bodyMat = new LitMaterial(); + bodyMat.baseMap = Engine3D.res.whiteTexture; + bodyMat.normalMap = Engine3D.res.normalTexture; + bodyMat.aoMap = Engine3D.res.whiteTexture; + bodyMat.maskMap = Engine3D.res.whiteTexture; + bodyMat.emissiveMap = Engine3D.res.blackTexture; + let bodyMr = bodyObj.addComponent(MeshRenderer); + let carController = bodyObj.addComponent(CarController); + bodyMr.geometry = new BoxGeometry(chassisWidth * 0.5, chassisHeight * 0.5, chassisLength * 0.5); + bodyMr.material = bodyMat; + var geometry = new Ammo.btBoxShape(new Ammo.btVector3(chassisWidth * 0.5, chassisHeight * 0.5, chassisLength * 0.5)); + var transform = new Ammo.btTransform(); + transform.setIdentity(); + transform.setOrigin(new Ammo.btVector3(bodyObj.x, bodyObj.y, bodyObj.z)); + transform.setRotation(new Ammo.btQuaternion(0, 0, 0, 1)); + var motionState = new Ammo.btDefaultMotionState(transform); + var localInertia = new Ammo.btVector3(0, 0, 0); + geometry.calculateLocalInertia(bodyMass, localInertia); + var bodyRb = new Ammo.btRigidBody(new Ammo.btRigidBodyConstructionInfo(bodyMass, motionState, geometry, localInertia)); + bodyRb.setActivationState(4); + Physics.world.addRigidBody(bodyRb); + + body.scaleX = 0.0055; + body.scaleY = 0.0055; + body.scaleZ = 0.0055; + body.rotationX = 0; + body.y = -1.1; + body.z = -0.15 + bodyObj.addChild(body); + + bodyObj.y = 10 + scene.addChild(bodyObj); + + //raycast Vehicle + let engineForce = 0; + let vehicleSteering = 0; + let breakingForce = 0; + let tuning = new Ammo.btVehicleTuning(); + let rayCaster = new Ammo.btDefaultVehicleRaycaster(Physics.world); + let vehicle = new Ammo.btRaycastVehicle(tuning, bodyRb, rayCaster); + vehicle.setCoordinateSystem(0, 1, 2); + Physics.world.addAction(vehicle); + + //create wheels + + const FRONT_LEFT = 0; + const FRONT_RIGHT = 1; + const BACK_LEFT = 2; + const BACK_RIGHT = 3; + + let wheelMeshes = []; + let wheelDirectCS0 = new Ammo.btVector3(0, -1, 0); + let wheelAxleCS = new Ammo.btVector3(-1, 0, 0); + + let addWheel = (name, isFront, pos, radius, width, index) => { + let wheelInfo = vehicle.addWheel(pos, wheelDirectCS0, wheelAxleCS, suspensionRestLength, radius, tuning, isFront); + wheelInfo.set_m_suspensionStiffness(suspensionStiffness); + wheelInfo.set_m_wheelsDampingRelaxation(suspensionDamping); + wheelInfo.set_m_wheelsDampingCompression(suspensionCompression); + wheelInfo.set_m_frictionSlip(friction); + wheelInfo.set_m_rollInfluence(rollInfluence); + wheelMeshes[index] = this.createWheelObject(name, radius, width, e); + }; + + addWheel("ExoRov_FrontWheel_L_ExoRov_Wheels_0", true, new Ammo.btVector3(wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_LEFT); + addWheel("ExoRov_FrontWheel_R_ExoRov_Wheels_0", true, new Ammo.btVector3(-wheelHalfTrackFront, wheelAxisHeightFront, wheelAxisFrontPosition), wheelRadiusFront, wheelWidthFront, FRONT_RIGHT); + addWheel("ExoRov_BackWheel_L_ExoRov_Wheels_0", false, new Ammo.btVector3(-wheelHalfTrackBack, wheelAxisHeightBack, wheelAxisPositionBack), wheelRadiusBack, wheelWidthBack, BACK_LEFT); + addWheel("ExoRov_BackWheel_R_ExoRov_Wheels_0", false, new Ammo.btVector3(wheelHalfTrackBack, wheelAxisHeightBack, wheelAxisPositionBack), wheelRadiusBack, wheelWidthBack, BACK_RIGHT); + + let syncList = carController.syncList; + let actions = carController.actions; + function sync(dt) { + var speed = vehicle.getCurrentSpeedKmHour(); + + breakingForce = 0; + engineForce = 0; + console.log(actions); + if (actions['acceleration']) { + if (speed < -1) breakingForce = maxBreakingForce; + else engineForce = maxEngineForce; + } + if (actions[`braking`]) { + if (speed > 1) breakingForce = maxBreakingForce; + else engineForce = -maxEngineForce / 2; + } + if (actions[`left`]) { + if (vehicleSteering < steeringClamp) vehicleSteering += steeringIncrement; + } else { + if (actions[`right`]) { + if (vehicleSteering > -steeringClamp) vehicleSteering -= steeringIncrement; + } else { + if (vehicleSteering < -steeringIncrement) vehicleSteering += steeringIncrement; + else { + if (vehicleSteering > steeringIncrement) vehicleSteering -= steeringIncrement; + else { + vehicleSteering = 0; + } + } + } + } + + vehicle.applyEngineForce(engineForce, BACK_LEFT); + vehicle.applyEngineForce(engineForce, BACK_RIGHT); + + vehicle.setBrake(breakingForce / 2, FRONT_LEFT); + vehicle.setBrake(breakingForce / 2, FRONT_RIGHT); + vehicle.setBrake(breakingForce, BACK_LEFT); + vehicle.setBrake(breakingForce, BACK_RIGHT); + + vehicle.setSteeringValue(vehicleSteering, FRONT_LEFT); + vehicle.setSteeringValue(vehicleSteering, FRONT_RIGHT); + + var tm, p, q, i; + var n = vehicle.getNumWheels(); + + // console.log("getNumWheels",n); + // console.log("engineForce",engineForce); + // console.log("breakingForce",breakingForce); + + for (i = 0; i < n; i++) { + vehicle.updateWheelTransform(i, true); + tm = vehicle.getWheelTransformWS(i); + p = tm.getOrigin(); + q = tm.getRotation(); + let obj = wheelMeshes[i]; + obj.transform.x = p.x(); + obj.transform.y = p.y(); + obj.transform.z = p.z(); + let qua = Quaternion.HELP_0; + + qua.set(q.x(), q.y(), q.z(), q.w()); + obj.transform.localRotQuat = qua; + } + + tm = vehicle.getChassisWorldTransform(); + p = tm.getOrigin(); + let q2 = tm.getRotation(); + bodyObj.x = p.x(); + bodyObj.y = p.y(); + bodyObj.z = p.z(); + let qua = Quaternion.HELP_0; + // q. + qua.set(q2.x(), q2.y(), q2.z(), q2.w()); + // qua. + bodyObj.transform.localRotQuat = qua; + } + + syncList.push(sync); + + let wheelMat = new LitMaterial(); + wheelMat.baseMap = Engine3D.res.whiteTexture; + wheelMat.normalMap = Engine3D.res.normalTexture; + wheelMat.aoMap = Engine3D.res.whiteTexture; + wheelMat.maskMap = Engine3D.res.whiteTexture; + wheelMat.emissiveMap = Engine3D.res.blackTexture; + wheelMat.roughness = 0.85; + wheelMat.metallic = 0.01; + wheelMat.envIntensity = 0.01; + }) + } + + private loop() { + Physics.update(); + } + + private createWheelObject(name: string, radius: number, width: number, skin: Object3D) { + + let wheelMat = new LitMaterial(); + wheelMat.baseMap = Engine3D.res.redTexture; + wheelMat.normalMap = Engine3D.res.normalTexture; + wheelMat.aoMap = Engine3D.res.whiteTexture; + wheelMat.maskMap = Engine3D.res.whiteTexture; + wheelMat.emissiveMap = Engine3D.res.blackTexture; + // wheelMat.blendMode = BlendMode.NORMAL; + wheelMat.roughness = 0.85; + wheelMat.metallic = 0.01; + wheelMat.envIntensity = 0.01; + wheelMat.doubleSide = true; + + let wheel = new Object3D(); + // let leftFrontWheel = new Object3D(); + let mr = wheel.addComponent(MeshRenderer); + + mr.geometry = new CylinderGeometry(radius * 2, radius * 2, width, 24, 1); + mr.materials = [wheelMat, wheelMat, wheelMat]; + let q = Quaternion.HELP_0; + q.fromEulerAngles(0, 0, 90); + wheel.transform.localRotQuat = q.clone(); + var p = new Object3D(); + p.addChild(wheel); + this.scene.addChild(p); + + var wheelSkin = skin.getChildByName(name) as Object3D; + wheelSkin.scaleX = 0.005; + wheelSkin.scaleY = 0.005; + wheelSkin.scaleZ = 0.005; + wheelSkin.x = 0; + wheelSkin.y = 0; + wheelSkin.z = 0; + wheelSkin.rotationX = 0; + wheelSkin.rotationY = 0; + wheelSkin.rotationZ = 0; + p.addChild(wheelSkin); + + return p; + } +} +new Sample_PhysicsCar().run(); \ No newline at end of file diff --git a/samples/utils/GUIUtil.ts b/samples/utils/GUIUtil.ts index 52bb62bc..328beff4 100644 --- a/samples/utils/GUIUtil.ts +++ b/samples/utils/GUIUtil.ts @@ -4,6 +4,7 @@ import { UVMoveComponent } from "@samples/material/script/UVMoveComponent"; export class GUIUtil { + //render AtmosphericComponent public static renderAtomosphericSky(component: AtmosphericComponent, open: boolean = true, name?: string) { name ||= 'AtmosphericSky'; diff --git a/src/Engine3D.ts b/src/Engine3D.ts index d0dece98..34610e7d 100644 --- a/src/Engine3D.ts +++ b/src/Engine3D.ts @@ -18,6 +18,7 @@ import { ShaderUtil } from './gfx/graphics/webGpu/shader/util/ShaderUtil'; import { ComponentCollect } from './gfx/renderJob/collect/ComponentCollect'; import { ShadowLightsCollect } from './gfx/renderJob/collect/ShadowLightsCollect'; import { GUIConfig } from './components/gui/GUIConfig'; +import { Transform } from './components/Transform'; /** * Orillusion 3D Engine @@ -420,36 +421,63 @@ export class Engine3D { if (this._beforeRender) this._beforeRender(); /****** auto before update with component list *****/ - ComponentCollect.componentsBeforeUpdateList.forEach((v, k) => { - v.forEach((c, f) => { + for (const iterator of ComponentCollect.componentsBeforeUpdateList) { + let k = iterator[0]; + let v = iterator[1]; + for (const iterator2 of v) { + let f = iterator2[0]; + let c = iterator2[1]; if (f.enable) { c(k); }; - }) - }); + } + } let command = webGPUContext.device.createCommandEncoder(); - ComponentCollect.componentsComputeList.forEach((v, k) => { - v.forEach((c, f) => { + for (const iterator of ComponentCollect.componentsComputeList) { + let k = iterator[0]; + let v = iterator[1]; + for (const iterator2 of v) { + let f = iterator2[0]; + let c = iterator2[1]; if (f.enable) { c(k, command); }; - }) - }); + } + } webGPUContext.device.queue.submit([command.finish()]); + /* update all transform */ + let views = this.views; + let i = 0; + for (i = 0; i < views.length; i++) { + const view = views[i]; + Transform.updateChildTransform(view.scene.transform); + } + // for (const iterator of RenderShaderCollect.renderNodeList) { + // let nodes = iterator[1]; + // for (const node of nodes) { + // let item = node[1]; + // item.transform.updateWorldMatrix(); + // } + // } + /****** auto update global matrix share buffer write to gpu *****/ let globalMatrixBindGroup = GlobalBindGroup.modelMatrixBindGroup; globalMatrixBindGroup.writeBuffer(); /****** auto update with component list *****/ - ComponentCollect.componentsUpdateList.forEach((v, k) => { - v.forEach((c, f) => { + for (const iterator of ComponentCollect.componentsUpdateList) { + let k = iterator[0]; + let v = iterator[1]; + for (const iterator2 of v) { + let f = iterator2[0]; + let c = iterator2[1]; if (f.enable) { c(k); }; - }) - }); + } + } if (this._renderLoop) { this._renderLoop(); @@ -460,13 +488,17 @@ export class Engine3D { }); /****** auto late update with component list *****/ - ComponentCollect.componentsLateUpdateList.forEach((v, k) => { - v.forEach((c, f) => { + for (const iterator of ComponentCollect.componentsLateUpdateList) { + let k = iterator[0]; + let v = iterator[1]; + for (const iterator2 of v) { + let f = iterator2[0]; + let c = iterator2[1]; if (f.enable) { c(k); }; - }) - }); + } + } if (this._lateRender) this._lateRender(); } diff --git a/src/assets/shader/ShaderLib.ts b/src/assets/shader/ShaderLib.ts index 1fb0789e..0c382cb4 100644 --- a/src/assets/shader/ShaderLib.ts +++ b/src/assets/shader/ShaderLib.ts @@ -1,7 +1,6 @@ import { Bloom_shader } from './post/Bloom_shader'; import { ClusterDebug_frag } from './materials/program/ClusterDebug_frag'; import { CubeSky_Shader } from './sky/CubeSky_Shader'; -import { LightStructFrag } from './core/struct/LightStructFrag'; import { LightingFunction_frag } from './lighting/LightingFunction_frag'; import { MathShader } from './math/MathShader'; import { PhysicMaterialUniform_frag } from './materials/uniforms/PhysicMaterialUniform_frag'; @@ -35,6 +34,7 @@ import { BxdfDebug_frag } from './materials/program/BxdfDebug_frag'; import { Quad_depth2d_frag_wgsl, Quad_depthCube_frag_wgsl, Quad_frag_wgsl, Quad_vert_wgsl } from './quad/Quad_shader'; import { ColorUtil } from './utils/ColorUtil'; import { GenerayRandomDir } from './utils/GenerayRandomDir'; +import { ClusterLight, MatrixShader } from '../..'; /** * @internal @@ -44,6 +44,7 @@ export class ShaderLib { public static init() { ShaderLib.register('MathShader', MathShader); ShaderLib.register('FastMathShader', FastMathShader); + ShaderLib.register('MatrixShader', MatrixShader); ShaderLib.register('GlobalUniform', GlobalUniform); ShaderLib.register('WorldMatrixUniform', WorldMatrixUniform); @@ -63,7 +64,7 @@ export class ShaderLib { ShaderLib.register('FragmentVarying', FragmentVarying); ShaderLib.register('ColorPassFragmentOutput', ColorPassFragmentOutput); - ShaderLib.register('LightStruct', LightStructFrag); + ShaderLib.register('ClusterLight', ClusterLight); ShaderLib.register('ShadingInput', ShadingInput); ShaderLib.register('IESProfiles_frag', IESProfiles_frag); @@ -83,7 +84,6 @@ export class ShaderLib { ShaderLib.register('LitShader', LitShader); ShaderLib.register('PBRLItShader', PBRLItShader); - ShaderLib.register('ClusterDebug_frag', ClusterDebug_frag); ShaderLib.register('BxdfDebug_frag', BxdfDebug_frag); ShaderLib.register('GenerayRandomDir', GenerayRandomDir); diff --git a/src/assets/shader/core/base/Common_frag.ts b/src/assets/shader/core/base/Common_frag.ts index f4667a0c..14f9495b 100644 --- a/src/assets/shader/core/base/Common_frag.ts +++ b/src/assets/shader/core/base/Common_frag.ts @@ -7,10 +7,12 @@ export let Common_frag: string = /*wgsl*/ ` var ORI_FragmentOutput: FragmentOutput; var ORI_VertexVarying: FragmentVarying; var ORI_ShadingInput: ShadingInput; + var viewDir:vec3; @fragment fn FragMain( vertex_varying:FragmentVarying ) -> FragmentOutput { ORI_VertexVarying = vertex_varying; ORI_FragmentOutput.color = vec4(1.0, 0.0, 0.0, 1.0); + viewDir = normalize(globalUniform.CameraPos.xyz - ORI_VertexVarying.vWorldPos.xyz) ; #if USE_WORLDPOS ORI_FragmentOutput.worldPos = ORI_VertexVarying.vWorldPos; #endif diff --git a/src/assets/shader/core/inline/Inline_vert.ts b/src/assets/shader/core/inline/Inline_vert.ts index 734ff7ee..3a2f3ac9 100644 --- a/src/assets/shader/core/inline/Inline_vert.ts +++ b/src/assets/shader/core/inline/Inline_vert.ts @@ -12,6 +12,7 @@ export let Inline_vert: string = /*wgsl*/ ` var ORI_CAMERAMATRIX: mat4x4; var ORI_NORMALMATRIX: mat3x3; var ORI_CameraWorldDir: vec3; + var ORI_ViewDir: vec3; var TIME: vec4; var MOUSE: vec4; diff --git a/src/assets/shader/core/struct/LightStruct.ts b/src/assets/shader/core/struct/ClusterLight.ts similarity index 98% rename from src/assets/shader/core/struct/LightStruct.ts rename to src/assets/shader/core/struct/ClusterLight.ts index b497bce1..a2653020 100644 --- a/src/assets/shader/core/struct/LightStruct.ts +++ b/src/assets/shader/core/struct/ClusterLight.ts @@ -1,4 +1,4 @@ -export let LightStruct: string = /*wgsl*/ ` +export let ClusterLight: string = /*wgsl*/ ` struct LightData { index:f32, lightType:i32, diff --git a/src/assets/shader/core/struct/LightStructFrag.ts b/src/assets/shader/core/struct/LightStructFrag.ts deleted file mode 100644 index 97553296..00000000 --- a/src/assets/shader/core/struct/LightStructFrag.ts +++ /dev/null @@ -1,109 +0,0 @@ -export let LightStructFrag: string = /*wgsl*/ ` - struct LightData { - index:f32, - lightType:i32, - radius:f32, - linear:f32, - - position:vec3, - lightMatrixIndex:f32, - - direction:vec3, - quadratic:f32, - - lightColor:vec3, - intensity:f32, - - innerCutOff :f32, - outerCutOff:f32, - range :f32, - castShadow:i32, - - lightTangent:vec3, - ies:f32, - }; - - const PointLightType = 1; - const DirectLightType = 2; - const SpotLightType = 3; - - struct ClusterBox{ - minPoint:vec4, - maxPoint:vec4 - }; - - struct LightIndex - { - count:f32, - start:f32, - empty0:f32, - empty1:f32, - }; - - struct ClustersUniform{ - clusterTileX:f32, - clusterTileY:f32, - clusterTileZ:f32, - numLights:f32, - maxNumLightsPerCluster:f32, - near:f32, - far:f32, - screenWidth:f32, - screenHeight:f32, - clusterPix:f32, - }; - - @group(2) @binding(1) - var lightBuffer: array; - @group(2) @binding(2) - var clustersUniform : ClustersUniform; - @group(2) @binding(3) - var lightAssignBuffer : array; - @group(2) @binding(4) - var assignTable : array; - #if DEBUG_CLUSTER - @group(2) @binding(5) - var clusterBuffer : array; - #endif - - fn getLight( index:i32 ) -> LightData{ - let lightId = i32(lightAssignBuffer[index]); - var lightData = lightBuffer[lightId]; - return lightData ; - } - - fn linear01Depth(depth : f32) -> f32 { - return globalUniform.far * globalUniform.near / fma(depth, globalUniform.near-globalUniform.far, globalUniform.far); - } - - fn getTile(fragCoord : vec4) -> vec3 { - var coord = fragCoord ; - coord.z = linear01Depth(coord.z) ; - - let sliceScale = f32(clustersUniform.clusterTileZ) / log2(globalUniform.far / globalUniform.near); - let sliceBias = -(f32(clustersUniform.clusterTileZ) * log2(globalUniform.near) / log2(globalUniform.far / globalUniform.near)); - let zTile = u32(max(log2(coord.z) * sliceScale + sliceBias, 0.0)); - return vec3(u32(coord.x / (clustersUniform.screenWidth / f32(clustersUniform.clusterTileX))), - u32(coord.y / (clustersUniform.screenHeight / f32(clustersUniform.clusterTileY))), - zTile); - } - - fn getCluster(fragCoord : vec4) -> LightIndex { - let tile = getTile(fragCoord); - let id = tile.x + - tile.y * u32(clustersUniform.clusterTileX) + - tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); - return assignTable[id]; - } - - #if DEBUG_CLUSTER - fn getClusterIndex(fragCoord : vec4) -> u32 { - let tile = getTile(fragCoord); - let id = tile.x + - tile.y * u32(clustersUniform.clusterTileX) + - tile.z * u32(clustersUniform.clusterTileX) * u32(clustersUniform.clusterTileY); - return id; - // return 0u ; - } - #endif -` \ No newline at end of file diff --git a/src/assets/shader/glsl/Quad_glsl.ts b/src/assets/shader/glsl/Quad_glsl.ts index fac3b8af..9c017ef5 100644 --- a/src/assets/shader/glsl/Quad_glsl.ts +++ b/src/assets/shader/glsl/Quad_glsl.ts @@ -37,7 +37,7 @@ layout(set = 0, binding = 0) uniform ConstUniform { mat4 pvMatrixInv; float frame; float time; - float detail; + float delta; float shadowBias; float skyExposure; float renderPassState; diff --git a/src/assets/shader/lighting/BRDF_frag.ts b/src/assets/shader/lighting/BRDF_frag.ts index 0981f1f6..1114f811 100644 --- a/src/assets/shader/lighting/BRDF_frag.ts +++ b/src/assets/shader/lighting/BRDF_frag.ts @@ -2,7 +2,8 @@ export let BRDF_frag: string = /*wgsl*/ ` #include "Clearcoat_frag" #include "EnvMap_frag" #include "BrdfLut_frag" - + #include "ColorUtil_frag" + struct FragData { Ao: f32, Metallic: f32, @@ -67,6 +68,14 @@ export let BRDF_frag: string = /*wgsl*/ ` return level * f32(mipmapCount); } + fn IORToF0(ior:f32)->f32{ + var dc = ior - 1.0 ; + dc *= dc ; + var dt = ior + 1.0 ; + dt *= dt ; + return dc / dt ; + } + fn Fd90( NoL:f32, roughness:f32) -> f32 { return (2.0 * NoL * roughness) + 0.4; @@ -84,7 +93,7 @@ export let BRDF_frag: string = /*wgsl*/ ` fn FresnelSchlickRoughness( NoV:f32, F0:vec3, roughness:f32) -> vec3 { - return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - NoV, 5.0); + return F0 + (max(vec3(roughness), F0) - F0) * pow(1.0 - NoV, 5.0); } fn DistributionGGX( NdotH:f32 , roughness:f32 ) -> f32 @@ -169,9 +178,8 @@ export let BRDF_frag: string = /*wgsl*/ ` return (alpha2) / (PI * (NdotH2 * (alpha2 - 1.0) + 1.0) * (NdotH2 * (alpha2 - 1.0) + 1.0)); } - fn D_GGX( N:vec3, H:vec3, roughness:f32 ) -> f32 + fn D_GGX( NoH:f32, roughness:f32 ) -> f32 { - var NoH = saturate(dot(N, H)); var d = ( NoH * roughness - NoH ) * NoH + 1.0; // 2 mad return roughness / ( PI*d*d ); // 4 mul, 1 rcp } @@ -195,17 +203,18 @@ export let BRDF_frag: string = /*wgsl*/ ` return rcp( Vis_SmithV * Vis_SmithL ); } - fn simpleBRDF( albedo:vec3, N:vec3, V:vec3,L:vec3,att:f32,lightColor:vec3,roughness:f32 )-> vec3{ + fn simpleBRDF( albedo:vec3, N:vec3, V:vec3,L:vec3,att:f32,lightColor:vec3,roughness:f32 ,metallic:f32)-> vec3{ let H = normalize(V + L); let Context:BxDFContext = getContext(N,V,H,L); + let F0 = mix(vec3(materialUniform.materialF0.rgb), albedo , metallic); let D = DistributionGGX( Context.NoH , roughness); let G = GeometrySmith(Context.NoV,Context.NoL, roughness ); - let F = FresnelSchlick(Context.VoH, vec3(fragData.F0)); + let F = FresnelSchlick(Context.VoH, vec3(F0)); let specular = ( D * G * F ) / (4.0 * Context.NoV * Context.NoL + 0.001); let kS = F; var kd = 1.0 - kS ; - kd *= 1.0 - fragData.Metallic ; + kd *= 1.0 - metallic ; var diffuse = kd * (albedo.rgb / PI ) ; let ambient = specular.rgb ; @@ -225,12 +234,12 @@ export let BRDF_frag: string = /*wgsl*/ ` return mix (N, R, lerpFactor ); } - fn approximateSpecularIBL( specularColor:vec3 , roughness:f32 , R:vec3) -> vec3 { - let NoV = fragData.NoV ; + fn approximateSpecularIBL( specularColor:vec3 , roughness:f32 , R:vec3 , NoV:f32 ) -> vec3 { + let MAX_REFLECTION_LOD = i32(textureNumLevels(prefilterMap)) ; let mip = roughnessToMipmapLevel(roughness,MAX_REFLECTION_LOD); var prefilteredColor: vec3 = (textureSampleLevel(prefilterMap, prefilterMapSampler, getSpecularDominantDir(fragData.N,R,roughness) , mip ).rgb); - prefilteredColor = globalUniform.skyExposure * LinearToGammaSpace(prefilteredColor); + prefilteredColor = globalUniform.skyExposure * (prefilteredColor); var envBRDF = textureSampleLevel(brdflutMap, brdflutMapSampler, vec2(NoV, roughness) , 0.0 ) ; return prefilteredColor * (specularColor.rgb * envBRDF.x + saturate( 50.0 * specularColor.g ) * envBRDF.y) ; } @@ -266,50 +275,59 @@ export let BRDF_frag: string = /*wgsl*/ ` return f0 + (f90 - f0) * pow(1.0 - VoH,5.0); } + fn F_Schlick2( SpecularColor:vec3, VoH :f32 )-> vec3 { + var Fc = pow5( 1.0 - VoH ); + let rt = clamp(50.0 * SpecularColor.g,0.0,1.0) ; + return rt * Fc + (1.0 - Fc) * SpecularColor; + } + //https://google.github.io/filament/Filament.html materialsystem/clearcoatmodel/clearcoatparameterization - fn CoatSpecular_brdf( f:vec3, s:vec3, n:vec3 , v:vec3 , l:vec3 , att:f32 , layer :vec3) -> vec3 { + fn CoatSpecular_brdf( f:vec3, s:vec3, n:vec3 , v:vec3 , l:vec3 , att:f32 , layer :vec3 , clearcoatRoughnessFactor:f32 ) -> vec3 { let H = normalize(v + l); let VdotNc = max(dot(v,n),0.0); let LdotNc = max(dot(l,n),0.0); let NoH = max(dot(n,H),0.0); - let LoH = clamp(dot(l,H),0.0,1.0); + let LoH = saturate(dot(l, H)) ; let NoL = max(dot(n,l),0.0); let Fd = f ; let Fr = s ; - let clearcoatRoughnessFactor = clamp(materialUniform.clearcoatRoughnessFactor,0.089,1.0); - let clearCoatRoughness = clearcoatRoughnessFactor * clearcoatRoughnessFactor ; + let factor = clamp(clearcoatRoughnessFactor,0.089,1.0); + let clearCoatRoughness = factor * factor ; - let Dc = Specular_D_GGX( NoH , clearCoatRoughness ) ; - let Vc = V_Kelemen( LoH ) ; - let Fc = F_Schlick(vec3(0.04), clearCoatRoughness , pow(LoH,2.0)); + let Dc = D_GGX( NoH , factor ) ; + let Vc = V_Kelemen( LoH ) * NoL ; + let Fc = F_Schlick(vec3(0.04), 2.0 , LoH); let Frc = (Dc * Vc) * Fc ; - // return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) ;//* NoL; - return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) * ( 0.5 + NoL * 0.5 ) ; + // return layer * vec3((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc) * ( 0.5 + NoL * 0.5 ) ; + return vec3(Frc) ; } - fn approximate_coating(base:vec3 , clearColor: vec3, n:vec3 , v:vec3 , light:LightData ) -> vec3 { - let clearcoatRoughnessFactor = clamp(materialUniform.clearcoatRoughnessFactor,0.084,1.0); - var clearcoatAlpha = clearcoatRoughnessFactor * clearcoatRoughnessFactor + fragData.ClearcoatRoughness; + #if USE_CLEARCOAT + fn approximate_coating(base:vec3 , clearColor: vec3, n:vec3 , v:vec3 , light:LightData , clearcoatRoughnessFactor:f32 ) -> vec3 { + let factor = clamp(clearcoatRoughnessFactor,0.084,1.0); + var clearcoatAlpha = factor * factor + fragData.ClearcoatRoughness; // var lightColor = getHDRColor( lightCC.rgb , light.linear ) ; - var att = light.intensity ; + var att = light.intensity / LUMEN ; let l = light.direction ; let NdotV = max(dot(n,v),0.0); - let MAX_REFLECTION_LOD = i32(textureNumLevels(prefilterMap)) ; - let mip = roughnessToMipmapLevel(clearcoatAlpha,MAX_REFLECTION_LOD); + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + // let mip = roughnessToMipmapLevel(clearcoatAlpha,MAX_REFLECTION_LOD); let R = 2.0 * dot( v , n ) * n - v ; - var envIBL: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, R ,mip ).rgb) ; - envIBL = LinearToGammaSpace(envIBL); + var envIBL: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, R , MAX_REFLECTION_LOD * clearcoatRoughnessFactor ).rgb) ; + // envIBL = LinearToGammaSpace(envIBL); let clearCoat = materialUniform.clearcoatFactor ; - let f = FresnelSchlickRoughness( max(dot(n,v),0.0) , vec3(0.0) , clearcoatAlpha ) ; - let clearcoat_brdf = (f * envIBL) + CoatSpecular_brdf( clearColor , vec3( clearCoat ) , n , v , -l , att , envIBL ) ; + // let f = FresnelSchlickRoughness( max(dot(n,v),0.0) , vec3(0.0) , clearcoatAlpha ) ; + let clearcoat_brdf = CoatSpecular_brdf( vec3(0.04) , vec3( 0.04 ) , n , v , -l , att , vec3( 0.04 ) , factor ) ; // return clearcoat_brdf;+ fragData.ClearcoatRoughness - return mix(base,clearcoat_brdf,materialUniform.clearcoatWeight ) ; + return mix(base, clearcoat_brdf,materialUniform.clearcoatWeight ) ; } + #endif + ` diff --git a/src/assets/shader/lighting/BxDF_frag.ts b/src/assets/shader/lighting/BxDF_frag.ts index fced9fdb..67eb029c 100644 --- a/src/assets/shader/lighting/BxDF_frag.ts +++ b/src/assets/shader/lighting/BxDF_frag.ts @@ -17,20 +17,22 @@ export let BxDF_frag: string = /*wgsl*/ ` //ORI_ShadingInput fn initFragData() { - fragData.Albedo = ORI_ShadingInput.BaseColor ; + fragData.Albedo = ORI_ShadingInput.BaseColor * ORI_ShadingInput.BaseColor.a ; fragData.Ao = ORI_ShadingInput.AmbientOcclusion ; - fragData.Roughness = max(ORI_ShadingInput.Roughness,0.003) ; + fragData.Roughness = clamp(ORI_ShadingInput.Roughness,0.003,1.0) ; fragData.Metallic = ORI_ShadingInput.Metallic ; fragData.Emissive = ORI_ShadingInput.EmissiveColor.rgb ; fragData.N = ORI_ShadingInput.Normal; - fragData.V = normalize(globalUniform.cameraWorldMatrix[3].xyz - ORI_VertexVarying.vWorldPos.xyz) ; + let viewDir = normalize(globalUniform.CameraPos.xyz - ORI_VertexVarying.vWorldPos.xyz) ; + fragData.V = viewDir ; + // fragData.V = normalize(globalUniform.cameraWorldMatrix[3].xyz - ORI_VertexVarying.vWorldPos.xyz) ; let R = 2.0 * dot( fragData.V , fragData.N ) * fragData.N - fragData.V ; - fragData.R = R;//reflect( fragData.V , -fragData.N ) ; + fragData.R = R ;//reflect( fragData.V , fragData.N ) ; fragData.NoV = saturate(dot(fragData.N, fragData.V)) ; - fragData.F0 = mix(vec3(0.04), fragData.Albedo.rgb, fragData.Metallic); + fragData.F0 = mix(vec3(materialUniform.materialF0.rgb), fragData.Albedo.rgb, fragData.Metallic); fragData.F = computeFresnelSchlick(fragData.NoV, fragData.F0); fragData.KD = vec3(fragData.F) ; @@ -42,17 +44,26 @@ export let BxDF_frag: string = /*wgsl*/ ` fragData.DiffuseColor = fragData.Albedo.rgb * (1.0 - fragData.Metallic); fragData.SpecularColor = mix(vec3(1.0), fragData.Albedo.rgb, fragData.Metallic); - fragData.ClearcoatRoughness = 0.0 ; + fragData.ClearcoatRoughness = materialUniform.clearcoatRoughnessFactor ; #if USE_CLEARCOAT_ROUGHNESS - fragData.ClearcoatRoughness = getClearcoatRoughnees() ; + fragData.ClearcoatRoughness = getClearcoatRoughnees() * materialUniform.clearcoatRoughnessFactor; #endif } fn BxDFShading(){ initFragData(); - var color = vec3(0.0); + var irradiance = vec3(0.0) ; + #if USEGI + irradiance += getIrradiance().rgb ; + #else + let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; + // irradiance += LinearToGammaSpace(globalUniform.skyExposure * textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + irradiance += (globalUniform.skyExposure * textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); + #endif + //***********lighting-PBR part********* + var specColor = vec3(0.0) ; let lightIndex = getCluster(ORI_VertexVarying.fragCoord); let start = max(lightIndex.start, 0.0); let count = max(lightIndex.count, 0.0); @@ -63,72 +74,46 @@ export let BxDF_frag: string = /*wgsl*/ ` switch (light.lightType) { case PointLightType: { - color += pointLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + specColor += pointLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness,fragData.Metallic,light) ; } case DirectLightType: { - color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; + specColor += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness ,fragData.Metallic, light , globalUniform.shadowBias) ; } case SpotLightType: { - color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; + specColor += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness,fragData.Metallic , light ) ; } default: { } } } - - var kS = FresnelSchlickRoughness(fragData.NoV, fragData.F0, fragData.Roughness ); + //***********lighting-PBR part********* + var F = FresnelSchlickRoughness(fragData.NoV, fragData.F0, fragData.Roughness); + var kS = F; var kD = vec3(1.0) - kS; kD = kD * (1.0 - fragData.Metallic); - kD = max(vec3(0.04),kD) ; - - let MAX_REFLECTION_LOD = f32(textureNumLevels(prefilterMap)) ; - var diffuseIrradiance: vec3 = vec3(0.0);// - - #if USE_SKYLIGHT - var prefilterTex: vec3 = globalUniform.skyExposure * (textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 8.0 ).rgb); - prefilterTex = LinearToGammaSpace(prefilterTex); - var skyLight = kD * fragData.Albedo.xyz * prefilterTex; - // color += skyLight ; - #endif - - var envRef = kS * approximateSpecularIBL( fragData.SpecularColor , fragData.Roughness , fragData.R ) ;//* (materialUniform.ior - 1.0) ; - var irradiance = diffuseIrradiance ; - #if USEGI - irradiance += getIrradiance().rgb ; - #else - irradiance += LinearToGammaSpace(globalUniform.skyExposure * textureSampleLevel(prefilterMap, prefilterMapSampler, fragData.N.xyz, 0.8 * (MAX_REFLECTION_LOD) ).rgb); - #endif - - fragData.Irradiance = irradiance; + let env = materialUniform.envIntensity * approximateSpecularIBL( F , fragData.Roughness , fragData.R , fragData.NoV ) ; + //***********indirect-specular part********* + + var surfaceReduction = 1.0/(fragData.Roughness*fragData.Roughness+1.0); //Reduce the reflection coefficient of non-metallic materials + var oneMinusReflectivity = materialUniform.materialF0.a - materialUniform.materialF0.a * fragData.Metallic ; + var grazingTerm= clamp((1.0 - fragData.Roughness ) + (1.0 - oneMinusReflectivity),0.0,1.0); + var t = pow5(1.0-fragData.NoV); + var fresnelLerp = mix(fragData.F0,vec3(grazingTerm),t); //Controlling Fresnel and metallic reflections + var iblSpecularResult = surfaceReduction*env*fresnelLerp ; + //***********indirect-specular part********* + + //***********indirect-ambient part********* + var kdLast = (1.0 - F) * (1.0 - fragData.Metallic); //Dim the edges, there should be more specular reflection at the edges + var iblDiffuseResult = irradiance * kdLast * fragData.Albedo.rgb ; + //***********indirect-ambient part********* + let sunLight = lightBuffer[0] ; + var indirectResult = (iblSpecularResult + iblDiffuseResult) * fragData.Ao * sunLight.quadratic ; - var diffuseIBL = fragData.Albedo.rgb * irradiance.rgb ; - // var ambientIBL = kD * fragData.Albedo.rgb * fragData.Ao; - fragData.EnvColor = materialUniform.envIntensity * envRef ; ORI_FragmentOutput.color = vec4(0.0); - #if USE_CLEARCOAT - for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) - { - let light = getLight(i); - switch (light.lightType) { - case PointLightType: { - color += pointLighting(fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - case DirectLightType: { - color += directLighting( fragData.Albedo.rgb ,fragData.N,fragData.V,fragData.Roughness , light , globalUniform.shadowBias) ; - } - case SpotLightType: { - color += spotLighting( fragData.Albedo.rgb,ORI_VertexVarying.vWorldPos.xyz,fragData.N,fragData.V,fragData.Roughness , light ) ; - } - default: { - } - } - } - #endif - - // // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. + // Using stripped down, 'pure log', formula. Parameterized by grey points and dynamic range covered. #if USEGBUFFER var normal_rgba8unorm = (ORI_VertexVarying.vWorldNormal + 1.0) * 0.5; normal_rgba8unorm = clamp(normal_rgba8unorm, vec3(0.0), vec3(1.0)); @@ -144,19 +129,23 @@ export let BxDF_frag: string = /*wgsl*/ ` ORI_FragmentOutput.material = vec4(1.0,fragData.Roughness,fragData.Metallic,1.0); #endif - // color = pow(color.rgb,vec3(2.0)); - - color += diffuseIBL ; - // color += ambientIBL ; - color += fragData.EnvColor * fragData.Ao ; + var color = specColor + indirectResult ; color += fragData.Emissive.xyz ; - //-1 1 - // color = diffuseIBL ; - ORI_FragmentOutput.color = vec4(color.rgb,fragData.Albedo.a) ; - - // let gamma = 2.0 ; - // ORI_FragmentOutput.color = pow(ORI_FragmentOutput.color,vec4(gamma,gamma,gamma,1.0)); + var clearCoatColor = vec3(0.0); + #if USE_CLEARCOAT + let clearCoatBaseColor = vec3(1.0) * materialUniform.baseColor.rgb ; + let clearNormal = fragData.N ; + let clearcoatRoughness = fragData.ClearcoatRoughness ; + let att = sunLight.intensity / LUMEN ; + let clearCoatLayer = ClearCoat_BRDF( color , materialUniform.clearcoatColor.rgb , materialUniform.ior , clearNormal , -sunLight.direction ,-fragData.V , materialUniform.clearcoatWeight , clearcoatRoughness , att ); + color = vec3(clearCoatLayer.rgb/fragData.Albedo.a) ; + #endif + + ORI_FragmentOutput.color = vec4(LinearToGammaSpace(color.rgb),fragData.Albedo.a) ; + // ORI_FragmentOutput.color = vec4(irradiance.rgb,fragData.Albedo.a) ; } + + ` diff --git a/src/assets/shader/lighting/Irradiance_frag.ts b/src/assets/shader/lighting/Irradiance_frag.ts index 7a508b69..2d1b74e9 100644 --- a/src/assets/shader/lighting/Irradiance_frag.ts +++ b/src/assets/shader/lighting/Irradiance_frag.ts @@ -269,8 +269,7 @@ export let Irradiance_frag: string = /*wgsl*/ ` irradiance *= (1.0 / accumulatedWeights); irradiance *= irradiance; - //irradiance *= 6.2831853071795864; - irradiance *= PI; + irradiance *= 6.2831853071795864; irradiance *= irradianceData.indirectIntensity; return vec4(irradiance,1.0) ; } diff --git a/src/assets/shader/lighting/LightingFunction_frag.ts b/src/assets/shader/lighting/LightingFunction_frag.ts index ce1a08ed..58fffe88 100644 --- a/src/assets/shader/lighting/LightingFunction_frag.ts +++ b/src/assets/shader/lighting/LightingFunction_frag.ts @@ -1,6 +1,6 @@ export let LightingFunction_frag: string = /*wgsl*/ ` #include "BRDF_frag" -#include "LightStruct" +#include "ClusterLight" #include "ShadowMapping_frag" #if USE_IES_PROFILE @@ -19,7 +19,7 @@ fn calcAttenuation( d : f32 , falloffStart : f32 , falloffEnd : f32)-> f32 return saturate((falloffEnd-d) / (falloffEnd - falloffStart)); } -fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData , shadowBias:f32 ) -> vec3 { +fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , metallic:f32 , light:LightData , shadowBias:f32 ) -> vec3 { var color = vec3(0.0) ; #if USE_LIGHT var L = -normalize(light.direction.xyz) ; @@ -28,7 +28,11 @@ fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , var att = light.intensity / LUMEN ; if(light.castShadow>=0){ #if USE_SHADOWMAPING - att *= shadowStrut.directShadowVisibility[light.castShadow] ; + for (var j: i32 = 0; j < 8; j += 1) { + if(j == light.castShadow){ + att *= shadowStrut.directShadowVisibility[j] ; + } + } #endif } @@ -37,13 +41,13 @@ fn directLighting( albedo:vec3, N:vec3, V:vec3, roughness:f32 , #endif #if USE_BRDF - color = simpleBRDF(albedo,N,V,L,att,lightColor,fragData.Roughness) ; + color = simpleBRDF(albedo,N,V,L,att,lightColor,roughness,metallic) ; #endif #endif return color ; } -fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { +fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , metallic:f32 ,light:LightData ) -> vec3 { var color = vec3(0.0) ; let lightPos = light.position.xyz; var dir = lightPos.xyz - WP ; @@ -58,7 +62,13 @@ fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, rough atten *= 1.0 / max(light.radius,0.001) * light.intensity / LUMEN; if( light.castShadow >= 0 ) { - atten *= shadowStrut.pointShadows[light.castShadow] ; + #if USE_SHADOWMAPING + for (var j: i32 = 0; j < 8; j += 1) { + if(j == light.castShadow){ + atten *= shadowStrut.pointShadows[j] ; + } + } + #endif } #if USE_IES_PROFILE @@ -67,14 +77,13 @@ fn pointLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, rough var lightColor = light.lightColor.rgb ; lightColor = getHDRColor(lightColor , light.linear ) ; - // lightColor = LinearToSrgbBranchless(lightColor.rgb) ; #if USE_LAMBERT color = vec3(1.0,0.5,1.0) ; #endif #if USE_BRDF - color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,roughness,metallic)) ; #endif } return color ; @@ -84,7 +93,7 @@ fn getDistanceAtten( light:LightData , dist : f32 ) -> f32 { return 1.0 - smoothstep(0.0,light.range,dist) ; } -fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , light:LightData ) -> vec3 { +fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughness:f32 , metallic:f32 ,light:LightData ) -> vec3 { let lightPos = light.position.xyz; var dir = lightPos.xyz - WP ; let dist = length(dir) ; @@ -108,12 +117,18 @@ fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughn } }else{ - atten = 0.0 ; + atten = 0.0 ; } if( light.castShadow >= 0 ) { - atten *= shadowStrut.pointShadows[light.castShadow] ; + #if USE_SHADOWMAPING + for (var j: i32 = 0; j < 8; j += 1) { + if(j == light.castShadow){ + atten *= shadowStrut.pointShadows[j] ; + } + } + #endif } #if USE_IES_PROFILE @@ -127,7 +142,7 @@ fn spotLighting( albedo:vec3,WP:vec3, N:vec3, V:vec3, roughn #endif #if USE_BRDF - color = (simpleBRDF(albedo,N,V,L,atten,lightColor,fragData.Roughness)) ; + color = (simpleBRDF(albedo,N,V,L,atten,lightColor,roughness,metallic)) ; #endif } return color ; diff --git a/src/assets/shader/lighting/UnLit_frag.ts b/src/assets/shader/lighting/UnLit_frag.ts index f8d7e62f..64969678 100644 --- a/src/assets/shader/lighting/UnLit_frag.ts +++ b/src/assets/shader/lighting/UnLit_frag.ts @@ -3,7 +3,6 @@ export let UnLit_frag: string = /*wgsl*/ ` #include "GlobalUniform" fn UnLit(){ - let alpha = ORI_ShadingInput.BaseColor.a ; ORI_FragmentOutput.color = vec4(ORI_ShadingInput.BaseColor.rgb * alpha , alpha) ; diff --git a/src/assets/shader/materials/LambertShader.ts b/src/assets/shader/materials/LambertShader.ts new file mode 100644 index 00000000..a83d1da4 --- /dev/null +++ b/src/assets/shader/materials/LambertShader.ts @@ -0,0 +1,59 @@ +export let LambertShader: string = /*wgsl*/ ` + #include "Common_vert" + #include "Common_frag" + #include "ClusterLight" + #include "UnLit_frag" + #include "UnLitMaterialUniform_frag" + + @group(1) @binding(0) + var baseMapSampler: sampler; + @group(1) @binding(1) + var baseMap: texture_2d; + + fn vert(inputData:VertexAttributes) -> VertexOutput { + ORI_Vert(inputData) ; + return ORI_VertexOut ; + } + + fn frag(){ + var transformUV1 = materialUniform.transformUV1; + var transformUV2 = materialUniform.transformUV2; + + var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; + let baseColor = textureSample(baseMap,baseMapSampler,uv) ; + if(baseColor.w < 0.5){ + discard ; + } + + var lightColor = vec4(0.0); + let lightIndex = getCluster(ORI_VertexVarying.fragCoord); + let start = max(lightIndex.start, 0.0); + let count = max(lightIndex.count, 0.0); + let end = max(start + count , 0.0); + for(var i:i32 = i32(start) ; i < i32(end); i += 1 ) + { + let light = getLight(i32(i)); + + switch (light.lightType) { + case PointLightType: { + } + case DirectLightType: { + var normal = ORI_VertexVarying.vWorldNormal ; + let intensity = (light.intensity/10.0); + let att = max(dot(normal,-light.direction),0.0) * intensity ; + lightColor += baseColor * att * 0.5 + baseColor * 0.5 ; + // lightColor = baseColor * 0.5; + } + case SpotLightType: { + } + default: { + } + } + } + + ORI_ShadingInput.BaseColor = lightColor * materialUniform.baseColor ; + ORI_ShadingInput.BaseColor.w = 1.0 ; + UnLit(); + } +` + diff --git a/src/assets/shader/materials/Lambert_shader.ts b/src/assets/shader/materials/Lambert_shader.ts deleted file mode 100644 index a0c788c2..00000000 --- a/src/assets/shader/materials/Lambert_shader.ts +++ /dev/null @@ -1,74 +0,0 @@ - -export class Lambert_shader { - public static lambert_frag_wgsl = /* wgsl */ ` - #include "FragmentOutput.wgsl" - #include "LighStruct" - #include "ColorUtil_frag" - - @group(2) @binding(4) - var baseMapSampler: sampler; - @group(2) @binding(5) - var baseMap: texture_2d; - - struct StandMaterial { - transformUV1:vec4, - transformUV2:vec4, - baseColor: vec4, - dirLight: vec4, - dirLightColor: vec4, - alphaCutoff: f32, - shadowBias: f32, - }; - - @group(2) @binding(0) - var materialUniform: StandMaterial; - - fn frag(){ - var baseColor = materialUniform.baseColor; - var alphaCutoff = materialUniform.alphaCutoff; - var shadowBias = materialUniform.shadowBias; - var transformUV1 = materialUniform.transformUV1; - var transformUV2 = materialUniform.transformUV2; - - var uv = transformUV1.zw * vUv0 + transformUV1.xy; - var baseMap = textureSample(baseMap, baseMapSampler, uv).xyz; - - let viewDir = normalize(globalUniform.cameraWorldMatrix[3].xyz - vWorldPos.xyz) ; - - let lightIndex = getCluster(builtin_fragCoord); - let start = max(lightIndex.start, 0.0); - let count = max(lightIndex.count, 0.0); - let end = max(start + count , 0.0); - var color = vec3(0.0); - for(var i:i32 = i32(start) ; i < i32(end); i = i + 1 ) - { - let light = getLight(i) ; - switch (light.lightType) { - case PointLightType: { - let lightingColor = lambert_pointLight( baseMap , viewDir,vWorldNormal,vWorldPos.xyz,light); - color += lightingColor ; - } - case DirectLightType: { - let lightingColor = lambert_directLight( baseMap , viewDir,vWorldNormal,light.direction,light.lightColor,light.intensity); - color += lightingColor ; - } - case SpotLightType: { - - } - default: { - } - } - } - - ORI_FragmentOutput.color = vec4(color, 1.0); - } - `; - - public static lambert_vert_wgsl = /* wgsl */ ` - #include "Common_vert" - - fn vert(){ - - } - `; -} \ No newline at end of file diff --git a/src/assets/shader/materials/PBRLItShader.ts b/src/assets/shader/materials/PBRLItShader.ts index 3d1c3d05..f8026940 100644 --- a/src/assets/shader/materials/PBRLItShader.ts +++ b/src/assets/shader/materials/PBRLItShader.ts @@ -14,17 +14,24 @@ export let PBRLItShader: string = /*wgsl*/ ` var normalMap: texture_2d; #if USE_ARMC - @group(1) @binding(auto) - var maskMapSampler: sampler; - @group(1) @binding(auto) - var maskMap: texture_2d; + @group(1) @binding(auto) + var maskMapSampler: sampler; + @group(1) @binding(auto) + var maskMap: texture_2d; + #endif + + #if USE_MR + @group(1) @binding(auto) + var maskMapSampler: sampler; + @group(1) @binding(auto) + var maskMap: texture_2d; #endif #if USE_AOTEX - @group(1) @binding(auto) - var aoMapSampler: sampler; - @group(1) @binding(auto) - var aomapMap: texture_2d; + @group(1) @binding(auto) + var aoMapSampler: sampler; + @group(1) @binding(auto) + var aomapMap: texture_2d; #endif @group(1) @binding(auto) @@ -43,10 +50,9 @@ export let PBRLItShader: string = /*wgsl*/ ` var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy; - ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) * materialUniform.baseColor ; - - // #if USE_ALPHACUT - // ORI_ShadingInput.BaseColor.a = clamp(ORI_ShadingInput.BaseColor.a, 0.001 , 1.0 ); + ORI_ShadingInput.BaseColor = textureSample(baseMap, baseMapSampler, uv ) ; + ORI_ShadingInput.BaseColor = vec4(gammaToLiner(ORI_ShadingInput.BaseColor.rgb/ORI_ShadingInput.BaseColor.w ) * materialUniform.baseColor.rgb,ORI_ShadingInput.BaseColor.w*materialUniform.baseColor.a) ; + #if USE_ALPHACUT if( (ORI_ShadingInput.BaseColor.a - materialUniform.alphaCutoff) <= 0.0 ){ ORI_FragmentOutput.color = vec4(0.0,0.0,0.0,1.0); ORI_FragmentOutput.worldPos = vec4(0.0,0.0,0.0,1.0); @@ -54,14 +60,12 @@ export let PBRLItShader: string = /*wgsl*/ ` ORI_FragmentOutput.material = vec4(0.0,0.0,0.0,1.0); discard; } - // #endif + #endif #if USE_SHADOWMAPING useShadow(); #endif - // ORI_ShadingInput.BaseColor = vec4(sRGBToLinear(ORI_ShadingInput.BaseColor.xyz),ORI_ShadingInput.BaseColor.w); - #if USE_ARMC var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; @@ -75,6 +79,17 @@ export let PBRLItShader: string = /*wgsl*/ ` ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic ; + #elseif USE_MR + var maskTex = textureSample(maskMap, maskMapSampler, uv ) ; + #if USE_AOTEX + var aoMap = textureSample(aomapMap, aoMapSampler, uv ); + ORI_ShadingInput.AmbientOcclusion = mix(0.0,aoMap.r,materialUniform.ao) ; + #else + ORI_ShadingInput.AmbientOcclusion = materialUniform.ao ; + #endif + + ORI_ShadingInput.Roughness = maskTex.g * materialUniform.roughness ; + ORI_ShadingInput.Metallic = maskTex.b * materialUniform.metallic; #else ORI_ShadingInput.Roughness = materialUniform.roughness ; ORI_ShadingInput.Metallic = materialUniform.metallic ; @@ -89,6 +104,7 @@ export let PBRLItShader: string = /*wgsl*/ ` ORI_ShadingInput.Specular = 0.5 ; var emissiveColor = textureSample(emissiveMap, emissiveMapSampler , ORI_VertexVarying.fragUV0.xy) ; + emissiveColor = vec4(gammaToLiner(emissiveColor.rgb),emissiveColor.w); ORI_ShadingInput.EmissiveColor = vec4(materialUniform.emissiveColor.rgb * emissiveColor.rgb * materialUniform.emissiveIntensity,1.0); var Normal = textureSample(normalMap,normalMapSampler,ORI_VertexVarying.fragUV0).rgb ; diff --git a/src/assets/shader/materials/program/Clearcoat_frag.ts b/src/assets/shader/materials/program/Clearcoat_frag.ts index ee478d64..a912de39 100644 --- a/src/assets/shader/materials/program/Clearcoat_frag.ts +++ b/src/assets/shader/materials/program/Clearcoat_frag.ts @@ -9,13 +9,42 @@ export let Clearcoat_frag: string = /*wgsl*/ ` @group(1) @binding(auto) var clearCoatRoughnessMap: texture_2d; - fn getClearcoatRoughnees() -> f32{ + fn getClearcoatRoughnees() -> f32{ let clearcoatRoughness = textureSample(clearCoatRoughnessMap, clearCoatRoughnessMapSampler, ORI_VertexVarying.fragUV0.xy).r; return clearcoatRoughness; } #else - fn getClearcoatRoughnees() -> f32{ - return 0.0; + fn getClearcoatRoughnees() -> f32{ + return 1.0; + } + #endif + + #if USE_CLEARCOAT + fn ClearCoat_BRDF( baseColor:vec3, clearCoatColor:vec3 , ior:f32 ,N:vec3, L:vec3 , V:vec3 , clearCoatStrength:f32, clearCoatPerceptualRoughness:f32 , att:f32) -> vec3 { + var factor = clamp(clearCoatPerceptualRoughness, 0.0001, 1.0); + var clearCoatRoughness = factor * factor; + + let H = normalize(-V + L); + let R = 2.0 * dot( -V , N ) * N + V ; + let LoH = dot(L,H); + let NoV = max(dot(N,-V),0.0); + let NoL = max(dot(N,L),0.0); + let NoH = max(dot(N,H),0.00001); + + let Fr = FresnelSchlickRoughness( NoV , vec3(0.0) , clearCoatRoughness ) ; + var Fd = clearCoatColor / 3.1415926 ; + let F0 = IORToF0(ior) ; + // clear coat BRDF + var Dc = D_GGX(NoH,clearCoatRoughness); + var Vc = V_Kelemen(LoH) * NoL; + var Fc = F_Schlick( vec3(F0) , 1.0, NoV) * materialUniform.clearcoatFactor; + var Frc = (Dc * Vc) * Fc; + // base layer attenuation for energy compensation + let oneMinusFc = 1.0 - Fc; + let brdfSpecular = ((Fd + Fr * oneMinusFc) * oneMinusFc + Frc) * att ; + var iblSpecular = vec3(brdfSpecular); + iblSpecular += approximateSpecularIBL(vec3(1.0),clearCoatRoughness,R, NoV) * Fc ; + return vec3(mix(baseColor,iblSpecular,materialUniform.clearcoatWeight)); } #endif ` \ No newline at end of file diff --git a/src/assets/shader/materials/program/NormalMap_frag.ts b/src/assets/shader/materials/program/NormalMap_frag.ts index 8af8cb5e..05cf453d 100644 --- a/src/assets/shader/materials/program/NormalMap_frag.ts +++ b/src/assets/shader/materials/program/NormalMap_frag.ts @@ -22,7 +22,7 @@ export let NormalMap_frag: string = /*wgsl*/ ` fn unpackNormalMap( normal : vec3 ) -> vec3 { var normalTex = vec3( normal.xyz * 2.0 - 1.0 ) ; - return normalize(normalTex); + return (normalTex); } fn unPackNormal(normal : vec3 , height:f32 ) -> vec3{ diff --git a/src/assets/shader/materials/program/ShadowMapping_frag.ts b/src/assets/shader/materials/program/ShadowMapping_frag.ts index 28c2c3b7..ca929630 100644 --- a/src/assets/shader/materials/program/ShadowMapping_frag.ts +++ b/src/assets/shader/materials/program/ShadowMapping_frag.ts @@ -32,44 +32,40 @@ export let ShadowMapping_frag: string = /*wgsl*/ ` } fn directShadowMaping(shadowBias: f32) { - for (var i: i32 = shadowBuffer.nDirShadowStart; i < shadowBuffer.nDirShadowEnd ; i = i + 1) { - let ldx = shadowBuffer.shadowLights[i]; - var light = lightBuffer[ldx]; - var shadowIndex = i32(light.castShadow); - shadowStrut.directShadowVisibility[shadowIndex] = 1.0; - #if USE_SHADOWMAPING - var shadowPosTmp = globalUniform.shadowMatrix[shadowIndex] * vec4(ORI_VertexVarying.vWorldPos.xyz, 1.0); - var shadowPos = shadowPosTmp.xyz / shadowPosTmp.w; - var varying_shadowUV = shadowPos.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5); - var bias = max(shadowBias * (1.0 - dot(ORI_ShadingInput.Normal, light.direction)), 0.000005); - - // if(varying_shadowUV.y>=1.0) { - // shadowStrut.directShadowVisibility[shadowIndex] = 2.0 ; - // continue; - // } - if (varying_shadowUV.x <= 1.0 && varying_shadowUV.x >= 0.0 && varying_shadowUV.y <= 1.0 && varying_shadowUV.y >= 0.0 && shadowPosTmp.z <= 1.0) { - var texelSize = 1.0 / vec2(globalUniform.shadowMapSize); - var oneOverShadowDepthTextureSize = texelSize; - var size = 1; - var sizeBlock = size * 2 + 1; - var sizeBlockA = sizeBlock * sizeBlock; - var visibility = 0.0; - for (var y = -size; y <= size; y++) { - for (var x = -size; x <= size; x++) { - var offset = vec2(f32(x), f32(y)) * oneOverShadowDepthTextureSize / f32(sizeBlock); - visibility += textureSampleCompare( - shadowMap, - shadowMapSampler, - varying_shadowUV + offset, - shadowIndex, - shadowPos.z - bias - ); + for (var i: i32 = 0; i < 8 ; i = i + 1) { + if( i >= shadowBuffer.nDirShadowStart && i <= shadowBuffer.nDirShadowEnd ){ + let ldx = shadowBuffer.shadowLights[i]; + var light = lightBuffer[ldx]; + var shadowIndex = i32(light.castShadow); + #if USE_SHADOWMAPING + var shadowPosTmp = globalUniform.shadowMatrix[shadowIndex] * vec4(ORI_VertexVarying.vWorldPos.xyz, 1.0); + var shadowPos = shadowPosTmp.xyz / shadowPosTmp.w; + var varying_shadowUV = shadowPos.xy * vec2(0.5, -0.5) + vec2(0.5, 0.5); + var bias = min(shadowBias * (1.0 - dot(ORI_ShadingInput.Normal, light.direction)), 0.0005); + if (varying_shadowUV.x <= 1.0 && varying_shadowUV.x >= 0.0 && varying_shadowUV.y <= 1.0 && varying_shadowUV.y >= 0.0 && shadowPosTmp.z <= 1.0) { + var texelSize = 1.0 / vec2(globalUniform.shadowMapSize); + var oneOverShadowDepthTextureSize = texelSize; + var size = 1; + var sizeBlock = size * 2 + 1; + var sizeBlockA = sizeBlock * sizeBlock; + var visibility = 0.0; + for (var y = -size; y <= size; y++) { + for (var x = -size; x <= size; x++) { + var offset = vec2(f32(x), f32(y)) * oneOverShadowDepthTextureSize / f32(sizeBlock); + visibility += textureSampleCompare( + shadowMap, + shadowMapSampler, + varying_shadowUV + offset, + shadowIndex, + shadowPos.z - bias + ); + } } + visibility /= f32(sizeBlockA); + shadowStrut.directShadowVisibility[i] = visibility + 0.001; } - visibility /= f32(sizeBlockA); - shadowStrut.directShadowVisibility[shadowIndex] = visibility + 0.001; - } - #endif + #endif + } } } @@ -81,62 +77,64 @@ export let ShadowMapping_frag: string = /*wgsl*/ ` // let count = max(lightIndex.count, 0.0); // let end = max(start + count, 0.0); - for (var i: i32 = shadowBuffer.nPointShadowStart; i < shadowBuffer.nPointShadowEnd ; i = i + 1) { - let ldx = shadowBuffer.shadowLights[i]; - let light = lightBuffer[ldx] ; - shadowStrut.pointShadows[light.castShadow] = 1.0; - - #if USE_SHADOWMAPING - let lightPos = light.position.xyz; - var shadow = 0.0; - let frgToLight = worldPos - lightPos.xyz; - var dir: vec3 = normalize(frgToLight); - var len = length(frgToLight); - var bias = max(shadowBias * globalUniform.far * (1.0 - dot(ORI_ShadingInput.Normal, dir)), 0.005); - - #if USE_PCF_SHADOW - let samples = 4.0; - for (var x: f32 = -offset; x < offset; x += offset / (samples * 0.5)) { - for (var y: f32 = -offset; y < offset; y += offset / (samples * 0.5)) { - for (var z: f32 = -offset; z < offset; z += offset / (samples * 0.5)) { - let offsetDir = normalize(dir.xyz + vec3(x, y, z)); - var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); - depth *= globalUniform.far; - if ((len - bias) > depth) { - shadow += 1.0 * dot(offsetDir, dir.xyz); + for (var i: i32 = 0; i < 8 ; i = i + 1) { + if( i >= shadowBuffer.nPointShadowStart && i <= shadowBuffer.nPointShadowEnd ){ + let ldx = shadowBuffer.shadowLights[i]; + let light = lightBuffer[ldx] ; + shadowStrut.pointShadows[i] = 1.0; + + #if USE_SHADOWMAPING + let lightPos = light.position.xyz; + var shadow = 0.0; + let frgToLight = worldPos - lightPos.xyz; + var dir: vec3 = normalize(frgToLight); + var len = length(frgToLight); + var bias = max(shadowBias * globalUniform.far * (1.0 - dot(ORI_ShadingInput.Normal, dir)), 0.005); + + #if USE_PCF_SHADOW + let samples = 4.0; + for (var x: f32 = -offset; x < offset; x += offset / (samples * 0.5)) { + for (var y: f32 = -offset; y < offset; y += offset / (samples * 0.5)) { + for (var z: f32 = -offset; z < offset; z += offset / (samples * 0.5)) { + let offsetDir = normalize(dir.xyz + vec3(x, y, z)); + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); + depth *= globalUniform.far; + if ((len - bias) > depth) { + shadow += 1.0 * dot(offsetDir, dir.xyz); + } } } } - } - shadow = min(max(shadow / (samples * samples * samples), 0.0), 1.0); - #endif - - #if USE_SOFT_SHADOW - let vDis = length(globalUniform.CameraPos.xyz - worldPos.xyz); - let sampleRadies = globalUniform.shadowSoft; - let samples = 20; - for (var j: i32 = 0; j < samples; j += 1) { - let offsetDir = normalize(dir.xyz + sampleOffetDir[j] * sampleRadies); - var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); + shadow = min(max(shadow / (samples * samples * samples), 0.0), 1.0); + #endif + + #if USE_SOFT_SHADOW + let vDis = length(globalUniform.CameraPos.xyz - worldPos.xyz); + let sampleRadies = globalUniform.shadowSoft; + let samples = 20; + for (var j: i32 = 0; j < samples; j += 1) { + let offsetDir = normalize(dir.xyz + sampleOffetDir[j] * sampleRadies); + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, offsetDir, light.castShadow, 0); + depth *= globalUniform.far; + if ((len - bias) > depth) { + shadow += 1.0 * dot(offsetDir, dir.xyz); + } + } + shadow = min(max(shadow / f32(samples), 0.0), 1.0); + #endif + + #if USE_HARD_SHADOW + var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, dir.xyz, light.castShadow, 0); depth *= globalUniform.far; if ((len - bias) > depth) { - shadow += 1.0 * dot(offsetDir, dir.xyz); + shadow = 1.0; } + #endif + + shadowStrut.pointShadows[i] = 1.0 - shadow; + #endif } - shadow = min(max(shadow / f32(samples), 0.0), 1.0); - #endif - - #if USE_HARD_SHADOW - var depth = textureSampleLevel(pointShadowMap, pointShadowMapSampler, dir.xyz, light.castShadow, 0); - depth *= globalUniform.far; - if ((len - bias) > depth) { - shadow = 1.0; } - #endif - - shadowStrut.pointShadows[light.castShadow] = 1.0 - shadow; - #endif - } } #if USE_SOFT_SHADOW diff --git a/src/assets/shader/math/MatrixShader.ts b/src/assets/shader/math/MatrixShader.ts new file mode 100644 index 00000000..05df75a1 --- /dev/null +++ b/src/assets/shader/math/MatrixShader.ts @@ -0,0 +1,107 @@ +/** + * @internal + */ +export let MatrixShader = /* wgsl */ ` + #include "MathShader" + + fn buildMatrix3x3() -> mat3x3{ + var mat3 = mat3x3( + 1.0,0.0,0.0, + 0.0,1.0,0.0, + 0.0,0.0,1.0, + ); + return mat3 ; + } + + fn buildMatrix4x4() -> mat4x4{ + var mat4 = mat4x4( + 1.0,0.0,0.0,0.0, + 0.0,1.0,0.0,0.0, + 0.0,0.0,1.0,0.0, + 0.0,0.0,0.0,1.0, + ); + return mat4 ; + } + + fn buildRotateXMat3(rad:f32) -> mat3x3{ + var xrot = mat3x3( + 1.0,0.0,0.0, + 0.0,cos(rad),-sin(rad), + 0.0,sin(rad),cos(rad) + ); + return xrot; + } + + fn buildRotateXMat4(rad:f32,x:f32,y:f32,z:f32) -> mat4x4{ + var xrot = mat4x4( + 1.0,0.0,0.0,0.0, + 0.0,cos(rad),-sin(rad),0.0, + 0.0,sin(rad),cos(rad),0.0, + x,y,z,1.0, + ); + return xrot; + } + + fn buildRotateXYZMat4(radX:f32,radY:f32,radZ:f32,x:f32,y:f32,z:f32) -> mat4x4{ + var xRot = mat4x4( + 1.0,0.0,0.0,0.0, + 0.0,cos(radX),-sin(radX),0.0, + 0.0,sin(radX),cos(radX),0.0, + 0.0,0.0,0.0,1.0, + ); + var yRot = mat4x4( + cos(radY),0.0,sin(radY),0.0, + 0.0,1.0,0.0,0.0, + -sin(radY),0.0,cos(radY),0.0, + 0.0,0.0,0.0,1.0, + ); + var zRot = mat4x4( + cos(radZ),-sin(radZ),0.0,0.0, + sin(radZ), cos(radZ),0.0,0.0, + 0.0,0.0,1.0,0.0, + 0.0,0.0,0.0,1.0, + ); + var fMat = xRot * yRot * zRot ; + fMat[3].x = x; + fMat[3].y = y; + fMat[3].z = z; + return fMat; + } + + fn buildRotateYMat3(rad:f32) -> mat3x3{ + var yrot = mat3x3( + cos(rad),0.0,sin(rad), + 0.0,1.0,0.0, + -sin(rad),0.0,cos(rad) + ); + return yrot ; + } + + fn buildRotateZ(rad:f32) -> mat3x3{ + var zrot = mat3x3( + cos(rad),-sin(rad),0.0, + sin(rad), cos(rad),0.0, + 0.0,0.0,1.0 + ); + return zrot; + } + + // fn buildRotateXMat4(rad:f32) -> mat4x4{ + // var xrot = mat4x4( + // 1.0,0.0,0.0,0.0, + // 0.0,cos(rad),-sin(rad),0.0, + // 0.0,sin(rad),cos(rad),0.0, + // 0.0,0.0,0.0,1.0); + // return xrot; + // } + + fn bulidTranslateMat4(x:f32,y:f32,z:f32) -> mat4x4{ + var trans = mat4x4( + 1.0,0.0,0.0,0.0, + 0.0,1.0,0.0,0.0, + 0.0,0.0,1.0,0.0, + x,y,z,1.0); + return trans; + } + +`; diff --git a/src/assets/shader/post/GlobalFog_shader.ts b/src/assets/shader/post/GlobalFog_shader.ts index d58f7823..d3a4da3e 100644 --- a/src/assets/shader/post/GlobalFog_shader.ts +++ b/src/assets/shader/post/GlobalFog_shader.ts @@ -192,6 +192,7 @@ fn computeFog(z:f32) -> f32 scatter *= (1.0-saturate(exp2(-global.dirHeightLine))); return vec3(scatter*sunColor); } + `; diff --git a/src/assets/shader/utils/ColorUtil.ts b/src/assets/shader/utils/ColorUtil.ts index 9b2636c3..719b8229 100644 --- a/src/assets/shader/utils/ColorUtil.ts +++ b/src/assets/shader/utils/ColorUtil.ts @@ -32,20 +32,20 @@ export let ColorUtil: string = /*wgsl*/ ` return color2; } - fn gammaToLiner(color: vec4) -> vec4 < f32 > { + fn gammaToLiner(color: vec3) -> vec3 < f32 > { let gammaCorrect = 2.4; - var color2 = pow(color, vec4(gammaCorrect)); + var color2 = pow(color, vec3(gammaCorrect)); return color2 ; } fn linerToGamma4(color: vec4) -> vec4 < f32 > { - let gammaCorrect = 1.0 / 2.4; + let gammaCorrect = 0.416666667; var color2 = pow(color, vec4(gammaCorrect)); return color2 ; } fn linerToGamma3(color: vec3) -> vec3 < f32 > { - let gammaCorrect = 1.0 / 2.4; + let gammaCorrect = 0.416666667; var color2 = pow(color, vec3(gammaCorrect)); return color2 ; } @@ -83,7 +83,7 @@ export let ColorUtil: string = /*wgsl*/ ` fn LinearToSrgbBranchless(lin: vec3) -> vec3 { var lin2 = max(vec3(6.10352e-5), lin); - return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(1.0 / 2.4)) * vec3(1.055) - vec3(0.055)); + return min(lin2 * 12.92, pow(max(lin2, vec3(0.00313067)), vec3(0.416666667)) * vec3(1.055) - vec3(0.055)); } fn sRGBToLinear(color : vec3) -> vec3 @@ -96,4 +96,18 @@ export let ColorUtil: string = /*wgsl*/ ` return color2 * (1.0 / 12.92); } } + +// fn ReorientedBlendNormal(){ +// vec3 t = texture(baseMap, uv).xyz * vec3( 2.0, 2.0, 2.0) + vec3(-1.0, -1.0, 0.0); +// vec3 u = texture(detailMap, uv).xyz * vec3(-2.0, -2.0, 2.0) + vec3( 1.0, 1.0, -1.0); +// vec3 r = normalize(t * dot(t, u) - u * t.z); +// return r; +// } + +// fn UDNBlendNormal(){ + // vec3 t = texture(baseMap, uv).xyz * 2.0 - 1.0; + // vec3 u = texture(detailMap, uv).xyz * 2.0 - 1.0; + // vec3 r = normalize(t.xy + u.xy, t.z); + // return r; +// } ` diff --git a/src/components/ColliderComponent.ts b/src/components/ColliderComponent.ts index 648026dc..4115077d 100644 --- a/src/components/ColliderComponent.ts +++ b/src/components/ColliderComponent.ts @@ -1,3 +1,4 @@ +import { ComponentCollect, View3D } from ".."; import { Engine3D } from "../Engine3D"; import { Ray } from "../math/Ray"; import { Vector3 } from "../math/Vector3"; @@ -25,6 +26,14 @@ export class ColliderComponent extends ComponentBase { } } + public onEnable(view?: View3D) { + ComponentCollect.bindEnablePick(view, this, null); + } + + public onDisable(view?: View3D) { + ComponentCollect.unBindEnablePick(view, this); + } + /** * Returns the shape of collider */ diff --git a/src/components/Transform.ts b/src/components/Transform.ts index 0b74525d..8f175082 100644 --- a/src/components/Transform.ts +++ b/src/components/Transform.ts @@ -92,10 +92,11 @@ export class Transform extends ComponentBase { private _parent: Transform; private _localPos: Vector3; - private _localRot: Vector3; + public _localRot: Vector3; private _localRotQuat: Quaternion; private _localScale: Vector3; // public localMatrix: Matrix4; + public _localChange: boolean = true; private _forward: Vector3 = new Vector3(); private _back: Vector3 = new Vector3(); @@ -104,9 +105,13 @@ export class Transform extends ComponentBase { private _up: Vector3 = new Vector3(); private _down: Vector3 = new Vector3(); public readonly _worldMatrix: Matrix4; - private _localChange: boolean = true; + + public rotatingX: number = 0; + public rotatingY: number = 0; + public rotatingZ: number = 0; private _targetPos: Vector3; + public static: boolean = false; public get targetPos(): Vector3 { return this._targetPos; @@ -140,9 +145,9 @@ export class Transform extends ComponentBase { child.transform.parent = value ? this : null; } - if (value) { - this.transform.updateWorldMatrix(); - } + // if (value) { + // this.transform.updateWorldMatrix(); + // } //notify parent change this.object3D.components.forEach((c) => { @@ -201,8 +206,10 @@ export class Transform extends ComponentBase { */ public notifyLocalChange() { this._localChange = true; - for (let child of this.object3D.entityChildren) { - child.transform.notifyLocalChange(); + if (this.object3D) { + for (let child of this.object3D.entityChildren) { + child.transform.notifyLocalChange(); + } } this.eventDispatcher.dispatchEvent(this.eventLocalChange); } @@ -356,10 +363,12 @@ export class Transform extends ComponentBase { public updateWorldMatrix(force: boolean = false) { if (this._localChange || force) { if (this.parent) { + // this._localRot.y += this.rotatingY; makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); append(this._worldMatrix, this.parent.worldMatrix, this._worldMatrix); // WasmMatrix4.makeMatrix44Append(this._localRot, this._localPos, this.localScale, this._worldMatrix, this._worldMatrix, this.parent.worldMatrix, this._worldMatrix); } else { + this._localRot.y += this.rotatingY; makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); // WasmMatrix4.makeMatrix44(this._localRot, this._localPos, this.localScale, this._worldMatrix); } @@ -367,6 +376,21 @@ export class Transform extends ComponentBase { this._localChange = false; } + public static updateChildTransform(transform: Transform) { + if (!transform.view3D || !transform.enable) { + return; + } + if (transform._localChange) + transform.updateWorldMatrix(); + let children = transform.object3D.entityChildren; + let i = 0; + let len = children.length; + for (i = 0; i < len; i++) { + const node = children[i]; + Transform.updateChildTransform(node.transform); + } + } + public lookTarget(target: Vector3, up: Vector3 = Vector3.UP) { this.lookAt(this.transform.worldPosition, target, up); } @@ -403,7 +427,7 @@ export class Transform extends ComponentBase { transform.localScale.copyFrom(prs[2]); transform.localScale = transform.localScale; - this.updateWorldMatrix(); + // this.updateWorldMatrix(); return this; } @@ -599,9 +623,9 @@ export class Transform extends ComponentBase { } public set localPosition(v: Vector3) { - this.x = v.x; - this.y = v.y; - this.z = v.z; + this._localPos.x = v.x; + this._localPos.y = v.y; + this._localPos.z = v.z; this.notifyLocalChange(); this.onPositionChange?.(); diff --git a/src/components/controller/FlyCameraController.ts b/src/components/controller/FlyCameraController.ts index eb804aa9..4886cb9a 100644 --- a/src/components/controller/FlyCameraController.ts +++ b/src/components/controller/FlyCameraController.ts @@ -213,7 +213,7 @@ export class FlyCameraController extends ComponentBase { } public onUpdate(): void { - this.transform.updateWorldMatrix(); + // this.transform.updateWorldMatrix(); let transform = this.transform; let dt = clamp(Time.delta, 0.0, 0.016); diff --git a/src/components/gui/core/GUIRenderer.ts b/src/components/gui/core/GUIRenderer.ts index 4d26884d..5879c5a5 100644 --- a/src/components/gui/core/GUIRenderer.ts +++ b/src/components/gui/core/GUIRenderer.ts @@ -70,7 +70,7 @@ export class GUIRenderer extends MeshRenderer { } public onUpdate(view?: View3D) { - this.transform.updateWorldMatrix(); + // this.transform.updateWorldMatrix(); } } diff --git a/src/components/lights/DirectLight.ts b/src/components/lights/DirectLight.ts index 6f9daaad..f28fdd3f 100644 --- a/src/components/lights/DirectLight.ts +++ b/src/components/lights/DirectLight.ts @@ -23,6 +23,7 @@ export class DirectLight extends LightBase { this.radius = 9999999;// Number.MAX_SAFE_INTEGER; this.lightData.lightType = LightType.DirectionLight; this.lightData.linear = 0; + this.lightData.quadratic = 0.3; } public start(): void { diff --git a/src/components/lights/PointLight.ts b/src/components/lights/PointLight.ts index b41067b1..81f94ecf 100644 --- a/src/components/lights/PointLight.ts +++ b/src/components/lights/PointLight.ts @@ -103,7 +103,7 @@ export class PointLight extends LightBase { } public onUpdate(): void { - this.transform.updateWorldMatrix(true); + // this.transform.updateWorldMatrix(true); } public onGraphic(view?: View3D): void { diff --git a/src/components/lights/SpotLight.ts b/src/components/lights/SpotLight.ts index 0e8a8c5b..24ec7f60 100644 --- a/src/components/lights/SpotLight.ts +++ b/src/components/lights/SpotLight.ts @@ -118,7 +118,7 @@ export class SpotLight extends LightBase { } public onUpdate(): void { - this.transform.updateWorldMatrix(true); + // this.transform.updateWorldMatrix(true); } public onGraphic(view: View3D) { diff --git a/src/components/renderer/InstanceDrawComponent.ts b/src/components/renderer/InstanceDrawComponent.ts index 3030f7e2..baaf6e47 100644 --- a/src/components/renderer/InstanceDrawComponent.ts +++ b/src/components/renderer/InstanceDrawComponent.ts @@ -12,40 +12,50 @@ import { ClusterLightingBuffer } from "../../gfx/renderJob/passRenderer/cluster/ export class InstanceDrawComponent extends RenderNode { - private _keyGroup: Map; - private _instanceMatrixBuffer: StorageGPUBuffer; + private _keyRenderGroup: Map; + private _keyBufferGroup: Map; + private _keyIdsGroup: Map; public init(param?: any): void { - this._keyGroup = new Map(); + this._keyRenderGroup = new Map(); + this._keyBufferGroup = new Map(); + this._keyIdsGroup = new Map(); } public start(): void { let meshRenders: MeshRenderer[] = []; this.object3D.getComponents(MeshRenderer, meshRenders, true); - this._instanceMatrixBuffer = new StorageGPUBuffer(meshRenders.length); - this._instanceMatrixBuffer.visibility = GPUShaderStage.VERTEX; - let idArray = new Int32Array(meshRenders.length); + + // let idArray = new Int32Array(meshRenders.length); for (let i = 0; i < meshRenders.length; i++) { const mr = meshRenders[i]; - mr.transform.enable = false; + mr.enable = false; + - idArray[i] = mr.transform.worldMatrix.index; - let key = mr.geometry.uuid; + let key = mr.geometry.instanceID; for (let j = 0; j < mr.materials.length; j++) { const mat = mr.materials[j]; key += mat.instanceID; } - if (!this._keyGroup.has(key)) { - this._keyGroup.set(key, [mr]); + if (!this._keyRenderGroup.has(key)) { + let matrixBuffer = new StorageGPUBuffer(meshRenders.length); + matrixBuffer.visibility = GPUShaderStage.VERTEX; + this._keyRenderGroup.set(key, [mr]); + this._keyBufferGroup.set(key, matrixBuffer); + this._keyIdsGroup.set(key, [mr.transform.worldMatrix.index]); } else { - this._keyGroup.get(key).push(mr); + this._keyRenderGroup.get(key).push(mr); + this._keyIdsGroup.get(key).push(mr.transform.worldMatrix.index); } } - this.instanceCount = meshRenders.length; - this._instanceMatrixBuffer.setInt32Array("matrixIDs", idArray); - this._instanceMatrixBuffer.apply(); + this._keyBufferGroup.forEach((v, k) => { + let ids = this._keyIdsGroup.get(k); + let instanceMatrixBuffer = this._keyBufferGroup.get(k); + instanceMatrixBuffer.setInt32Array("matrixIDs", new Int32Array(ids)); + instanceMatrixBuffer.apply(); + }) } public stop(): void { @@ -53,73 +63,74 @@ export class InstanceDrawComponent extends RenderNode { } public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer?: ClusterLightingBuffer): void { - - - this._keyGroup.forEach((v, k) => { + this._keyRenderGroup.forEach((v, k) => { + let instanceMatrixBuffer = this._keyBufferGroup.get(k); let renderNode = v[0]; for (let i = 0; i < renderNode.materials.length; i++) { let material = renderNode.materials[i]; let passes = material.renderPasses.get(passType); if (passes) { for (let i = 0; i < passes.length; i++) { - const renderShader = passes[i].renderShader;// RenderShader.getShader(passes[i].shaderID); - + const renderShader = passes[i].renderShader; renderShader.setDefine("USE_INSTANCEDRAW", true); - renderShader.setStorageBuffer(`instanceDrawID`, this._instanceMatrixBuffer); + renderShader.setStorageBuffer(`instanceDrawID`, instanceMatrixBuffer); } } } renderNode.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); }) - super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer); + this.preInit = false; } - public renderPass(view: View3D, passType: RendererType, renderEncoder: RenderContext) { - this._keyGroup.forEach((v, k) => { + public renderPass(view: View3D, passType: RendererType, renderContext: RenderContext) { + this._keyRenderGroup.forEach((v, k) => { let renderNode = v[0]; - // for (let ii = 0; ii < v.length; ii++) { - // const renderNode = v[ii]; - // renderNode.object3D.transform.updateWorldMatrix() - // } - for (let i = 0; i < renderNode.materials.length; i++) { - const material = renderNode.materials[i]; - let passes = material.renderPasses.get(passType); + renderNode.instanceCount = v.length; + this.renderItem(view, passType, renderNode, renderContext); + }) + } - if (!passes || passes.length == 0) continue; - - GPUContext.bindGeometryBuffer(renderEncoder.encoder, renderNode.geometry); - let worldMatrix = renderNode.object3D.transform._worldMatrix; - for (let j = 0; j < passes.length; j++) { - if (!passes || passes.length == 0) continue; - let matPass = passes[j]; - if (!matPass.enable) continue; - - for (let jj = passes.length > 1 ? 1 : 0; jj < passes.length; jj++) { - const renderShader = matPass.renderShader; - if (renderShader.shaderState.splitTexture) { - - renderEncoder.endRenderPass(); - RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); - renderEncoder.beginRenderPass(); - - GPUContext.bindCamera(renderEncoder.encoder, view.camera); - GPUContext.bindGeometryBuffer(renderEncoder.encoder, renderNode.geometry); - } - GPUContext.bindPipeline(renderEncoder.encoder, renderShader); - let subGeometries = renderNode.geometry.subGeometries; - for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[k]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[renderNode.lodLevel]; - - GPUContext.drawIndexed(renderEncoder.encoder, lodInfo.indexCount, v.length, lodInfo.indexStart, 0, 0); - } - } + public renderItem(view: View3D, passType: RendererType, renderNode: RenderNode, renderContext: RenderContext) { + let worldMatrix = renderNode.transform._worldMatrix; + + for (let i = 0; i < renderNode.materials.length; i++) { + const material = renderNode.materials[i]; + let passes = material.renderPasses.get(passType); + + if (!passes || passes.length == 0) + continue; + + for (let j = 0; j < passes.length; j++) { + if (!passes || passes.length == 0) + continue; + let matPass = passes[j]; + if (!matPass.enable) + continue; + + GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode.geometry); + const renderShader = matPass.renderShader; + if (renderShader.shaderState.splitTexture) { + renderContext.endRenderPass(); + RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); + renderContext.beginRenderPass(); + + GPUContext.bindCamera(renderContext.encoder, view.camera); + GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode.geometry); } - } - }) + GPUContext.bindPipeline(renderContext.encoder, renderShader); + let subGeometries = renderNode.geometry.subGeometries; + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + + if (renderNode.instanceCount > 0) { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); + } else { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } + } } } - diff --git a/src/components/renderer/RenderNode.ts b/src/components/renderer/RenderNode.ts index 7f23f569..31645f11 100644 --- a/src/components/renderer/RenderNode.ts +++ b/src/components/renderer/RenderNode.ts @@ -49,9 +49,11 @@ export class RenderNode extends ComponentBase { public isRenderOrderChange?: boolean; public needSortOnCameraZ?: boolean; - constructor() { - super(); + public preInit: boolean = false; + + public init() { this.rendererMask = RendererMask.Default; + this.instanceID = UUID(); } public copyComponent(from: this): this { @@ -119,8 +121,9 @@ export class RenderNode extends ComponentBase { return this._materials; } - @EditorInspector public set materials(value: MaterialBase[]) { + this._readyPipeline = false; + for (let i = 0; i < this._materials.length; i++) { let mat = this._materials[i]; Reference.getInstance().detached(mat, this) @@ -147,10 +150,7 @@ export class RenderNode extends ComponentBase { } } - public init() { - // this.renderPasses = new Map(); - this.instanceID = UUID(); - } + public addRendererMask(tag: RendererMask) { this._rendererMask = RendererMaskUtil.addMask(this._rendererMask, tag); @@ -167,7 +167,6 @@ export class RenderNode extends ComponentBase { EntityCollect.instance.addRenderNode(this.transform.scene3D, this); } - public onDisable(): void { EntityCollect.instance.removeRenderNode(this.transform.scene3D, this); } @@ -187,8 +186,9 @@ export class RenderNode extends ComponentBase { protected initPipeline() { if (this._geometry && this._materials.length > 0) { - for (let i = 0; i < this._materials.length; i++) { - const material = this._materials[i]; + let index = 0; + for (let j = 0; j < this._materials.length; j++) { + const material = this._materials[j]; let passList = material.addPass(RendererType.COLOR, material); for (let i = 0; i < passList.length; i++) { const pass = passList[i]; @@ -198,7 +198,6 @@ export class RenderNode extends ComponentBase { } this._geometry.generate(shader.shaderReflection); } - this.object3D.bound = this._geometry.bounds.clone(); } this._readyPipeline = true; @@ -220,6 +219,7 @@ export class RenderNode extends ComponentBase { if (this.enable && this.transform && this.transform.scene3D) { EntityCollect.instance.addRenderNode(this.transform.scene3D, this); } + } } @@ -313,27 +313,29 @@ export class RenderNode extends ComponentBase { // for (let j = passes.length > 1 ? 1 : 0 ; j < passes.length; j++) { const renderShader = matPass.renderShader; - if (renderShader.shaderState.splitTexture) { - renderContext.endRenderPass(); - RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); - renderContext.beginRenderPass(); - GPUContext.bindCamera(renderContext.encoder, view.camera); - GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode._geometry); - } - GPUContext.bindPipeline(renderContext.encoder, renderShader); - let subGeometries = renderNode._geometry.subGeometries; - // for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[i]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[renderNode.lodLevel]; + if (renderShader.pipeline) { + if (renderShader.shaderState.splitTexture) { + renderContext.endRenderPass(); + RTResourceMap.WriteSplitColorTexture(renderNode.instanceID); + renderContext.beginRenderPass(); - if (renderNode.instanceCount > 0) { - GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); - } else { - GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + GPUContext.bindCamera(renderContext.encoder, view.camera); + GPUContext.bindGeometryBuffer(renderContext.encoder, renderNode._geometry); + } + GPUContext.bindPipeline(renderContext.encoder, renderShader); + let subGeometries = renderNode._geometry.subGeometries; + // for (let k = 0; k < subGeometries.length; k++) { + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + + if (renderNode.instanceCount > 0) { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, renderNode.instanceCount, lodInfo.indexStart, 0, 0); + } else { + GPUContext.drawIndexed(renderContext.encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } } - // } } } } @@ -347,7 +349,7 @@ export class RenderNode extends ComponentBase { public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { if (!this.enable) return; - this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); + // this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); let node = this; let worldMatrix = node.object3D.transform._worldMatrix; @@ -358,26 +360,29 @@ export class RenderNode extends ComponentBase { return; if (this.drawType == 2) { - for (let j = 0; j < passes.length; j++) { - let matPass = passes[j]; + for (let matPass of passes) { if (!matPass.enable) continue; - GPUContext.bindPipeline(encoder, matPass.renderShader); - GPUContext.draw(encoder, 6, 1, 0, worldMatrix.index); + if (matPass.renderShader.pipeline) { + GPUContext.bindPipeline(encoder, matPass.renderShader); + GPUContext.draw(encoder, 6, 1, 0, worldMatrix.index); + } } } else { GPUContext.bindGeometryBuffer(encoder, node._geometry); - for (let j = 0; j < passes.length; j++) { - let matPass = passes[j]; + for (let matPass of passes) { if (!matPass.enable) continue; - GPUContext.bindPipeline(encoder, matPass.renderShader); - let subGeometries = node._geometry.subGeometries; - const subGeometry = subGeometries[i]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[node.lodLevel]; - GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + + if (matPass.renderShader.pipeline) { + GPUContext.bindPipeline(encoder, matPass.renderShader); + let subGeometries = node._geometry.subGeometries; + const subGeometry = subGeometries[i]; + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[node.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } } } @@ -388,7 +393,7 @@ export class RenderNode extends ComponentBase { public recordRenderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { if (!this.enable) return; - this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); + // this.nodeUpdate(view, passType, rendererPassState, clusterLightingBuffer); let node = this; for (let i = 0; i < this.materials.length; i++) { @@ -408,43 +413,44 @@ export class RenderNode extends ComponentBase { GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); } } - } private noticeShaderChange() { if (this.enable) { this.onEnable(); + this.preInit = false; } } public nodeUpdate(view: View3D, passType: RendererType, renderPassState: RendererPassState, clusterLightingBuffer?: ClusterLightingBuffer) { - + this.preInit = true; let node = this; - for (let i = 0; i < this.materials.length; i++) { - let material = this.materials[i]; + let envMap = view.scene.envMap; + + for (let j = 0; j < node.materials.length; j++) { + let material = node.materials[j]; let passes = material.renderPasses.get(passType); if (passes) { for (let i = 0; i < passes.length; i++) { const pass = passes[i]; - // RenderShader.getShader(passes[i].shaderID); + const renderShader = pass.renderShader; - // RenderShader.getShader(passes[i].shaderID); + if (renderShader.shaderState.splitTexture) { - let splitTexture = RTResourceMap.CreateSplitTexture(this.instanceID); + let splitTexture = RTResourceMap.CreateSplitTexture(node.instanceID); renderShader.setTexture("splitTexture_Map", splitTexture); } - // renderShader.setUniformVector3("center", this.transform.worldPosition); - // if(scene3D.envMapChange){ - if (!this._ignoreEnvMap) { - renderShader.setTexture(`envMap`, view.scene.envMap); + + if (!node._ignoreEnvMap && renderShader.envMap != envMap) { + renderShader.setTexture(`envMap`, envMap); } - if (!this._ignorePrefilterMap) { - renderShader.setTexture(`prefilterMap`, view.scene.envMap); + + if (!node._ignorePrefilterMap && renderShader.prefilterMap != envMap) { + renderShader.setTexture(`prefilterMap`, envMap); } - // } if (renderShader.pipeline) { - renderShader.apply(this._geometry, pass, renderPassState, () => this.noticeShaderChange()); + renderShader.apply(node._geometry, pass, renderPassState, () => node.noticeShaderChange()); continue; } @@ -489,7 +495,8 @@ export class RenderNode extends ComponentBase { renderShader.setStorageBuffer(`clusterBuffer`, clusterLightingBuffer.clusterBuffer); } - renderShader.apply(this._geometry, pass, renderPassState); + renderShader.apply(node._geometry, pass, renderPassState); + } } } diff --git a/src/components/renderer/SkyRenderer.ts b/src/components/renderer/SkyRenderer.ts index 5c0faeca..5b077d3c 100644 --- a/src/components/renderer/SkyRenderer.ts +++ b/src/components/renderer/SkyRenderer.ts @@ -24,16 +24,14 @@ export class SkyRenderer extends MeshRenderer { */ public skyMaterial: SkyMaterial; - constructor() { - super(); + + public init(): void { + super.init(); this.castShadow = false; this.castGI = true; this.addRendererMask(RendererMask.Sky); this.alwaysRender = true; - } - public init(): void { - super.init(); this.object3D.bound = new BoundingBox(Vector3.ZERO.clone(), Vector3.MAX); this.geometry = new SphereGeometry(Engine3D.setting.sky.defaultFar, 20, 20); this.skyMaterial ||= new SkyMaterial(); @@ -60,7 +58,7 @@ export class SkyRenderer extends MeshRenderer { } public renderPass2(view: View3D, passType: RendererType, rendererPassState: RendererPassState, clusterLightingBuffer: ClusterLightingBuffer, encoder: GPURenderPassEncoder, useBundle: boolean = false) { - this.transform.updateWorldMatrix(); + // this.transform.updateWorldMatrix(); super.renderPass2(view, passType, rendererPassState, clusterLightingBuffer, encoder, useBundle); // this.transform.localPosition = Camera3D.mainCamera.transform.localPosition ; } diff --git a/src/core/Camera3D.ts b/src/core/Camera3D.ts index 1084ca45..ecd5d7e2 100644 --- a/src/core/Camera3D.ts +++ b/src/core/Camera3D.ts @@ -505,7 +505,7 @@ export class Camera3D extends ComponentBase { public getWorldDirection(target?: Vector3) { target ||= new Vector3(); - this.transform.updateWorldMatrix(); + // this.transform.updateWorldMatrix(); const e = this.transform._worldMatrix.rawData; return target.set(-e[8], -e[9], -e[10]).normalize(); } diff --git a/src/core/geometry/GeometryBase.ts b/src/core/geometry/GeometryBase.ts index 46f4f1a0..4aabb172 100644 --- a/src/core/geometry/GeometryBase.ts +++ b/src/core/geometry/GeometryBase.ts @@ -31,7 +31,7 @@ export class SubGeometry { */ export class GeometryBase { - public uuid: string; + public instanceID: string; public name: string; public subGeometries: SubGeometry[] = []; public morphTargetsRelative: boolean; @@ -43,7 +43,7 @@ export class GeometryBase { private _indicesBuffer: GeometryIndicesBuffer; private _vertexBuffer: GeometryVertexBuffer; constructor() { - this.uuid = UUID(); + this.instanceID = UUID(); this._attributeMap = new Map(); this._attributes = []; @@ -266,7 +266,7 @@ export class GeometryBase { } destroy(force?: boolean) { - this.uuid = null; + this.instanceID = null; this.name = null; this.subGeometries = null; this.morphTargetDictionary = null; diff --git a/src/core/geometry/GeometryVertexBuffer.ts b/src/core/geometry/GeometryVertexBuffer.ts index cf7c93a6..f204ab3d 100644 --- a/src/core/geometry/GeometryVertexBuffer.ts +++ b/src/core/geometry/GeometryVertexBuffer.ts @@ -91,6 +91,7 @@ export class GeometryVertexBuffer { for (let i = 0; i < shaderReflection.attributes.length; i++) { const attributeInfo = shaderReflection.attributes[i]; if (attributeInfo.name == `index`) continue; + if (attributeInfo.type == `builtin`) continue; this._attributeLocation[attributeInfo.name] = attributeInfo.location; let attributeLayout: VertexAttribute = { @@ -132,6 +133,7 @@ export class GeometryVertexBuffer { } public upload(attribute: string, vertexDataInfo: VertexAttributeData) { + if (!this.vertexGPUBuffer) return; switch (this.geometryType) { case GeometryVertexType.split: { diff --git a/src/core/geometry/VertexAttributeName.ts b/src/core/geometry/VertexAttributeName.ts index c4decd61..43c05ce6 100644 --- a/src/core/geometry/VertexAttributeName.ts +++ b/src/core/geometry/VertexAttributeName.ts @@ -13,6 +13,7 @@ export enum VertexAttributeName { joints1 = 'joints1', weights0 = 'weights0', weights1 = 'weights1', + weight = 'weight', indices = `indices`, vIndex = 'vIndex', a_morphPositions_0 = 'a_morphPositions_0', diff --git a/src/core/geometry/VertexAttributeStride.ts b/src/core/geometry/VertexAttributeStride.ts index 4c01520c..87c5323c 100644 --- a/src/core/geometry/VertexAttributeStride.ts +++ b/src/core/geometry/VertexAttributeStride.ts @@ -13,5 +13,6 @@ export enum VertexAttributeStride { joints1 = 4, weights1 = 4, vIndex = 1, + weight = 1, a_morphPositions_0 = 3, } diff --git a/src/gfx/graphics/webGpu/Context3D.ts b/src/gfx/graphics/webGpu/Context3D.ts index e89838d6..a36f4290 100644 --- a/src/gfx/graphics/webGpu/Context3D.ts +++ b/src/gfx/graphics/webGpu/Context3D.ts @@ -14,9 +14,10 @@ class Context3D { public windowHeight: number; public canvasConfig: CanvasConfig; public super: number = 1.0; + private _pixelRatio: number = 1.0; // initSize: number[]; public get pixelRatio() { - return this.canvasConfig?.devicePixelRatio || window.devicePixelRatio || 1 + return this._pixelRatio; } /** * Configure canvas by CanvasConfig @@ -25,18 +26,19 @@ class Context3D { */ async init(canvasConfig?: CanvasConfig): Promise { this.canvasConfig = canvasConfig; + if (canvasConfig && canvasConfig.canvas) { this.canvas = canvasConfig.canvas; if (this.canvas === null) throw new Error('no Canvas') - + // check if external canvas has initial with and height style const _width = this.canvas.clientWidth, _height = this.canvas.clientHeight this.resize(this.canvas.clientWidth, this.canvas.clientHeight) // set a initial style if size changed - if(_width != this.canvas.clientWidth) + if (_width != this.canvas.clientWidth) this.canvas.style.width = _width + 'px' - if(_height != this.canvas.clientHeight) + if (_height != this.canvas.clientHeight) this.canvas.style.width = _height + 'px' } else { this.canvas = document.createElement('canvas'); @@ -74,7 +76,14 @@ class Context3D { } // request device this.device = await this.adapter.requestDevice({ - //requiredFeatures: [`texture-compression-bc`], + requiredFeatures: [ + "bgra8unorm-storage", + "depth-clip-control", + "depth32float-stencil8", + "indirect-first-instance", + "rg11b10ufloat-renderable", + "texture-compression-bc" + ], requiredLimits: { minUniformBufferOffsetAlignment: 256, maxStorageBufferBindingSize: this.adapter.limits.maxStorageBufferBindingSize @@ -84,6 +93,9 @@ class Context3D { throw new Error('Your browser does not support WebGPU!'); } + this._pixelRatio = this.canvasConfig?.devicePixelRatio || window.devicePixelRatio || 1; + this._pixelRatio = Math.min(this._pixelRatio, 2.0); + // configure webgpu context this.device.label = 'device'; this.presentationFormat = navigator.gpu.getPreferredCanvasFormat(); @@ -93,7 +105,7 @@ class Context3D { format: this.presentationFormat, usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT, alphaMode: 'premultiplied', - colorSpace: `display-p3` + colorSpace: `display-p3`, }); // resize canvas size, aspect diff --git a/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts index e890e1c5..338086cb 100644 --- a/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/GlobalUniformGroup.ts @@ -74,7 +74,7 @@ export class GlobalUniformGroup { // } public setCamera(camera: Camera3D) { - camera.transform.updateWorldMatrix(true); + // camera.transform.updateWorldMatrix(true); this.uniformGPUBuffer.setMatrix(`_projectionMatrix`, camera.projectionMatrix); this.uniformGPUBuffer.setMatrix(`_viewMatrix`, camera.viewMatrix); this.uniformGPUBuffer.setMatrix(`_cameraWorldMatrix`, camera.transform.worldMatrix); @@ -92,9 +92,9 @@ export class GlobalUniformGroup { this.uniformGPUBuffer.setFloat32Array(`_shadowCamera`, raw); this.uniformGPUBuffer.setVector3(`CameraPos`, camera.transform.worldPosition); - this.uniformGPUBuffer.setFloat(`Time.frame`, Time.frame); - this.uniformGPUBuffer.setFloat(`Time.time`, Time.frame); - this.uniformGPUBuffer.setFloat(`Time.detail`, Time.delta); + this.uniformGPUBuffer.setFloat(`frame`, Time.frame); + this.uniformGPUBuffer.setFloat(`time`, Time.frame); + this.uniformGPUBuffer.setFloat(`delta`, Time.delta); this.uniformGPUBuffer.setFloat(`EngineSetting.Shadow.shadowBias`, Engine3D.setting.shadow.shadowBias); this.uniformGPUBuffer.setFloat(`skyExposure`, Engine3D.setting.sky.skyExposure); this.uniformGPUBuffer.setFloat(`EngineSetting.Render.renderPassState`, Engine3D.setting.render.renderPassState); @@ -121,10 +121,49 @@ export class GlobalUniformGroup { } setShadowCamera(camera: Camera3D) { - camera.transform.updateWorldMatrix(true); + // camera.transform.updateWorldMatrix(true); this.uniformGPUBuffer.setMatrix(`_projectionMatrix`, camera.projectionMatrix); this.uniformGPUBuffer.setMatrix(`_viewMatrix`, camera.viewMatrix); this.uniformGPUBuffer.setMatrix(`_pvMatrix`, camera.pvMatrix); + this.uniformGPUBuffer.setMatrix(`_projectionMatrixInv`, camera.projectionMatrixInv); + let raw = new Float32Array(8 * 16); + for (let i = 0; i < 8; i++) { + let shadowLightList = ShadowLightsCollect.getDirectShadowLightWhichScene(camera.transform.scene3D); + if (i < shadowLightList.length) { + let mat = shadowLightList[i].shadowCamera.pvMatrix.rawData; + raw.set(mat, i * 16); + } else { + raw.set(camera.transform.worldMatrix.rawData, i * 16); + } + } + this.uniformGPUBuffer.setFloat32Array(`_shadowCamera`, raw); + this.uniformGPUBuffer.setVector3(`CameraPos`, camera.transform.worldPosition); + + this.uniformGPUBuffer.setFloat(`frame`, Time.frame); + this.uniformGPUBuffer.setFloat(`time`, Time.frame); + this.uniformGPUBuffer.setFloat(`delta`, Time.delta); + this.uniformGPUBuffer.setFloat(`EngineSetting.Shadow.shadowBias`, Engine3D.setting.shadow.shadowBias); + this.uniformGPUBuffer.setFloat(`skyExposure`, Engine3D.setting.sky.skyExposure); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.renderPassState`, Engine3D.setting.render.renderPassState); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.quadScale`, Engine3D.setting.render.quadScale); + this.uniformGPUBuffer.setFloat(`EngineSetting.Render.hdrExposure`, Engine3D.setting.render.hdrExposure); + + this.uniformGPUBuffer.setInt32(`renderState_left`, Engine3D.setting.render.renderState_left); + this.uniformGPUBuffer.setInt32(`renderState_right`, Engine3D.setting.render.renderState_right); + this.uniformGPUBuffer.setFloat(`renderState_split`, Engine3D.setting.render.renderState_split); + + let mouseX = Engine3D.inputSystem.mouseX * webGPUContext.pixelRatio; + let mouseY = Engine3D.inputSystem.mouseY * webGPUContext.pixelRatio; + this.uniformGPUBuffer.setFloat(`mouseX`, mouseX); + this.uniformGPUBuffer.setFloat(`mouseY`, mouseY); + this.uniformGPUBuffer.setFloat(`windowWidth`, webGPUContext.windowWidth); + this.uniformGPUBuffer.setFloat(`windowHeight`, webGPUContext.windowHeight); + this.uniformGPUBuffer.setFloat(`near`, camera.near); + this.uniformGPUBuffer.setFloat(`far`, camera.far); + + this.uniformGPUBuffer.setFloat(`EngineSetting.Shadow.pointShadowBias`, Engine3D.setting.shadow.pointShadowBias); + this.uniformGPUBuffer.setFloat(`shadowMapSize`, Engine3D.setting.shadow.shadowSize); + this.uniformGPUBuffer.setFloat(`shadowSoft`, Engine3D.setting.shadow.shadowSoft); this.uniformGPUBuffer.apply(); } diff --git a/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts b/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts index dbefda97..a9df77dc 100644 --- a/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts +++ b/src/gfx/graphics/webGpu/core/bindGroups/MatrixBindGroup.ts @@ -1,6 +1,7 @@ import { Matrix4 } from '../../../../../math/Matrix4'; import { UUID } from '../../../../../util/Global'; import { webGPUContext } from '../../Context3D'; +import { MatrixGPUBuffer } from '../buffer/MatrixGPUBuffer'; import { StorageGPUBuffer } from '../buffer/StorageGPUBuffer'; /** * @author sirxu @@ -12,7 +13,7 @@ export class MatrixBindGroup { public index: number; public usage: number; public groupBufferSize: number; - public matrixBufferDst: StorageGPUBuffer; + public matrixBufferDst: MatrixGPUBuffer; constructor() { this.uuid = UUID(); this.groupBufferSize = 0; @@ -23,21 +24,34 @@ export class MatrixBindGroup { private cacheWorldMatrix() { this.groupBufferSize = Matrix4.maxCount * Matrix4.blockBytes; - this.matrixBufferDst = new StorageGPUBuffer(this.groupBufferSize / 4); + this.matrixBufferDst = new MatrixGPUBuffer(this.groupBufferSize / 4); this.matrixBufferDst.visibility = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE this.matrixBufferDst.buffer.label = this.groupBufferSize.toString(); } writeBuffer() { - const matBytes = Matrix4.matrixBytes; - let totalBytes = matBytes.byteLength; - let offsetBytes = 0; - - const space = 5000 * 64; - while (offsetBytes < totalBytes) { - let len = Math.min(space, totalBytes - offsetBytes); - webGPUContext.device.queue.writeBuffer(this.matrixBufferDst.buffer, offsetBytes, matBytes.buffer, matBytes.byteOffset + offsetBytes, len); - offsetBytes += len; - } + const matBytes = Matrix4.dynamicMatrixBytes; + this.matrixBufferDst.writeToGpu(matBytes); } + + // writeBuffer() { + // const matBytes = Matrix4.dynamicMatrixBytes; + // let totalBytes = matBytes.byteLength; + // let offsetBytes = 0; + + // const space = 5000 * 64; + // while (offsetBytes < totalBytes) { + // let len = Math.min(space, totalBytes - offsetBytes); + // webGPUContext.device.queue.writeBuffer(this.matrixBufferDst.buffer, offsetBytes, matBytes.buffer, matBytes.byteOffset + offsetBytes, len); + // offsetBytes += len; + // } + // } + + // public async mapAsync() { + // await this.matrixBufferDst.buffer.mapAsync(GPUMapMode.WRITE); + + // const matBytes = Matrix4.dynamicMatrixBytes; + // new Float32Array(this.matrixBufferDst.buffer.getMappedRange()).set(matBytes); + // this.matrixBufferDst.buffer.unmap(); + // } } diff --git a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts index 154e9de5..46f663a7 100644 --- a/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts +++ b/src/gfx/graphics/webGpu/core/buffer/GPUBufferBase.ts @@ -27,10 +27,13 @@ export class GPUBufferBase { public usage: GPUBufferUsageFlags; public visibility: number = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE; private _readBuffer: GPUBuffer; + private _dataView: Float32Array; constructor() { this.memory = new MemoryDO(); this.memoryNodes = new Map(); + + this._dataView = new Float32Array(this.memory.shareDataBuffer); } public debug() { @@ -295,14 +298,21 @@ export class GPUBufferBase { // } public clean() { - let data = new Float32Array(this.memory.shareDataBuffer); - data.fill(0, 0, data.length); + // this._dataView = new Float32Array(this.memory.shareDataBuffer); + this._dataView.fill(0, 0, this._dataView.length); } public apply() { webGPUContext.device.queue.writeBuffer(this.buffer, 0, this.memory.shareDataBuffer);//, this.memory.shareFloat32Array.byteOffset, this.memory.shareFloat32Array.byteLength); } + public async mapAsync() { + await this.buffer.mapAsync(GPUMapMode.WRITE); + let data = new Float32Array(this.memory.shareDataBuffer); + new Float32Array(this.buffer.getMappedRange()).set(data); + this.buffer.unmap(); + } + public destroy(force?: boolean) { if (this.memoryNodes) { this.memoryNodes.forEach((v) => { diff --git a/src/gfx/graphics/webGpu/core/buffer/MatrixGPUBuffer.ts b/src/gfx/graphics/webGpu/core/buffer/MatrixGPUBuffer.ts new file mode 100644 index 00000000..4f04f982 --- /dev/null +++ b/src/gfx/graphics/webGpu/core/buffer/MatrixGPUBuffer.ts @@ -0,0 +1,65 @@ +import { webGPUContext } from '../../Context3D'; +import { ArrayBufferData } from './ArrayBufferData'; +import { GPUBufferBase } from './GPUBufferBase'; +import { GPUBufferType } from './GPUBufferType'; +/** + * The buffer of the storage class + * written in the computer shader or CPU Coder + * usage GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST + * @group GFX + */ +export class MatrixGPUBuffer extends GPUBufferBase { + + private mapAsyncBuffersOutstanding = 0; + private mapAsyncReady: GPUBuffer[]; + + constructor(size: number, usage: number = 0, data?: ArrayBufferData) { + super(); + this.bufferType = GPUBufferType.StorageGPUBuffer; + this.mapAsyncReady = []; + this.createBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | usage, size, data); + } + + public writeToGpu(mapAsyncArray: Float32Array) { + // Upload data using mapAsync and a queue of staging buffers. + let device = webGPUContext.device; + if (mapAsyncArray.length > 0) { + // if (this.mapAsyncBufferSize != mapAsyncArray.byteLength) { + // this.mapAsyncBufferSize = mapAsyncArray.byteLength; + // if (this.buffer) this.buffer.destroy(); + // this.buffer = device.createBuffer({ size: mapAsyncArray.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST }); + // } + let buffer: GPUBuffer = null; + while (this.mapAsyncReady.length) { + buffer = this.mapAsyncReady.shift(); + if (buffer['usedSize'] == mapAsyncArray.byteLength) + break; + buffer.destroy(); + this.mapAsyncBuffersOutstanding--; + buffer = null; + } + if (!buffer) { + buffer = device.createBuffer({ + size: mapAsyncArray.byteLength, + usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.MAP_WRITE, + mappedAtCreation: true, + }); + buffer['usedSize'] = mapAsyncArray.byteLength; + this.mapAsyncBuffersOutstanding++; + if (this.mapAsyncBuffersOutstanding > 10) { + // ${(this.mapAsync.value * this.mapAsyncBuffersOutstanding).toFixed(2)} + console.warn(` Warning: mapAsync requests from ${this.mapAsyncBuffersOutstanding} frames ago have not resolved yet. MB of staging buffers allocated.`); + } + } + new Float32Array(buffer.getMappedRange()).set(mapAsyncArray); + buffer.unmap(); + const commandEncoder = device.createCommandEncoder(); + commandEncoder.copyBufferToBuffer(buffer, 0, this.buffer, 0, mapAsyncArray.byteLength); + // TODO: combine this submit with the main one, but we'll have to delay calling mapAsync until after the submit. + device.queue.submit([commandEncoder.finish()]); + // TODO: use this data during rendering. + buffer.mapAsync(GPUMapMode.WRITE).then(() => this.mapAsyncReady.push(buffer)); + } + } +} + diff --git a/src/gfx/graphics/webGpu/core/texture/Texture.ts b/src/gfx/graphics/webGpu/core/texture/Texture.ts index 8d3b90ee..19ef4e9a 100644 --- a/src/gfx/graphics/webGpu/core/texture/Texture.ts +++ b/src/gfx/graphics/webGpu/core/texture/Texture.ts @@ -344,6 +344,10 @@ export class Texture implements GPUSamplerDescriptor { this.noticeChange(); } + public get sourceImageData() { + return this._sourceImageData; + } + protected updateTextureDescription() { // let mipmapCount = this.useMipmap ? Math.floor(Math.log2(this.width)) : 1; this.mipmapCount = Math.floor(this.useMipmap ? Math.log2(Math.min(this.width, this.height)) : 1); diff --git a/src/gfx/graphics/webGpu/shader/RenderShader.ts b/src/gfx/graphics/webGpu/shader/RenderShader.ts index 34d81aaa..c13fe1ea 100644 --- a/src/gfx/graphics/webGpu/shader/RenderShader.ts +++ b/src/gfx/graphics/webGpu/shader/RenderShader.ts @@ -274,12 +274,20 @@ export class RenderShader extends ShaderBase { } this._textureChange = true; this.textures[name] = texture; + if (name == "envMap") { + this.envMap = texture; + } else if (name == "prefilterMap") { + this.prefilterMap = texture; + } texture.bindStateChange(() => { this._textureChange = true; }, this); } } + public envMap: Texture; + public prefilterMap: Texture; + /** * Get the texture used in the Render Shader code * @param name Name in the shader code diff --git a/src/gfx/graphics/webGpu/shader/ShaderBase.ts b/src/gfx/graphics/webGpu/shader/ShaderBase.ts index aec68958..9d5bdc62 100644 --- a/src/gfx/graphics/webGpu/shader/ShaderBase.ts +++ b/src/gfx/graphics/webGpu/shader/ShaderBase.ts @@ -59,7 +59,7 @@ export class ShaderBase { public uniforms: { [name: string]: UniformNode }; protected _bufferDic: Map; - protected _shaderChange: boolean = false; + protected _shaderChange: boolean = true; protected _stateChange: boolean = false; constructor() { @@ -132,8 +132,13 @@ export class ShaderBase { * @param value */ public setDefine(defineName: string, value: any) { + if (this.defineValue[defineName] == null || this.defineValue[defineName] != value) { + this.defineValue[defineName] = value; + this.noticeStateChange(); + this.noticeShaderChange(); + // console.log("USE_CLEARCOAT"); + } this.defineValue[defineName] = value; - this.noticeShaderChange(); } /** diff --git a/src/gfx/renderJob/collect/ComponentCollect.ts b/src/gfx/renderJob/collect/ComponentCollect.ts index ef56fe8f..3ba59db9 100644 --- a/src/gfx/renderJob/collect/ComponentCollect.ts +++ b/src/gfx/renderJob/collect/ComponentCollect.ts @@ -1,3 +1,4 @@ +import { ColliderComponent } from "../../.."; import { IComponent } from "../../../components/IComponent"; import { View3D } from "../../../core/View3D"; import { Object3D } from "../../../core/entities/Object3D"; @@ -24,6 +25,11 @@ export class ComponentCollect { */ public static componentsComputeList: Map>; + /** + * @internal + */ + public static componentsEnablePickerList: Map>; + /** * @internal */ @@ -43,6 +49,7 @@ export class ComponentCollect { ComponentCollect.componentsLateUpdateList = new Map>(); ComponentCollect.componentsBeforeUpdateList = new Map>(); ComponentCollect.componentsComputeList = new Map>(); + ComponentCollect.componentsEnablePickerList = new Map>(); ComponentCollect.graphicComponent = new Map>(); ComponentCollect.waitStartComponent = new Map(); } @@ -150,4 +157,22 @@ export class ComponentCollect { } } } + + public static bindEnablePick(view: View3D, component: ColliderComponent, call: Function) { + this.init(); + let list = ComponentCollect.componentsEnablePickerList.get(view); + if (!list) { + list = new Map(); + ComponentCollect.componentsEnablePickerList.set(view, list); + } + list.set(component, call); + } + + public static unBindEnablePick(view: View3D, component: ColliderComponent) { + this.init(); + let list = ComponentCollect.componentsEnablePickerList.get(view); + if (list) { + list.delete(component); + } + } } diff --git a/src/gfx/renderJob/collect/EntityBatchCollect.ts b/src/gfx/renderJob/collect/EntityBatchCollect.ts index e13790ff..7977d0ee 100644 --- a/src/gfx/renderJob/collect/EntityBatchCollect.ts +++ b/src/gfx/renderJob/collect/EntityBatchCollect.ts @@ -15,7 +15,7 @@ export class EntityBatchCollect { public collect_add(node: RenderNode) { let g_key = ''; let s_key = ''; - g_key += node.geometry.uuid; + g_key += node.geometry.instanceID; for (let i = 0; i < node.materials.length; i++) { const mat = node.materials[i]; s_key += mat.renderShader.shaderVariant; diff --git a/src/gfx/renderJob/collect/EntityCollect.ts b/src/gfx/renderJob/collect/EntityCollect.ts index 32b652f0..851b1cf4 100644 --- a/src/gfx/renderJob/collect/EntityCollect.ts +++ b/src/gfx/renderJob/collect/EntityCollect.ts @@ -1,4 +1,5 @@ +import { View3D } from '../../..'; import { Engine3D } from '../../../Engine3D'; import { ILight } from '../../../components/lights/ILight'; import { RenderNode } from '../../../components/renderer/RenderNode'; @@ -10,6 +11,7 @@ import { Graphic3DBatchRenderer } from '../passRenderer/graphic/Graphic3DBatchRe import { RendererMask } from '../passRenderer/state/RendererMask'; import { CollectInfo } from './CollectInfo'; import { EntityBatchCollect } from './EntityBatchCollect'; +import { RenderShaderCollect } from './RenderShaderCollect'; /** * @internal @@ -28,6 +30,8 @@ export class EntityCollect { private _op_renderGroup: Map; private _tr_renderGroup: Map; + private _renderShaderCollect: RenderShaderCollect; + public state: { /** * gi effect lighting change @@ -63,6 +67,7 @@ export class EntityCollect { this._tr_renderGroup = new Map(); this._collectInfo = new CollectInfo(); + this._renderShaderCollect = new RenderShaderCollect(); } private getPashList(root: Scene3D, renderNode: RenderNode) { @@ -127,6 +132,8 @@ export class EntityCollect { } } renderNode.object3D.renderNode = renderNode; + + this._renderShaderCollect.collect_add(renderNode); } public removeRenderNode(root: Scene3D, renderNode: RenderNode) { @@ -143,6 +150,8 @@ export class EntityCollect { } } } + + this._renderShaderCollect.collect_remove(renderNode); } public addLight(root: Scene3D, light: ILight) { @@ -259,4 +268,9 @@ export class EntityCollect { public getGraphicList(): Graphic3DBatchRenderer[] { return this._graphics; } + + public getRenderShaderCollect(view: View3D) { + let viewList = this._renderShaderCollect.renderShaderUpdateList.get(view) || []; + return viewList; + } } diff --git a/src/gfx/renderJob/collect/RenderShaderCollect.ts b/src/gfx/renderJob/collect/RenderShaderCollect.ts new file mode 100644 index 00000000..fa7ae373 --- /dev/null +++ b/src/gfx/renderJob/collect/RenderShaderCollect.ts @@ -0,0 +1,61 @@ +import { GeometryBase, MaterialBase, MaterialPass, RenderNode, RenderShader, View3D } from "../../.."; + + +export type RenderShaderList = Map>; + +export class RenderShaderCollect { + public renderShaderUpdateList: Map = new Map(); + public renderNodeList: Map> = new Map>(); + + public collect_add(node: RenderNode) { + let view = node.transform.view3D; + if (view && node.materials) { + node.materials.forEach((mat) => { + let rDic = this.renderShaderUpdateList.get(view); + if (!rDic) { + rDic = new Map>(); + this.renderShaderUpdateList.set(view, rDic); + } + + let renderGlobalMap = this.renderNodeList.get(view); + if (!renderGlobalMap) { + renderGlobalMap = new Map(); + this.renderNodeList.set(view, renderGlobalMap); + } + renderGlobalMap.set(node.instanceID, node); + + mat.renderPasses.forEach((v) => { + v.forEach((pass) => { + let key = `${node.geometry.instanceID + pass.renderShader.instanceID}` + let nodeMap = rDic.get(key); + if (!nodeMap) { + nodeMap = new Map(); + rDic.set(key, nodeMap); + } + nodeMap.set(node.instanceID, node); + }) + }); + }); + } + } + + public collect_remove(node: RenderNode) { + let view = node.transform.view3D; + if (view && node.materials) { + let rDic = this.renderShaderUpdateList.get(view); + if (rDic) { + node.materials.forEach((mat) => { + mat.renderPasses.forEach((v) => { + v.forEach((pass) => { + let key = `${node.geometry.instanceID + pass.renderShader.instanceID}` + let nodeMap = rDic.get(key); + if (nodeMap) { + nodeMap.delete(node.instanceID); + } + }) + }); + }); + } + } + } +} \ No newline at end of file diff --git a/src/gfx/renderJob/collect/ShadowLightsCollect.ts b/src/gfx/renderJob/collect/ShadowLightsCollect.ts index 7d8b695a..53f4b47b 100644 --- a/src/gfx/renderJob/collect/ShadowLightsCollect.ts +++ b/src/gfx/renderJob/collect/ShadowLightsCollect.ts @@ -192,7 +192,7 @@ export class ShadowLightsCollect { let nDirShadowEnd: number = 0; let nPointShadowStart: number = 0; let nPointShadowEnd: number = 0; - shadowLights.fill(-1); + shadowLights.fill(0); if (directionLightList) { for (let i = 0; i < directionLightList.length; i++) { const light = directionLightList[i]; diff --git a/src/gfx/renderJob/occlusion/OcclusionSystem.ts b/src/gfx/renderJob/occlusion/OcclusionSystem.ts index 401f7896..5e873fee 100644 --- a/src/gfx/renderJob/occlusion/OcclusionSystem.ts +++ b/src/gfx/renderJob/occlusion/OcclusionSystem.ts @@ -10,8 +10,9 @@ import { EntityCollect } from '../collect/EntityCollect'; export class OcclusionSystem { public frustumCullingList: Float32Array; public zVisibleList: Float32Array; + private _renderList: Map>; - private _renderList: Map> + public static enable = true; constructor() { this._renderList = new Map>(); @@ -45,6 +46,7 @@ export class OcclusionSystem { } public update(camera: Camera3D, scene: Scene3D) { + if (!OcclusionSystem.enable) return; let cameraViewRenderList = this._renderList.get(camera); if (!cameraViewRenderList) { cameraViewRenderList = new Map(); @@ -53,44 +55,38 @@ export class OcclusionSystem { cameraViewRenderList.clear(); EntityCollect.instance.autoSortRenderNodes(scene); let nodes = EntityCollect.instance.getRenderNodes(scene); - // for (let i = 0; i < nodes.opaqueList.length; i++) { - // const node = nodes.opaqueList[i]; - // if(node.object3D.transform[`_localChange`]) - // node.object3D.transform.updateWorldMatrix(); - // } - // for (let i = 0; i < nodes.transparentList.length; i++) { - // const node = nodes.transparentList[i]; - // if(node.object3D.transform[`_localChange`]) - // node.object3D.transform.updateWorldMatrix(); - // } - for (let i = 0; i < nodes.opaqueList.length; i++) { - const node = nodes.opaqueList[i]; - let inRender = 0; + if (nodes.opaqueList) { + for (let node of nodes.opaqueList) { + let inRender = 0; - if (node.enable && node.transform.enable && node.object3D.bound) { - inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); - } + if (node.enable && node.transform.enable && node.object3D.bound) { + inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); + } - if (inRender) { - cameraViewRenderList.set(node, inRender); + if (inRender) { + cameraViewRenderList.set(node, inRender); + } } } - for (let i = 0; i < nodes.transparentList.length; i++) { - const node = nodes.transparentList[i]; - let inRender = 0; - if (node.enable && node.transform.enable && node.object3D.bound) { - inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); - } + if (nodes.transparentList) { + for (let node of nodes.transparentList) { + + let inRender = 0; + if (node.enable && node.transform.enable && node.object3D.bound) { + inRender = node.object3D.bound.containsFrustum(node.object3D, camera.frustum); + } - if (inRender) { - cameraViewRenderList.set(node, inRender); + if (inRender) { + cameraViewRenderList.set(node, inRender); + } } } } renderCommitTesting(camera: Camera3D, renderNode: RenderNode): boolean { + if (!OcclusionSystem.enable) return true; let cameraRenderList = this._renderList.get(camera); if (cameraRenderList) { return this._renderList.get(camera).get(renderNode) > 0; diff --git a/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts b/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts index c79879a5..37054cbb 100644 --- a/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts +++ b/src/gfx/renderJob/passRenderer/color/ColorPassRenderer.ts @@ -4,6 +4,7 @@ import { View3D } from "../../../../core/View3D"; import { ProfilerUtil } from "../../../../util/ProfilerUtil"; import { GPUContext } from "../../GPUContext"; import { EntityCollect } from "../../collect/EntityCollect"; +import { RenderShaderCollect } from "../../collect/RenderShaderCollect"; import { OcclusionSystem } from "../../occlusion/OcclusionSystem"; import { RenderContext } from "../RenderContext"; import { RendererBase } from "../RendererBase"; @@ -55,25 +56,30 @@ export class ColorPassRenderer extends RendererBase { if (op_bundleList.length > 0) { // GPUContext.bindCamera(renderPassEncoder,camera); let entityBatchCollect = EntityCollect.instance.getOpRenderGroup(scene); - entityBatchCollect.renderGroup.forEach((group) => { - for (let i = 0; i < group.renderNodes.length; i++) { - const node = group.renderNodes[i]; - node.transform.updateWorldMatrix(); - } - }); + // entityBatchCollect.renderGroup.forEach((group) => { + // for (let i = 0; i < group.renderNodes.length; i++) { + // const node = group.renderNodes[i]; + // node.transform.updateWorldMatrix(); + // } + // }); renderPassEncoder.executeBundles(op_bundleList); } if (!maskTr && EntityCollect.instance.sky) { GPUContext.bindCamera(renderPassEncoder, camera); + if (!EntityCollect.instance.sky.preInit) { + EntityCollect.instance.sky.nodeUpdate(view, this._rendererType, this.rendererPassState, clusterLightingBuffer); + } EntityCollect.instance.sky.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, renderPassEncoder); } - GPUContext.bindCamera(renderPassEncoder, camera); - this.drawNodes(view, this.renderContext, collectInfo.opaqueList, occlusionSystem, clusterLightingBuffer); - this.renderContext.endRenderPass(); - ProfilerUtil.end("ColorPass Draw Opaque"); + if (collectInfo.opaqueList) { + GPUContext.bindCamera(renderPassEncoder, camera); + this.drawNodes(view, this.renderContext, collectInfo.opaqueList, occlusionSystem, clusterLightingBuffer); + this.renderContext.endRenderPass(); + ProfilerUtil.end("ColorPass Draw Opaque"); + } } { @@ -88,7 +94,7 @@ export class ColorPassRenderer extends RendererBase { renderPassEncoder.executeBundles(tr_bundleList); } - if (!maskTr) { + if (!maskTr && collectInfo.transparentList) { GPUContext.bindCamera(renderPassEncoder, camera); this.drawNodes(view, this.renderContext, collectInfo.transparentList, occlusionSystem, clusterLightingBuffer); } @@ -102,6 +108,7 @@ export class ColorPassRenderer extends RendererBase { } this.renderContext.endRenderPass(); + ProfilerUtil.end("ColorPass Draw Transparent"); } @@ -110,6 +117,18 @@ export class ColorPassRenderer extends RendererBase { public drawNodes(view: View3D, renderContext: RenderContext, nodes: RenderNode[], occlusionSystem: OcclusionSystem, clusterLightingBuffer: ClusterLightingBuffer) { { + let viewRenderList = EntityCollect.instance.getRenderShaderCollect(view); + for (const renderList of viewRenderList) { + let nodeMap = renderList[1]; + for (const iterator of nodeMap) { + let node = iterator[1]; + if (node.preInit) { + node.nodeUpdate(view, this._rendererType, this.rendererPassState, clusterLightingBuffer); + break; + } + } + } + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { let renderNode = nodes[i]; if (!occlusionSystem.renderCommitTesting(view.camera, renderNode)) @@ -119,7 +138,9 @@ export class ColorPassRenderer extends RendererBase { if (!renderNode.enable) continue; - renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState, clusterLightingBuffer); + if (!renderNode.preInit) { + renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState, clusterLightingBuffer); + } renderNode.renderPass(view, this.passType, this.renderContext); } } diff --git a/src/gfx/renderJob/passRenderer/ddgi/DDGIProbeRenderer.ts b/src/gfx/renderJob/passRenderer/ddgi/DDGIProbeRenderer.ts index 194168ce..b9036f13 100644 --- a/src/gfx/renderJob/passRenderer/ddgi/DDGIProbeRenderer.ts +++ b/src/gfx/renderJob/passRenderer/ddgi/DDGIProbeRenderer.ts @@ -193,15 +193,34 @@ export class DDGIProbeRenderer extends RendererBase { let drawMin = Math.max(0, Engine3D.setting.render.drawOpMin); let drawMax = Math.min(Engine3D.setting.render.drawOpMax, collectInfo.opaqueList.length); + let viewRenderList = EntityCollect.instance.getRenderShaderCollect(view); + for (const renderList of viewRenderList) { + let nodeMap = renderList[1]; + for (const iterator of nodeMap) { + let node = iterator[1]; + if (node.preInit) { + node.nodeUpdate(view, this.passType, this.rendererPassState, null); + break; + } + } + } + for (let i = drawMin; i < drawMax; ++i) { let renderNode = collectInfo.opaqueList[i]; if (renderNode.enable && renderNode.transform.enable) { + if (!renderNode.preInit) { + renderNode.nodeUpdate(view, this.passType, this.rendererPassState, null); + } renderNode.renderPass2(view, this.passType, this.rendererPassState, null, encoder); } } - if (EntityCollect.instance.sky) + if (EntityCollect.instance.sky) { + if (!EntityCollect.instance.sky.preInit) { + EntityCollect.instance.sky.nodeUpdate(view, this.passType, this.rendererPassState, null); + } EntityCollect.instance.sky.renderPass2(view, this.passType, this.rendererPassState, null, encoder); + } drawMin = Math.max(0, Engine3D.setting.render.drawTrMin); drawMax = Math.min(Engine3D.setting.render.drawTrMax, collectInfo.transparentList.length); @@ -209,6 +228,9 @@ export class DDGIProbeRenderer extends RendererBase { for (let i = drawMin; i < drawMax; ++i) { let renderNode = collectInfo.transparentList[i]; if (renderNode.enable && renderNode.transform.enable) { + if (!renderNode.preInit) { + renderNode.nodeUpdate(view, this.passType, this.rendererPassState, null); + } renderNode.renderPass2(view, this.passType, this.rendererPassState, null, encoder); } } @@ -223,8 +245,10 @@ export class DDGIProbeRenderer extends RendererBase { this.volume.isVolumeFrameChange = false; this.volume.uploadBuffer(); - let sky = EntityCollect.instance.sky; - sky && sky.nodeUpdate(view, this.passType, this.rendererPassState, null); + // let sky = EntityCollect.instance.sky; + // if (sky && !sky.preInit) { + // sky.nodeUpdate(view, this.passType, this.rendererPassState, null); + // } this.rendProbe(view); let probeBeRendered = this.probeRenderResult.count > 0; diff --git a/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts b/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts index 753f8911..630b59fa 100644 --- a/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts +++ b/src/gfx/renderJob/passRenderer/shadow/PointLightShadowRenderer.ts @@ -183,6 +183,18 @@ export class PointLightShadowRenderer extends RendererBase { shadowCamera.onUpdate(); shadowCamera.transform.updateWorldMatrix(true); + let viewRenderList = EntityCollect.instance.getRenderShaderCollect(view); + for (const renderList of viewRenderList) { + let nodeMap = renderList[1]; + for (const iterator of nodeMap) { + let node = iterator[1]; + if (node.preInit) { + node.nodeUpdate(view, this._rendererType, this.rendererPassState, null); + break; + } + } + } + this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.opaqueList, occlusionSystem); this.drawShadowRenderNodes(view, shadowCamera, encoder, collectInfo.transparentList, occlusionSystem); @@ -192,39 +204,40 @@ export class PointLightShadowRenderer extends RendererBase { protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[], occlusionSystem: OcclusionSystem) { GPUContext.bindCamera(encoder, shadowCamera); - for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { - let renderNode = nodes[i]; - let matrixIndex = renderNode.transform.worldMatrix.index; - if (!renderNode.transform.enable) - continue; - if (!occlusionSystem.renderCommitTesting(shadowCamera, renderNode)) - continue; - if (!renderNode.enable) - continue; - renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState); - - for (let i = 0; i < renderNode.materials.length; i++) { - const material = renderNode.materials[i]; - let passes = material.renderPasses.get(this._rendererType); - if (!passes || passes.length == 0) + if (nodes) { + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + let matrixIndex = renderNode.transform.worldMatrix.index; + if (!renderNode.transform.enable) continue; - - GPUContext.bindGeometryBuffer(encoder, renderNode.geometry); - let worldMatrix = renderNode.object3D.transform._worldMatrix; - for (let i = 0; i < passes.length; i++) { - const renderShader = passes[i].renderShader; - - renderShader.setUniformFloat("cameraFar", shadowCamera.far); - renderShader.setUniformVector3("lightWorldPos", shadowCamera.transform.worldPosition); - renderShader.materialDataUniformBuffer.apply(); - - GPUContext.bindPipeline(encoder, renderShader); - let subGeometries = renderNode.geometry.subGeometries; - for (let k = 0; k < subGeometries.length; k++) { - const subGeometry = subGeometries[k]; - let lodInfos = subGeometry.lodLevels; - let lodInfo = lodInfos[renderNode.lodLevel]; - GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + if (!occlusionSystem.renderCommitTesting(shadowCamera, renderNode)) + continue; + if (!renderNode.enable) + continue; + // renderNode.nodeUpdate(view, this._rendererType, this.rendererPassState); + + for (let material of renderNode.materials) { + let passes = material.renderPasses.get(this._rendererType); + if (!passes || passes.length == 0) + continue; + + GPUContext.bindGeometryBuffer(encoder, renderNode.geometry); + let worldMatrix = renderNode.object3D.transform._worldMatrix; + for (let pass of passes) { + const renderShader = pass.renderShader; + if (renderShader.pipeline) { + renderShader.setUniformFloat("cameraFar", shadowCamera.far); + renderShader.setUniformVector3("lightWorldPos", shadowCamera.transform.worldPosition); + renderShader.materialDataUniformBuffer.apply(); + + GPUContext.bindPipeline(encoder, renderShader); + let subGeometries = renderNode.geometry.subGeometries; + for (const subGeometry of subGeometries) { + let lodInfos = subGeometry.lodLevels; + let lodInfo = lodInfos[renderNode.lodLevel]; + GPUContext.drawIndexed(encoder, lodInfo.indexCount, 1, lodInfo.indexStart, 0, worldMatrix.index); + } + } } } } diff --git a/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts b/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts index e0353372..dcbf88aa 100644 --- a/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts +++ b/src/gfx/renderJob/passRenderer/shadow/ShadowMapPassRenderer.ts @@ -78,6 +78,10 @@ export class ShadowMapPassRenderer extends RendererBase { return; camera.transform.updateWorldMatrix(); + + + + //*********************/ //***shadow light******/ //*********************/ @@ -89,6 +93,18 @@ export class ShadowMapPassRenderer extends RendererBase { continue; this.rendererPassState = this.rendererPassStates[light.shadowIndex]; + let viewRenderList = EntityCollect.instance.getRenderShaderCollect(view); + for (const renderList of viewRenderList) { + let nodeMap = renderList[1]; + for (const iterator of nodeMap) { + let node = iterator[1]; + if (node.preInit) { + node.nodeUpdate(view, this._rendererType, this.rendererPassState, null); + break; + } + } + } + if ((light.castShadow && light.needUpdateShadow || this._forceUpdate) || (light.castShadow && Engine3D.setting.shadow.autoUpdate)) { light.needUpdateShadow = false; let shadowFar = clamp(Engine3D.setting.shadow.shadowFar, camera.near, camera.far); @@ -142,7 +158,7 @@ export class ShadowMapPassRenderer extends RendererBase { let command = GPUContext.beginCommandEncoder(); let encoder = GPUContext.beginRenderPass(command, this.rendererPassState); - shadowCamera.transform.updateWorldMatrix(); + // shadowCamera.transform.updateWorldMatrix(); occlusionSystem.update(shadowCamera, view.scene); GPUContext.bindCamera(encoder, shadowCamera); let op_bundleList = this.renderShadowBundleOp(view, shadowCamera); @@ -201,30 +217,33 @@ export class ShadowMapPassRenderer extends RendererBase { return []; } - protected recordShadowRenderBundleNode(view: View3D, shadowCamera: Camera3D, encoder, nodes: RenderNode[], clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, shadowCamera); GPUContext.bindGeometryBuffer(encoder, nodes[0].geometry); - for (let i = 0; i < nodes.length; ++i) { - let renderNode = nodes[i]; - let matrixIndex = renderNode.transform.worldMatrix.index; - if (!renderNode.transform.enable) - continue; - renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); + if (nodes) { + for (let i = 0; i < nodes.length; ++i) { + let renderNode = nodes[i]; + let matrixIndex = renderNode.transform.worldMatrix.index; + if (!renderNode.transform.enable) + continue; + renderNode.recordRenderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); + } } } protected drawShadowRenderNodes(view: View3D, shadowCamera: Camera3D, encoder: GPURenderPassEncoder, nodes: RenderNode[], clusterLightingBuffer?: ClusterLightingBuffer) { GPUContext.bindCamera(encoder, shadowCamera); - for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { - let renderNode = nodes[i]; - // let matrixIndex = renderNode.transform.worldMatrix.index; - // if (!occlusionSystem.renderCommitTesting(camera,renderNode) ) continue; - if (!renderNode.transform.enable) - continue; - if (!renderNode.enable) - continue; - renderNode.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); + if (nodes) { + for (let i = Engine3D.setting.render.drawOpMin; i < Math.min(nodes.length, Engine3D.setting.render.drawOpMax); ++i) { + let renderNode = nodes[i]; + // let matrixIndex = renderNode.transform.worldMatrix.index; + // if (!occlusionSystem.renderCommitTesting(camera,renderNode) ) continue; + if (!renderNode.transform.enable) + continue; + if (!renderNode.enable) + continue; + renderNode.renderPass2(view, this._rendererType, this.rendererPassState, clusterLightingBuffer, encoder); + } } } } diff --git a/src/index.ts b/src/index.ts index a2e081be..c8cf51ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,10 +42,9 @@ export * from "./assets/shader/core/pass/SkyGBuffer_pass" export * from "./assets/shader/core/pass/ZPassShader_cs" export * from "./assets/shader/core/pass/ZPassShader_fs" export * from "./assets/shader/core/pass/ZPassShader_vs" +export * from "./assets/shader/core/struct/ClusterLight" export * from "./assets/shader/core/struct/ColorPassFragmentOutput" export * from "./assets/shader/core/struct/FragmentVarying" -export * from "./assets/shader/core/struct/LightStruct" -export * from "./assets/shader/core/struct/LightStructFrag" export * from "./assets/shader/core/struct/ShadingInput" export * from "./assets/shader/core/struct/VertexAttributes" export * from "./assets/shader/glsl/Quad_glsl" @@ -63,7 +62,7 @@ export * from "./assets/shader/lighting/UnLit_frag" export * from "./assets/shader/materials/ColorLitShader" export * from "./assets/shader/materials/GIProbeShader" export * from "./assets/shader/materials/GlassShader" -export * from "./assets/shader/materials/Lambert_shader" +export * from "./assets/shader/materials/LambertShader" export * from "./assets/shader/materials/LitShader" export * from "./assets/shader/materials/OutlinePass" export * from "./assets/shader/materials/PBRLItShader" @@ -81,6 +80,7 @@ export * from "./assets/shader/materials/uniforms/UnLitMaterialUniform_frag" export * from "./assets/shader/materials/uniforms/VideoUniform_frag" export * from "./assets/shader/math/FastMathShader" export * from "./assets/shader/math/MathShader" +export * from "./assets/shader/math/MatrixShader" export * from "./assets/shader/post/Bloom_shader" export * from "./assets/shader/post/FXAAShader" export * from "./assets/shader/post/GlobalFog_shader" @@ -248,6 +248,7 @@ export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferBase" export * from "./gfx/graphics/webGpu/core/buffer/GPUBufferType" export * from "./gfx/graphics/webGpu/core/buffer/IndicesGPUBuffer" export * from "./gfx/graphics/webGpu/core/buffer/MaterialDataUniformGPUBuffer" +export * from "./gfx/graphics/webGpu/core/buffer/MatrixGPUBuffer" export * from "./gfx/graphics/webGpu/core/buffer/StorageGPUBuffer" export * from "./gfx/graphics/webGpu/core/buffer/StructStorageGPUBuffer" export * from "./gfx/graphics/webGpu/core/buffer/UniformGPUBuffer" @@ -287,6 +288,7 @@ export * from "./gfx/renderJob/collect/ComponentCollect" export * from "./gfx/renderJob/collect/EntityBatchCollect" export * from "./gfx/renderJob/collect/EntityCollect" export * from "./gfx/renderJob/collect/RenderGroup" +export * from "./gfx/renderJob/collect/RenderShaderCollect" export * from "./gfx/renderJob/collect/ShadowLightsCollect" export * from "./gfx/renderJob/config/RTResourceConfig" export * from "./gfx/renderJob/config/RenderLayer" diff --git a/src/loader/parser/gltf/GLTFSubParserConverter.ts b/src/loader/parser/gltf/GLTFSubParserConverter.ts index 041a2757..c09ad4cb 100644 --- a/src/loader/parser/gltf/GLTFSubParserConverter.ts +++ b/src/loader/parser/gltf/GLTFSubParserConverter.ts @@ -183,6 +183,7 @@ export class GLTFSubParserConverter { if (`enableBlend` in primitive.material) { if (primitive.material[`enableBlend`]) { physicMaterial.blendMode = BlendMode.NORMAL; + physicMaterial.shaderState.depthWriteEnabled = false; } else { physicMaterial.blendMode = BlendMode.NONE; } @@ -191,6 +192,7 @@ export class GLTFSubParserConverter { if (primitive.material.defines.indexOf(`ALPHA_BLEND`) != -1) { physicMaterial.blendMode = BlendMode.ALPHA; physicMaterial.transparent = true; + physicMaterial.shaderState.depthWriteEnabled = false; } } } @@ -199,6 +201,7 @@ export class GLTFSubParserConverter { physicMaterial.alphaCutoff = alphaCutoff; physicMaterial.blendMode = BlendMode.NORMAL; physicMaterial.transparent = true; + physicMaterial.shaderState.depthWriteEnabled = false; } if (primitive.material.transformUV1) physicMaterial.uvTransform_1 = primitive.material.transformUV1; @@ -212,6 +215,8 @@ export class GLTFSubParserConverter { physicMaterial.doubleSide = doubleSided; + physicMaterial.ao = 1; + if (baseColorTexture) { physicMaterial.baseMap = baseColorTexture; } diff --git a/src/materials/LambertMaterial.ts b/src/materials/LambertMaterial.ts index 6418d8ad..7940e478 100644 --- a/src/materials/LambertMaterial.ts +++ b/src/materials/LambertMaterial.ts @@ -1,5 +1,5 @@ -import { Lambert_shader } from '../assets/shader/materials/Lambert_shader'; +import { LambertShader } from '..'; import { ShaderLib } from '../assets/shader/ShaderLib'; import { Engine3D } from '../Engine3D'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; @@ -20,28 +20,31 @@ export class LambertMaterial extends MaterialBase { */ constructor() { super(); - ShaderLib.register("lambert_vert_wgsl", Lambert_shader.lambert_vert_wgsl); - ShaderLib.register("lambert_frag_wgsl", Lambert_shader.lambert_frag_wgsl); - let shader = this.setShader(`lambert_vert_wgsl`, `lambert_frag_wgsl`); + ShaderLib.register("LambertShader", LambertShader); + let shader = this.setShader(`LambertShader`, `LambertShader`); + shader.setShaderEntry(`VertMain`, `FragMain`) + shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1)); shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1)); - shader.setUniformColor(`baseColor`, new Color()); - shader.setUniformVector4(`dirLight`, new Vector4(0, 0, 1, 1)); - shader.setUniformColor(`dirLightColor`, new Color()); + shader.setUniformColor(`baseColor`, new Color(1, 1, 1, 1)); shader.setUniformFloat(`alphaCutoff`, 0.5); - shader.setUniformFloat(`shadowBias`, 0.00035); - let shaderState = shader.shaderState; - shaderState.acceptShadow = true; - shaderState.castShadow = true; + shaderState.acceptShadow = false; shaderState.receiveEnv = false; shaderState.acceptGI = false; - shaderState.useLight = true; + shaderState.useLight = false; + + // let shaderState = shader.shaderState; + // shaderState.acceptShadow = true; + // shaderState.castShadow = true; + // shaderState.receiveEnv = false; + // shaderState.acceptGI = false; + // shaderState.useLight = true; // default value - this.baseMap = Engine3D.res.whiteTexture; - this.emissiveMap = Engine3D.res.blackTexture; + // this.baseMap = Engine3D.res.whiteTexture; + // this.emissiveMap = Engine3D.res.blackTexture; this.baseMap = Engine3D.res.grayTexture; } diff --git a/src/materials/MaterialBase.ts b/src/materials/MaterialBase.ts index 00dacfdd..f13006f6 100644 --- a/src/materials/MaterialBase.ts +++ b/src/materials/MaterialBase.ts @@ -1,3 +1,4 @@ +import { GPUPrimitiveTopology } from '..'; import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; import { ShaderState } from '../gfx/graphics/webGpu/shader/value/ShaderState'; import { RendererType } from '../gfx/renderJob/passRenderer/state/RendererType'; diff --git a/src/materials/PhysicMaterial.ts b/src/materials/PhysicMaterial.ts index d96555d8..82493873 100644 --- a/src/materials/PhysicMaterial.ts +++ b/src/materials/PhysicMaterial.ts @@ -187,7 +187,9 @@ export class PhysicMaterial extends MaterialBase { * A_chanel -> C */ public set maskMap(value: Texture) { - this.renderShader.setDefine(`USE_ARMC`, true); + // USE_MR + // USE_ARMC + this.renderShader.setDefine(`USE_MR`, true); this.renderShader.setTexture(`maskMap`, value); } @@ -214,6 +216,8 @@ export class PhysicMaterial extends MaterialBase { */ public set clearCoatRoughnessMap(value: Texture) { if (!value) return; + console.log("USE_CLEARCOAT_ROUGHNESS"); + this.renderShader.setTexture(`clearCoatRoughnessMap`, value); this.renderShader.setDefine(`USE_CLEARCOAT_ROUGHNESS`, true); } @@ -294,6 +298,7 @@ export class PhysicMaterial extends MaterialBase { */ public set clearcoatFactor(value: number) { this.renderShader.setUniformFloat(`clearcoatFactor`, value); + this.useCleanCoat(); } /** @@ -308,6 +313,7 @@ export class PhysicMaterial extends MaterialBase { */ public set clearcoatRoughnessFactor(value: number) { this.renderShader.setUniformFloat(`clearcoatRoughnessFactor`, value); + this.useCleanCoat(); } /** @@ -322,6 +328,7 @@ export class PhysicMaterial extends MaterialBase { */ public set clearcoatWeight(value: number) { this.renderShader.setUniformFloat(`clearcoatWeight`, value); + this.useCleanCoat(); } /** @@ -336,6 +343,7 @@ export class PhysicMaterial extends MaterialBase { */ public set clearcoatColor(value: Color) { this.renderShader.setUniformColor(`clearcoatColor`, value); + this.useCleanCoat(); } /** diff --git a/src/math/Color.ts b/src/math/Color.ts index a24337a6..db956d2d 100644 --- a/src/math/Color.ts +++ b/src/math/Color.ts @@ -120,22 +120,24 @@ export class Color { * update this color rgb from hexadecimal no alpha * @param value */ - public hexToRGB(value: number) { + public hexToRGB(value: number): Color { //this.a = ((value >> 24) & 0xff ) / 255; this.r = ((value >> 16) & 0xff) / 255; this.g = ((value >> 8) & 0xff) / 255; this.b = (value & 0xff) / 255; + return this; } /** * update this color rgb from hexadecimal has alpha * @param value */ - public hexToRGBA(value: number) { + public hexToRGBA(value: number): Color { this.a = ((value >> 24) & 0xff) / 255; this.r = ((value >> 16) & 0xff) / 255; this.g = ((value >> 8) & 0xff) / 255; this.b = (value & 0xff) / 255; + return this; } /** diff --git a/src/math/MathUtil.ts b/src/math/MathUtil.ts index 98cb1f9f..fbcfcc4d 100644 --- a/src/math/MathUtil.ts +++ b/src/math/MathUtil.ts @@ -231,7 +231,7 @@ export class MathUtil { */ public static fromToRotation(fromDirection: Vector3, toDirection: Vector3, target: Quaternion = null): Quaternion { target ||= new Quaternion(); - let mat: Matrix4 = new Matrix4(); + let mat: Matrix4 = Matrix4.help_matrix_2; Matrix4.fromToRotation(fromDirection, toDirection, mat); target.fromMatrix(mat); return target; diff --git a/src/math/Matrix4.ts b/src/math/Matrix4.ts index f8c67845..14bcbd28 100644 --- a/src/math/Matrix4.ts +++ b/src/math/Matrix4.ts @@ -50,12 +50,12 @@ export class Matrix4 { /** * matrix do use share bytesArray */ - public static matrixBytes: Float32Array; + public static dynamicMatrixBytes: Float32Array; /** * cache all use do matrix */ - public static globalMatrixRef: Matrix4[]; + public static dynamicGlobalMatrixRef: Matrix4[]; /** * @internal @@ -122,14 +122,14 @@ export class Matrix4 { public static allocMatrix(allocCount: number) { this.allocCount = allocCount; - Matrix4.matrixBytes = new Float32Array(allocCount * 16); - Matrix4.buffer = Matrix4.matrixBytes.buffer; + Matrix4.dynamicMatrixBytes = new Float32Array(allocCount * 16); + Matrix4.buffer = Matrix4.dynamicMatrixBytes.buffer; Matrix4.wasmMatrixPtr = 0; - this.globalMatrixRef ||= []; - this.globalMatrixRef.forEach((m) => { + this.dynamicGlobalMatrixRef ||= []; + this.dynamicGlobalMatrixRef.forEach((m) => { let rawData = m.rawData; - m.rawData = new Float32Array(Matrix4.matrixBytes.buffer, m.offset, 16); + m.rawData = new Float32Array(Matrix4.dynamicMatrixBytes.buffer, m.offset, 16); for (let i = 0; i < rawData.length; i++) { m.rawData[i] = rawData[i]; } @@ -326,10 +326,10 @@ export class Matrix4 { this.index = Matrix4.useCount; this.offset = Matrix4.useCount * Matrix4.blockBytes + Matrix4.wasmMatrixPtr; - Matrix4.globalMatrixRef[this.index] = this; + Matrix4.dynamicGlobalMatrixRef[this.index] = this; Matrix4.useCount++; // console.log(this.index); - this.rawData = new Float32Array(Matrix4.matrixBytes.buffer, this.offset, 16); + this.rawData = new Float32Array(Matrix4.dynamicMatrixBytes.buffer, this.offset, 16); // } else { // this.rawData = new Float32Array(16); // } @@ -725,7 +725,7 @@ export class Matrix4 { let data = this.rawData; let EPSILON: number = 0.000001; - let v: Vector3 = Vector3.HELP_0; + let v: Vector3 = Vector3.ZERO; toDirection.crossProduct(fromDirection, v); let e: number = toDirection.dotProduct(fromDirection); @@ -813,7 +813,8 @@ export class Matrix4 { let hvxz; let hvyz; - let h = (1.0 - e) / v.dotProduct(v); + let v2 = v.dotProduct(v); + let h = (1.0 - e) / v2; hvx = h * v.x; hvz = h * v.z; hvxy = hvx * v.y; diff --git a/src/math/Quaternion.ts b/src/math/Quaternion.ts index 86201774..e2a5e76c 100644 --- a/src/math/Quaternion.ts +++ b/src/math/Quaternion.ts @@ -7,9 +7,9 @@ import { Vector3 } from './Vector3'; * @group Math */ export class Quaternion { - public static HELP_0: Quaternion = new Quaternion(); - public static HELP_1: Quaternion = new Quaternion(); - public static HELP_2: Quaternion = new Quaternion(); + public static HELP_0: Quaternion = new Quaternion(0, 0, 0, 1); + public static HELP_1: Quaternion = new Quaternion(0, 0, 0, 1); + public static HELP_2: Quaternion = new Quaternion(0, 0, 0, 1); public static _zero: Quaternion = new Quaternion(0, 0, 0, 1); public static CALCULATION_QUATERNION: Quaternion = new Quaternion(); /** diff --git a/src/shape/CylinderGeometry.ts b/src/shape/CylinderGeometry.ts index 97584dcc..a03baad7 100644 --- a/src/shape/CylinderGeometry.ts +++ b/src/shape/CylinderGeometry.ts @@ -64,7 +64,7 @@ export class CylinderGeometry extends GeometryBase { this.openEnded = openEnded; this.thetaStart = thetaStart; this.thetaLength = thetaLength; - this.uuid = UUID(); + this.instanceID = UUID(); this.buildGeometry(); } diff --git a/src/shape/PlaneGeometry.ts b/src/shape/PlaneGeometry.ts index cc612d38..3c4b78e2 100644 --- a/src/shape/PlaneGeometry.ts +++ b/src/shape/PlaneGeometry.ts @@ -64,7 +64,14 @@ export class PlaneGeometry extends GeometryBase { let position_arr = new Float32Array(vertexCount * 3); let normal_arr = new Float32Array(vertexCount * 3); let uv_arr = new Float32Array(vertexCount * 2); - let indices_arr = new Uint16Array(this.segmentW * this.segmentH * 2 * 3); + + let indices_arr: any; + let totalIndexCount = this.segmentW * this.segmentH * 2 * 3; + if (totalIndexCount >= Uint16Array.length) { + indices_arr = new Uint32Array(this.segmentW * this.segmentH * 2 * 3); + } else { + indices_arr = new Uint16Array(this.segmentW * this.segmentH * 2 * 3); + } numIndices = 0; var indexP: number = 0; diff --git a/src/textures/BitmapTexture2D.ts b/src/textures/BitmapTexture2D.ts index abb0070d..e41451dc 100644 --- a/src/textures/BitmapTexture2D.ts +++ b/src/textures/BitmapTexture2D.ts @@ -9,7 +9,7 @@ import { Texture } from '../gfx/graphics/webGpu/core/texture/Texture'; * @group Texture */ export class BitmapTexture2D extends Texture { - private _source: HTMLCanvasElement | ImageBitmap | OffscreenCanvas; + private _source: HTMLCanvasElement | ImageBitmap | OffscreenCanvas | HTMLImageElement; /** * @constructor @@ -23,14 +23,14 @@ export class BitmapTexture2D extends Texture { /** * get raw data of this texture */ - public get source(): HTMLCanvasElement | ImageBitmap | OffscreenCanvas { + public get source(): HTMLCanvasElement | ImageBitmap | OffscreenCanvas | HTMLImageElement { return this._source; } /** * set raw data of this texture */ - public set source(value: HTMLCanvasElement | ImageBitmap | OffscreenCanvas) { + public set source(value: HTMLCanvasElement | ImageBitmap | OffscreenCanvas | HTMLImageElement) { this._source = value; if (this._source instanceof HTMLImageElement) { diff --git a/src/textures/VirtualTexture.ts b/src/textures/VirtualTexture.ts index d648033a..afbd24f3 100644 --- a/src/textures/VirtualTexture.ts +++ b/src/textures/VirtualTexture.ts @@ -148,6 +148,7 @@ export class VirtualTexture extends Texture { ); let arryBuffer = textureBuffer.getMappedRange(0, td.byteLength); + return arryBuffer; } } diff --git a/src/util/GeometryUtil.ts b/src/util/GeometryUtil.ts index b8c318d2..73323f94 100644 --- a/src/util/GeometryUtil.ts +++ b/src/util/GeometryUtil.ts @@ -1,10 +1,13 @@ +import { Matrix4 } from '..'; import { GeometryBase } from '../core/geometry/GeometryBase'; import { ShaderReflection } from '../gfx/graphics/webGpu/shader/value/ShaderReflectionInfo'; /** * @internal */ export class GeometryUtil { - public static merge() { } + public static merge(geometries: GeometryBase[], matrixes: Matrix4[], target?: GeometryBase) { + + } public static generateNormal() { } public static generateTangent() { } diff --git a/src/util/Vector3Ex.ts b/src/util/Vector3Ex.ts index c914d604..19f4d99e 100644 --- a/src/util/Vector3Ex.ts +++ b/src/util/Vector3Ex.ts @@ -143,7 +143,7 @@ export class Vector3Ex { * @returns random vector */ public static getRandomXYZ(min: number = -100, max: number = 100): Vector3 { - return new Vector3(Math.random() * max + min, Math.random() * max + min, Math.random() * max + min); + return new Vector3(Math.random() * (max - min) + min, Math.random() * (max - min) + min, Math.random() * (max - min) + min); } /** @@ -157,4 +157,20 @@ export class Vector3Ex { public static getRandomV3(min: number = -100, max: number = 100, yMin: number, yMax: number): Vector3 { return new Vector3(Math.random() * max + min, Math.random() * yMax + yMin, Math.random() * max + min); } + + public static sphere(radius: number) { + let r = radius * Math.random(); + let randomDir = new Vector3(Math.random() * 1 - 0.5, Math.random() * 1 - 0.5, Math.random() * 1 - 0.5); + randomDir.normalize(); + randomDir.scaleBy(r); + return randomDir; + } + + public static sphereXYZ(radiusMin: number, radiusMax: number, x: number = 1, y: number = 1, z: number = 1) { + let r = radiusMin + (radiusMax - radiusMin) * Math.random(); + let randomDir = new Vector3(Math.random() * x - x * 0.5, Math.random() * y - y * 0.5, Math.random() * z - z * 0.5); + randomDir.normalize(); + randomDir.scaleBy(r); + return randomDir; + } } diff --git a/test/math/MatrixDO.test.ts b/test/math/MatrixDO.test.ts index ab5c969a..abfef6a7 100644 --- a/test/math/MatrixDO.test.ts +++ b/test/math/MatrixDO.test.ts @@ -20,7 +20,7 @@ await test('MatrixDO create 5000 test', async () => { expect(list.length).toEqual(5000); // expect(Matrix4.globalMatrixRef.length).toEqual(10010); // about all this runtime init matrix - expect(Matrix4.matrixBytes.byteLength).toEqual(704000); + expect(Matrix4.dynamicMatrixBytes.byteLength).toEqual(704000); }) setTimeout(end, 500) diff --git a/vite.config.js b/vite.config.js index 9e8336eb..84ba8fd7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,8 +3,9 @@ import { defineConfig } from 'vite' import { readFile, writeFile, readdir, lstat } from 'fs/promises' import { resolve, parse } from 'path' -export default defineConfig( option => ({ +export default defineConfig(option => ({ server: { + host: '0.0.0.0', port: 8000, // hmr: false // open this line if no auto hot-reload required }, @@ -37,7 +38,7 @@ export default defineConfig( option => ({ return ts } async function autoIndex(file) { - if(file && !tsFile.test(file.replace(/\\/g, '/'))) // fix windows path + if (file && !tsFile.test(file.replace(/\\/g, '/'))) // fix windows path return let ts = await dir('./src') ts.sort() // make sure same sort on windows and unix @@ -53,7 +54,7 @@ export default defineConfig( option => ({ } server.httpServer.on('listening', autoIndex) server.watcher.on('change', autoIndex) - server.watcher.on('unlink', autoIndex) + server.watcher.on('unlink', autoIndex) } }], build: {