@woosh/meep-engine 2.41.0 → 2.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/core/geom/3d/apply_mat4_transform_to_v3_array.js +2 -4
  2. package/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +28 -0
  3. package/core/geom/Quaternion.js +14 -0
  4. package/engine/EngineHarness.js +9 -3
  5. package/engine/ecs/transform/Transform.js +23 -3
  6. package/engine/graphics/ecs/decal/v2/Decal.d.ts +11 -0
  7. package/engine/graphics/ecs/decal/v2/Decal.js +50 -0
  8. package/engine/graphics/ecs/decal/v2/FPDecalSystem.d.ts +8 -0
  9. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +213 -0
  10. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +237 -0
  11. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -1
  12. package/engine/graphics/ecs/mesh-v2/build_three_object.js +4 -0
  13. package/engine/graphics/geometry/MikkT/MikkTSpace.js +466 -305
  14. package/engine/graphics/geometry/buffered/computeGeometryEquality.js +1 -1
  15. package/engine/graphics/geometry/buffered/computeGeometryHash.js +1 -1
  16. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +27 -14
  17. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +6 -0
  18. package/engine/graphics/impostors/octahedral/README.md +1 -0
  19. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere.js +25 -22
  20. package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere_radius_only.js +37 -0
  21. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +30 -1
  22. package/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +1 -1
  23. package/engine/graphics/impostors/octahedral/prototypeBaker.js +121 -22
  24. package/engine/graphics/impostors/octahedral/shader/BakeShaderStandard.js +46 -7
  25. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +349 -0
  26. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV1.js +74 -0
  27. package/engine/graphics/impostors/octahedral/shader/glsl/v1/common.glsl +209 -0
  28. package/engine/graphics/impostors/octahedral/shader/glsl/v1/flagment.glsl +80 -0
  29. package/engine/graphics/impostors/octahedral/shader/glsl/v1/vertex.glsl +350 -0
  30. package/engine/graphics/micron/render/v1/getTransformedPositionsCached.js +1 -1
  31. package/engine/graphics/render/forward_plus/LightManager.js +1 -1
  32. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +1 -3
  33. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
  34. package/engine/graphics/render/forward_plus/model/Decal.js +19 -2
  35. package/engine/graphics/texture/sampler/Sampler2D.js +10 -10
  36. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +117 -11
  37. package/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +66 -0
  38. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +2 -2
  39. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { isArrayEqualStrict } from "../../../../core/collection/array/isArrayEqualStrict.d.ts";
1
+ import { isArrayEqualStrict } from "../../../../core/collection/array/isArrayEqualStrict.js";
2
2
  import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
3
3
 
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { computeBufferAttributeHash } from "./computeBufferAttributeHash.js";
2
- import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.d.ts";
2
+ import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
3
3
 
4
4
  /**
5
5
  *
@@ -3,7 +3,7 @@ import { assert } from "../../../../core/assert.js";
3
3
  import { isPowerOfTwo } from "../../../../core/math/isPowerOrTwo.js";
4
4
  import { Mesh, OrthographicCamera, Scene, Vector4, WebGLMultipleRenderTargets } from "three";
5
5
  import { ImpostorDescription } from "./ImpostorDescription.js";
6
- import { mat4 } from "gl-matrix";
6
+ import { mat4, vec3 } from "gl-matrix";
7
7
  import { BakeShaderStandard } from "./shader/BakeShaderStandard.js";
8
8
  import { Sampler2D } from "../../texture/sampler/Sampler2D.js";
9
9
  import Signal from "../../../../core/events/signal/Signal.js";
@@ -14,8 +14,8 @@ import { UvEncoder } from "./grid/UvEncoder.js";
14
14
  import { OctahedralUvEncoder } from "./grid/OctahedralUvEncoder.js";
15
15
  import { HemiOctahedralUvEncoder } from "./grid/HemiOctahedralUvEncoder.js";
16
16
  import { prepare_bake_material } from "./bake/prepare_bake_material.js";
17
- import { compute_bounding_sphere } from "./bake/compute_bounding_sphere.js";
18
17
  import { collectIteratorValueToArray } from "../../../../core/collection/IteratorUtils.js";
18
+ import { compute_bounding_sphere } from "./bake/compute_bounding_sphere.js";
19
19
 
20
20
  export class ImpostorBaker {
21
21
 
@@ -37,20 +37,22 @@ export class ImpostorBaker {
37
37
 
38
38
  /**
39
39
  *
40
- * @param {number} distance
40
+ * @param {number[]|vec4} bounding_sphere
41
41
  * @param {{mesh:ShadedGeometry, transform:mat4}[]} objects
42
42
  * @param {number} resolution
43
43
  * @param {number} frames
44
44
  * @param {UvEncoder} encoder
45
45
  */
46
46
  bake_internal({
47
- distance,
47
+ bounding_sphere,
48
48
  objects,
49
49
  resolution,
50
50
  frames,
51
51
  encoder
52
52
  }) {
53
53
 
54
+ const distance = bounding_sphere[3];
55
+
54
56
  assert.isNumber(distance, 'distance');
55
57
  assert.isNonNegativeInteger(resolution, 'resolution');
56
58
  assert.isNonNegativeInteger(frames, 'frames');
@@ -66,7 +68,6 @@ export class ImpostorBaker {
66
68
  rt.texture[1].name = 'normal+depth';
67
69
  rt.texture[2].name = 'orm'; // Occlusion, Roughness, Metalness
68
70
 
69
-
70
71
  const renderer = this._renderer;
71
72
 
72
73
  // remember render state
@@ -74,6 +75,7 @@ export class ImpostorBaker {
74
75
  const _vp = new Vector4();
75
76
  renderer.getViewport(_vp);
76
77
  const _autoClear = renderer.autoClear;
78
+ const _pixelRatio = renderer.getPixelRatio();
77
79
 
78
80
  const gl = this._renderer.getContext();
79
81
 
@@ -90,6 +92,7 @@ export class ImpostorBaker {
90
92
  renderer.setRenderTarget(rt);
91
93
  renderer.setClearColor(0xFFFFFF, 0);
92
94
  renderer.clearColor();
95
+ renderer.setPixelRatio(1);
93
96
 
94
97
  const frame_width = resolution / frames;
95
98
  const frame_height = resolution / frames;
@@ -122,6 +125,7 @@ export class ImpostorBaker {
122
125
  keyEqualityFunction: computeMaterialEquality
123
126
  });
124
127
 
128
+ const max_anisotropic_filtering_level = renderer.capabilities.getMaxAnisotropy();
125
129
 
126
130
  for (let k = 0; k < object_count; k++) {
127
131
  const object = objects[k];
@@ -129,7 +133,7 @@ export class ImpostorBaker {
129
133
  const source_mesh = object.mesh;
130
134
 
131
135
  // ensure tangents are generated
132
- // buffer_geometry_ensure_tangents(source_mesh.geometry);
136
+ //buffer_geometry_ensure_tangents(source_mesh.geometry);
133
137
 
134
138
  const source_material = source_mesh.material;
135
139
 
@@ -139,7 +143,14 @@ export class ImpostorBaker {
139
143
  const bake_material = new BakeShaderStandard();
140
144
 
141
145
  // prepare bake material to match the source material
142
- prepare_bake_material(bake_material, source_material, cleanup_signal);
146
+ prepare_bake_material({
147
+ bake_material: bake_material,
148
+ source_material: source_material,
149
+ cleanup_signal: cleanup_signal,
150
+ anisotropy: max_anisotropic_filtering_level
151
+ });
152
+
153
+ bake_material.uniforms.uAtlasResolution.value.set(resolution, resolution);
143
154
 
144
155
  cleanup_signal.addOne(bake_material.dispose, bake_material);
145
156
 
@@ -183,9 +194,9 @@ export class ImpostorBaker {
183
194
  encoder.uv_to_unit(unit_sphere_direction, [octahedron_u, octahedron_v]);
184
195
 
185
196
  // offset by the radius of the sphere
186
- const camera_px = distance * unit_sphere_direction[0];
187
- const camera_py = distance * unit_sphere_direction[1];
188
- const camera_pz = distance * unit_sphere_direction[2];
197
+ const camera_px = distance * unit_sphere_direction[0] + bounding_sphere[0];
198
+ const camera_py = distance * unit_sphere_direction[1] + bounding_sphere[1];
199
+ const camera_pz = distance * unit_sphere_direction[2] + bounding_sphere[2];
189
200
 
190
201
  // console.log(`UV:${octahedron_u.toFixed(2)},${octahedron_v.toFixed(2)}\t V3:${unit_sphere_direction.map(n => n.toFixed(2)).join(', ')}`);
191
202
 
@@ -203,7 +214,7 @@ export class ImpostorBaker {
203
214
  camera_pz
204
215
  );
205
216
 
206
- cam.lookAt(0, 0, 0);
217
+ cam.lookAt(bounding_sphere[0], bounding_sphere[1], bounding_sphere[2]);
207
218
  cam.updateProjectionMatrix();
208
219
 
209
220
  // update materials
@@ -237,6 +248,7 @@ export class ImpostorBaker {
237
248
  renderer.setRenderTarget(_rt);
238
249
  renderer.setViewport(_vp);
239
250
  renderer.autoClear = _autoClear;
251
+ renderer.setPixelRatio(_pixelRatio);
240
252
  if (_enabled_antialias) {
241
253
  gl.enable(gl.SAMPLE_ALPHA_TO_COVERAGE);
242
254
  }
@@ -302,7 +314,7 @@ export class ImpostorBaker {
302
314
  throw new Error('No renderer attached. Renderer is required for baking.');
303
315
  }
304
316
 
305
- const objects_radius = compute_bounding_sphere(objects);
317
+ const bounding_sphere = compute_bounding_sphere(objects);
306
318
 
307
319
  // we need to compute bounding sphere around origin of the object
308
320
  let encoder;
@@ -318,12 +330,13 @@ export class ImpostorBaker {
318
330
  resolution,
319
331
  frames,
320
332
  objects,
321
- distance: objects_radius,
333
+ bounding_sphere,
322
334
  encoder
323
335
  });
324
336
 
325
337
  r.capture_type = type;
326
- r.sphere_radius = objects_radius;
338
+ r.sphere_radius = bounding_sphere[3];
339
+ vec3.copy(r.offset,bounding_sphere);
327
340
 
328
341
  console.timeEnd('bake');
329
342
 
@@ -27,6 +27,12 @@ export class ImpostorDescription {
27
27
  */
28
28
  sphere_radius = 0;
29
29
 
30
+ /**
31
+ * Baking offset
32
+ * @type {number[]}
33
+ */
34
+ offset = [0, 0, 0];
35
+
30
36
  /**
31
37
  * Actual baked data
32
38
  * @type {Sampler2D|null}
@@ -22,6 +22,7 @@ This is inherently a deferred rendering technique, where an impostor asset is re
22
22
  ---
23
23
  references:
24
24
 
25
+ - [2021] [Rendering a Sphere on a Quad](https://bgolus.medium.com/rendering-a-sphere-on-a-quad-13c92025570c) by Ben Golus
25
26
  - [2018] [Octahedral Impostors](https://shaderbits.com/blog/octahedral-impostors) by Ryan Brucks
26
27
  - [2018] https://github.com/xraxra/IMP
27
28
  - [2018] https://github.com/wojtekpil/Godot-Octahedral-Impostors
@@ -1,42 +1,45 @@
1
- import { vec3 } from "gl-matrix";
2
- import { max2 } from "../../../../../core/math/max2.js";
1
+ import { Miniball } from "../../../../../core/geom/packing/miniball/Miniball.js";
2
+ import { PointSet } from "../../../../../core/geom/packing/miniball/PointSet.js";
3
+ import { apply_mat4_transform_to_v3_array } from "../../../../../core/geom/3d/apply_mat4_transform_to_v3_array.js";
3
4
 
4
5
  /**
5
- * Computes radius of bounding sphere around origin for given group of objects
6
6
  *
7
- * NOTE: This may seem pointless, but by doing this computation on per-vertex basis we get the tightest possible bounds,
8
- * allowing us to get the best possible texture space utilization.
9
7
  * @param {{mesh:ShadedGeometry, transform:mat4}[]} objects
10
- * @returns {number}
11
8
  */
12
9
  export function compute_bounding_sphere(objects) {
13
- let distance = 0;
10
+ let total_point_count = 0;
11
+ const object_count = objects.length;
14
12
 
15
- const v3 = [];
16
- const n = objects.length;
17
- for (let i = 0; i < n; i++) {
13
+ for (let i = 0; i < object_count; i++) {
18
14
  const object = objects[i];
19
15
 
20
- const attribute = object.mesh.geometry.getAttribute('position');
16
+ const geometry = object.mesh.geometry;
21
17
 
22
- const array = attribute.array;
18
+ const attribute = geometry.getAttribute('position');
23
19
 
24
- const transform = object.transform;
20
+ total_point_count += attribute.count;
21
+ }
22
+
23
+ const final_buffer = new Float32Array(total_point_count * 3);
24
+
25
+ let pointer = 0;
26
+
27
+ for (let i = 0; i < object_count; i++) {
28
+ const object = objects[i];
25
29
 
26
- const n = array.length;
30
+ const geometry = object.mesh.geometry;
27
31
 
28
- for (let j = 0; j < n; j += 3) {
29
- v3[0] = array[j];
30
- v3[1] = array[j + 1];
31
- v3[2] = array[j + 2];
32
+ const attribute = geometry.getAttribute('position');
32
33
 
33
- vec3.transformMat4(v3, v3, transform);
34
+ const source_length = attribute.array.length;
34
35
 
35
- distance = max2(distance, vec3.length(v3));
36
- }
36
+ apply_mat4_transform_to_v3_array(attribute.array, 0, final_buffer, pointer, attribute.count, object.transform);
37
37
 
38
+ pointer += source_length;
38
39
  }
39
40
 
41
+ const points = new PointSet(total_point_count, 3, final_buffer);
42
+ const miniball = new Miniball(points);
40
43
 
41
- return distance;
44
+ return [...miniball.center(), miniball.radius()];
42
45
  }
@@ -0,0 +1,37 @@
1
+ import { max2 } from "../../../../../core/math/max2.js";
2
+ import {
3
+ sphere_radius_sqr_from_v3_array_transformed
4
+ } from "../../../../../core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js";
5
+
6
+ /**
7
+ * Computes radius of bounding sphere around origin for given group of objects
8
+ *
9
+ * NOTE: This may seem pointless, but by doing this computation on per-vertex basis we get the tightest possible bounds,
10
+ * allowing us to get the best possible texture space utilization.
11
+ * @param {{mesh:ShadedGeometry, transform:mat4}[]} objects
12
+ * @returns {number}
13
+ */
14
+ export function compute_bounding_sphere_radius_only(objects) {
15
+ let distance_sqr = 0;
16
+
17
+ const n = objects.length;
18
+ for (let i = 0; i < n; i++) {
19
+ const object = objects[i];
20
+
21
+ const attribute = object.mesh.geometry.getAttribute('position');
22
+
23
+ const array = attribute.array;
24
+
25
+ const transform = object.transform;
26
+
27
+ const n = array.length;
28
+
29
+ const radius2 = sphere_radius_sqr_from_v3_array_transformed(array, n, transform);
30
+
31
+ distance_sqr = max2(distance_sqr, radius2);
32
+
33
+ }
34
+
35
+
36
+ return Math.sqrt(distance_sqr);
37
+ }
@@ -18,13 +18,20 @@ function onePixelTexture(contents, cleanup_signal) {
18
18
  return t;
19
19
  }
20
20
 
21
+
21
22
  /**
22
23
  *
23
24
  * @param {THREE.RawShaderMaterial} bake_material
24
25
  * @param {THREE.Material | THREE.MeshStandardMaterial} source_material
25
26
  * @param {Signal} cleanup_signal
27
+ * @param {number} anisotropy
26
28
  */
27
- export function prepare_bake_material(bake_material, source_material, cleanup_signal) {
29
+ export function prepare_bake_material({
30
+ bake_material,
31
+ source_material,
32
+ cleanup_signal,
33
+ anisotropy
34
+ }) {
28
35
 
29
36
 
30
37
  const target_uniforms = bake_material.uniforms;
@@ -70,6 +77,28 @@ export function prepare_bake_material(bake_material, source_material, cleanup_si
70
77
  texture_emissive = onePixelTexture([0, 0, 0, 0], cleanup_signal);
71
78
  }
72
79
 
80
+ // set rendering parameters on textures
81
+ [
82
+ texture_diffuse,
83
+ texture_emissive,
84
+ texture_occlusion,
85
+ texture_metalness,
86
+ texture_roughness,
87
+ texture_normal
88
+ ].forEach(t => {
89
+ if (t === null) {
90
+ return;
91
+ }
92
+
93
+ const _old_a = t.anisotropy;
94
+
95
+ t.anisotropy = anisotropy;
96
+
97
+ cleanup_signal.addOne(() => {
98
+ t.anisotropy = _old_a;
99
+ });
100
+ });
101
+
73
102
  target_uniforms.tDiffuse.value = texture_diffuse;
74
103
  target_uniforms.tNormal.value = texture_normal;
75
104
  target_uniforms.tRoughness.value = texture_roughness;
@@ -9,7 +9,7 @@ export class HemiOctahedralUvEncoder extends UvEncoder {
9
9
  const abs_x = Math.abs(px);
10
10
  const abs_z = Math.abs(pz);
11
11
 
12
- const r_y = 1 - abs_x - abs_z;
12
+ const r_y = 1 - (abs_x + abs_z);
13
13
 
14
14
  output[0] = px;
15
15
  output[1] = r_y;
@@ -17,8 +17,18 @@ import { Transform } from "../../../ecs/transform/Transform.js";
17
17
  import { GLTFAssetLoader } from "../../../asset/loaders/GLTFAssetLoader.js";
18
18
  import { ImpostorCaptureType } from "./ImpostorCaptureType.js";
19
19
  import { PlaneBufferGeometry } from "three";
20
- import { ImpostorShaderStandard } from "./shader/ImpostorShaderStandard.js";
21
20
  import { ShadedGeometrySystem } from "../../ecs/mesh-v2/ShadedGeometrySystem.js";
21
+ import { ImpostorShaderV0 } from "./shader/ImpostorShaderV0.js";
22
+ import Quaternion from "../../../../core/geom/Quaternion.js";
23
+ import { DEG2RAD } from "three/src/math/MathUtils.js";
24
+ import { SGMesh } from "../../ecs/mesh-v2/aggregate/SGMesh.js";
25
+ import { SGMeshSystem } from "../../ecs/mesh-v2/aggregate/SGMeshSystem.js";
26
+ import { ShadedGeometryFlags } from "../../ecs/mesh-v2/ShadedGeometryFlags.js";
27
+ import { TransformAttachmentSystem } from "../../../ecs/transform-attachment/TransformAttachmentSystem.js";
28
+ import { BehaviorComponent } from "../../../intelligence/behavior/ecs/BehaviorComponent.js";
29
+ import Vector3 from "../../../../core/geom/Vector3.js";
30
+ import { BehaviorSystem } from "../../../intelligence/behavior/ecs/BehaviorSystem.js";
31
+ import { RotationBehavior } from "../../../../../model/game/util/behavior/RotationBehavior.js";
22
32
 
23
33
  /**
24
34
  *
@@ -27,7 +37,9 @@ import { ShadedGeometrySystem } from "../../ecs/mesh-v2/ShadedGeometrySystem.js"
27
37
  */
28
38
  async function main(engine) {
29
39
  await EngineHarness.buildBasics({
30
- engine
40
+ engine,
41
+ enableWater: false,
42
+ cameraFieldOfView: 45
31
43
  });
32
44
 
33
45
  const baker = new ImpostorBaker();
@@ -35,16 +47,18 @@ async function main(engine) {
35
47
  baker.renderer = renderer;
36
48
 
37
49
 
38
- // const gltf_asset = await engine.assetManager.promise('data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf', GameAssetType.ModelGLTF_JSON);
39
- // const gltf_asset = await engine.assetManager.promise('data/models/LowPolyTownshipSet/Barrel/model.gltf', GameAssetType.ModelGLTF_JSON);
40
- // const gltf_asset = await engine.assetManager.promise('data/models/LowPolyTownshipSet/Town_Hall/model.gltf', GameAssetType.ModelGLTF_JSON);
41
- // const gltf_asset = await engine.assetManager.promise('data/models/LowPolyTownshipSet/Small_house/Small_house.gltf', GameAssetType.ModelGLTF_JSON);
42
- const gltf_asset = await engine.assetManager.promise('data/models/MOBA and Tower Defense/Tree_03.gltf', GameAssetType.ModelGLTF_JSON);
43
- // const gltf_asset = await engine.assetManager.promise('data/models/samples/transform-hierarchy.glb', GameAssetType.ModelGLTF_JSON);
44
- // const gltf_asset = await engine.assetManager.promise('data/models/sponza-pbr/gltf/sponza.glb', GameAssetType.ModelGLTF_JSON);
45
- // const gltf_asset = await engine.assetManager.promise('moicon/gnutti_not_optimized/model.gltf', GameAssetType.ModelGLTF_JSON);
46
- // const gltf_asset = await engine.assetManager.promise('moicon/isiflow_Oct_15_21/2/model.gltf', GameAssetType.ModelGLTF_JSON);
47
- // const gltf_asset = await engine.assetManager.promise('moicon/Kople/EVCharger1.gltf', GameAssetType.ModelGLTF_JSON);
50
+ const path = 'data/models/LowPolyTownshipSet/Small_house/Small_house.gltf';
51
+ // const path = 'data/models/LowPolyTownshipSet/Barrel/model.gltf';
52
+ // const path = 'data/models/LowPolyTownshipSet/Town_Hall/model.gltf';
53
+ // const path = 'data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf';
54
+ // const path = 'data/models/MOBA and Tower Defense/Tree_01.gltf';
55
+ // const path = 'data/models/samples/transform-hierarchy.glb';
56
+ // const path = 'data/models/sponza-pbr/gltf/sponza.glb';
57
+ // const path = 'moicon/gnutti_not_optimized/model.gltf';
58
+ // const path = 'moicon/isiflow_Oct_15_21/1/model.gltf';
59
+ // const path = 'moicon/Kople/EVCharger1.gltf';
60
+
61
+ const gltf_asset = await engine.assetManager.promise(path, GameAssetType.ModelGLTF_JSON);
48
62
 
49
63
  const node_hierarchy = three_object_to_entity_composition(gltf_asset.create());
50
64
 
@@ -74,23 +88,26 @@ async function main(engine) {
74
88
  // }
75
89
  // );
76
90
 
91
+ // console.profile('bake');
77
92
  const id = baker.bake({
78
93
  objects,
79
- frames: 12,
80
- resolution: 1024,
81
- type: ImpostorCaptureType.Hemisphere
94
+ frames: 16,
95
+ resolution: 2048,
96
+ type: ImpostorCaptureType.FullSphere
82
97
  });
98
+ // console.profileEnd('bake');
83
99
 
84
100
  console.log(id);
85
101
 
86
102
  const ctrl = buildCanvasViewFromTexture({
87
- texture: id.rt.texture[1],
103
+ texture: id.rt.texture[0],
88
104
  renderer: renderer,
89
105
  // swizzle: ['a', 'a', 'a', 1]
90
- swizzle: ['r', 'g', 'b', 1]
106
+ // swizzle: ['r', 'g', 'b', 1]
107
+ swizzle: ['r', 'g', 'b', 'a']
91
108
  });
92
109
  ctrl.view.css({
93
- opacity: 0.2
110
+ opacity: 1
94
111
  });
95
112
  ctrl.render();
96
113
 
@@ -115,13 +132,92 @@ async function main(engine) {
115
132
  offset: new Vector2(0, 0)
116
133
  }))
117
134
  .add(GUIElement.fromView(ctrl.view))
118
- .build(ecd);
135
+ // .build(ecd);
119
136
 
137
+ const t0 = Transform.fromJSON({
138
+ position: { x: 10, y: 0.5, z: 10 },
139
+ scale: 3,
140
+ rotation: Quaternion.fromEulerAngles(0, 90 * DEG2RAD, 0)
141
+ });
120
142
 
121
- new EntityBuilder()
122
- .add(new Transform())
123
- .add(ShadedGeometry.from(new PlaneBufferGeometry(1, 1, 1), new ImpostorShaderStandard()))
143
+ t0.scale.setScalar(3 / (id.sphere_radius * 2));
144
+
145
+ const entity_impostor = make_impostor_entity(id, t0);
146
+ entity_impostor.build(ecd);
147
+
148
+ const t1 = new Transform();
149
+ t1.copy(t0);
150
+ t1.position._add(3, 0, 0);
151
+ // t1.scale.setScalar(1.9);
152
+
153
+ const sg_mesh = SGMesh.fromURL(path);
154
+
155
+ sg_mesh.castShadow = false;
156
+ sg_mesh.receiveShadow = false;
157
+
158
+ const entity_true_mesh = new EntityBuilder();
159
+ entity_true_mesh
160
+ .add(sg_mesh)
161
+ .add(t1)
124
162
  .build(ecd);
163
+
164
+
165
+ // [entity_true_mesh, entity_impostor].forEach(e => make_spin(e));
166
+ }
167
+
168
+ /**
169
+ *
170
+ * @param {EntityBuilder} entity
171
+ * @param {number} [speed]
172
+ * @param {Vector3} [axis]
173
+ */
174
+ function make_spin(entity, speed = 1, axis = Vector3.up) {
175
+ /**
176
+ *
177
+ * @type {Transform}
178
+ */
179
+ const t = entity.getComponent(Transform);
180
+
181
+ if (t === null) {
182
+ return;
183
+ }
184
+
185
+ entity.add(BehaviorComponent.fromOne(RotationBehavior.fromJSON({
186
+ axis, speed
187
+ })));
188
+ }
189
+
190
+ /**
191
+ *
192
+ * @param {ImpostorDescription} id
193
+ * @param {Transform} t
194
+ * @returns {EntityBuilder}
195
+ */
196
+ function make_impostor_entity(id, t = new Transform()) {
197
+
198
+ const mat = new ImpostorShaderV0();
199
+
200
+ mat.uniforms.tBase.value = id.rt.texture[0];
201
+ mat.uniforms.tGeometry.value = id.rt.texture[1];
202
+ mat.uniforms.uFrames.value = id.frame_count;
203
+ mat.uniforms.uOffset.value.set(id.offset[0], id.offset[1], id.offset[2]);
204
+ mat.uniforms.uRadius.value = id.sphere_radius;
205
+ mat.uniforms.uIsFullSphere.value = id.capture_type === ImpostorCaptureType.FullSphere;
206
+
207
+ const transform = new Transform();
208
+
209
+ transform.copy(t);
210
+
211
+ const sg = ShadedGeometry.from(new PlaneBufferGeometry(1, 1, 1), mat);
212
+
213
+ sg.depth_material = mat;
214
+ sg.clearFlag(ShadedGeometryFlags.CastShadow);
215
+ sg.clearFlag(ShadedGeometryFlags.ReceiveShadow);
216
+
217
+ return new EntityBuilder()
218
+ .add(transform)
219
+ .add(sg)
220
+ ;
125
221
  }
126
222
 
127
223
  new EngineHarness().initialize({
@@ -129,6 +225,9 @@ new EngineHarness().initialize({
129
225
  config.addSystem(new GUIElementSystem(engine.gui.view, engine));
130
226
  config.addSystem(new ViewportPositionSystem(engine.graphics.viewport.size));
131
227
  config.addSystem(new ShadedGeometrySystem(engine));
228
+ config.addSystem(new SGMeshSystem(engine));
229
+ config.addSystem(new TransformAttachmentSystem());
230
+ config.addSystem(new BehaviorSystem(engine));
132
231
 
133
232
  const gltfAssetLoader = new GLTFAssetLoader();
134
233
 
@@ -1,6 +1,6 @@
1
1
  //
2
2
 
3
- import { Color, GLSL3, RawShaderMaterial, Vector4 } from "three";
3
+ import { Color, GLSL3, RawShaderMaterial, Vector2, Vector4 } from "three";
4
4
 
5
5
  const shader_vx = `
6
6
  in vec3 position;
@@ -68,6 +68,9 @@ const shader_fg = `
68
68
  uniform sampler2D tOcclusion;
69
69
  uniform sampler2D tEmissive;
70
70
 
71
+ uniform float uTextureLODBias;
72
+ uniform vec2 uAtlasResolution;
73
+
71
74
  uniform vec2 repeat;
72
75
 
73
76
  in vec3 vNormal;
@@ -75,10 +78,37 @@ const shader_fg = `
75
78
  in mat3 TBN;
76
79
  in vec3 vColor;
77
80
  in float depth;
81
+
82
+ vec4 texture_supersample_4(in sampler2D sampler, in vec2 uv, float lod_bias){
83
+ vec2 half_pixel_size = vec2(0.5) / uAtlasResolution;
84
+
85
+ // per pixel partial derivatives
86
+ vec2 dx = dFdx(uv.xy);
87
+ vec2 dy = dFdy(uv.xy);
88
+ // rotated grid uv offsets
89
+ vec2 uvOffsets = vec2(0.125, 0.375);
90
+ vec4 offsetUV = vec4(0.0, 0.0, 0.0, uTextureLODBias);
91
+
92
+ float bias = -1.0 + lod_bias;
93
+
94
+ // supersampled using 2x2 rotated grid
95
+ vec4 col;
96
+ offsetUV.xy = uv.xy + uvOffsets.x * dx + uvOffsets.y * dy;
97
+ col += texture(sampler, offsetUV.xy, bias);
98
+ offsetUV.xy = uv.xy - uvOffsets.x * dx - uvOffsets.y * dy;
99
+ col += texture(sampler, offsetUV.xy, bias);
100
+ offsetUV.xy = uv.xy + uvOffsets.y * dx - uvOffsets.x * dy;
101
+ col += texture(sampler, offsetUV.xy, bias);
102
+ offsetUV.xy = uv.xy - uvOffsets.y * dx + uvOffsets.x * dy;
103
+ col += texture(sampler, offsetUV.xy, bias);
104
+ col *= 0.25;
105
+
106
+ return col;
107
+ }
78
108
 
79
109
  void main() {
80
110
  // write color to G-Buffer
81
- vec4 diffuse_texture_sample = texture( tDiffuse, vUv);
111
+ vec4 diffuse_texture_sample = texture_supersample_4( tDiffuse, vUv, uTextureLODBias);
82
112
 
83
113
  if(diffuse_texture_sample.a < 0.5){
84
114
  // alpha masking
@@ -91,15 +121,15 @@ const shader_fg = `
91
121
 
92
122
  // write normals to G-Buffer
93
123
  // see https://learnopengl.com/Advanced-Lighting/Normal-Mapping
94
- vec3 normal_sample = texture(tNormal, vUv).rgb*2.0 - 1.0;
124
+ vec3 normal_sample = texture_supersample_4(tNormal, vUv,uTextureLODBias).rgb*2.0 - 1.0;
95
125
  vec3 normal = normalize(TBN * normal_sample);
96
126
 
97
127
  gNormal = vec4( normal*0.5 + 0.5, depth);
98
128
 
99
- float roughness = texture(tRoughness, vUv).g;
100
- float metalness = texture(tMetalness, vUv).b;
101
- float occlusion = texture(tOcclusion, vUv).r;
102
- vec3 emissive = texture(tEmissive, vUv).rgb;
129
+ float roughness = texture_supersample_4(tRoughness, vUv,uTextureLODBias).g;
130
+ float metalness = texture_supersample_4(tMetalness, vUv,uTextureLODBias).b;
131
+ float occlusion = texture_supersample_4(tOcclusion, vUv,uTextureLODBias).r;
132
+ vec3 emissive = texture_supersample_4(tEmissive, vUv,uTextureLODBias).rgb;
103
133
 
104
134
  gORM = vec4(occlusion, roughness, metalness, 1.0);
105
135
  }
@@ -146,6 +176,15 @@ export class BakeShaderStandard extends RawShaderMaterial {
146
176
  */
147
177
  projection_params: {
148
178
  value: new Vector4(0, 0, 0, 0)
179
+ },
180
+ /**
181
+ * Bias texture LOD, -0.5 pushes MIP switching a half a LOD further away, and produces more crisp-looking results
182
+ */
183
+ uTextureLODBias:{
184
+ value:-0.5
185
+ },
186
+ uAtlasResolution:{
187
+ value: new Vector2(1,1)
149
188
  }
150
189
  }
151
190
  });