@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.
- package/core/geom/3d/apply_mat4_transform_to_v3_array.js +2 -4
- package/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +28 -0
- package/core/geom/Quaternion.js +14 -0
- package/engine/EngineHarness.js +9 -3
- package/engine/ecs/transform/Transform.js +23 -3
- package/engine/graphics/ecs/decal/v2/Decal.d.ts +11 -0
- package/engine/graphics/ecs/decal/v2/Decal.js +50 -0
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.d.ts +8 -0
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +213 -0
- package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +237 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +8 -1
- package/engine/graphics/ecs/mesh-v2/build_three_object.js +4 -0
- package/engine/graphics/geometry/MikkT/MikkTSpace.js +466 -305
- package/engine/graphics/geometry/buffered/computeGeometryEquality.js +1 -1
- package/engine/graphics/geometry/buffered/computeGeometryHash.js +1 -1
- package/engine/graphics/impostors/octahedral/ImpostorBaker.js +27 -14
- package/engine/graphics/impostors/octahedral/ImpostorDescription.js +6 -0
- package/engine/graphics/impostors/octahedral/README.md +1 -0
- package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere.js +25 -22
- package/engine/graphics/impostors/octahedral/bake/compute_bounding_sphere_radius_only.js +37 -0
- package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +30 -1
- package/engine/graphics/impostors/octahedral/grid/HemiOctahedralUvEncoder.js +1 -1
- package/engine/graphics/impostors/octahedral/prototypeBaker.js +121 -22
- package/engine/graphics/impostors/octahedral/shader/BakeShaderStandard.js +46 -7
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV0.js +349 -0
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderV1.js +74 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/common.glsl +209 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/flagment.glsl +80 -0
- package/engine/graphics/impostors/octahedral/shader/glsl/v1/vertex.glsl +350 -0
- package/engine/graphics/micron/render/v1/getTransformedPositionsCached.js +1 -1
- package/engine/graphics/render/forward_plus/LightManager.js +1 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +1 -3
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +2 -1
- package/engine/graphics/render/forward_plus/model/Decal.js +19 -2
- package/engine/graphics/texture/sampler/Sampler2D.js +10 -10
- package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +117 -11
- package/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +66 -0
- package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +2 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isArrayEqualStrict } from "../../../../core/collection/array/isArrayEqualStrict.
|
|
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.
|
|
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}
|
|
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
|
-
|
|
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
|
-
//
|
|
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(
|
|
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,
|
|
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
|
|
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
|
-
|
|
333
|
+
bounding_sphere,
|
|
322
334
|
encoder
|
|
323
335
|
});
|
|
324
336
|
|
|
325
337
|
r.capture_type = type;
|
|
326
|
-
r.sphere_radius =
|
|
338
|
+
r.sphere_radius = bounding_sphere[3];
|
|
339
|
+
vec3.copy(r.offset,bounding_sphere);
|
|
327
340
|
|
|
328
341
|
console.timeEnd('bake');
|
|
329
342
|
|
|
@@ -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 {
|
|
2
|
-
import {
|
|
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
|
|
10
|
+
let total_point_count = 0;
|
|
11
|
+
const object_count = objects.length;
|
|
14
12
|
|
|
15
|
-
|
|
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
|
|
16
|
+
const geometry = object.mesh.geometry;
|
|
21
17
|
|
|
22
|
-
const
|
|
18
|
+
const attribute = geometry.getAttribute('position');
|
|
23
19
|
|
|
24
|
-
|
|
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
|
|
30
|
+
const geometry = object.mesh.geometry;
|
|
27
31
|
|
|
28
|
-
|
|
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
|
-
|
|
34
|
+
const source_length = attribute.array.length;
|
|
34
35
|
|
|
35
|
-
|
|
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
|
|
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(
|
|
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;
|
|
@@ -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
|
-
|
|
39
|
-
// const
|
|
40
|
-
// const
|
|
41
|
-
// const
|
|
42
|
-
const
|
|
43
|
-
// const
|
|
44
|
-
// const
|
|
45
|
-
// const
|
|
46
|
-
// const
|
|
47
|
-
// const
|
|
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:
|
|
80
|
-
resolution:
|
|
81
|
-
type: ImpostorCaptureType.
|
|
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[
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
100
|
-
float metalness =
|
|
101
|
-
float occlusion =
|
|
102
|
-
vec3 emissive =
|
|
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
|
});
|