@woosh/meep-engine 2.34.47 → 2.35.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/binary/BitSet.js +10 -3
- package/core/bvh2/BinaryNode.js +19 -35
- package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +5 -5
- package/core/bvh2/aabb3_combined_surface_area.js +21 -0
- package/core/bvh2/traversal/queryBinaryNode_FrustumIntersections.js +24 -12
- package/core/cache/Cache.d.ts +2 -0
- package/core/cache/Cache.js +27 -23
- package/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +1 -1
- package/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +29 -24
- package/core/math/max2.js +2 -6
- package/core/math/min2.js +2 -6
- package/engine/asset/loaders/geometry/geometry/computeGeometryEquality.js +3 -2
- package/engine/asset/loaders/geometry/geometry/computeGeometryHash.js +9 -1
- package/engine/ecs/EntityComponentDataset.js +7 -2
- package/engine/ecs/foliage/ViewState.js +13 -3
- package/engine/ecs/foliage/ecs/Foliage2System.js +15 -3
- package/engine/ecs/parent/EntityNode.js +23 -11
- package/engine/ecs/transform/Transform.js +15 -13
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +63 -26
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +63 -3
- package/engine/graphics/ecs/mesh-v2/render/AbstractRenderAdapter.js +67 -0
- package/engine/graphics/ecs/mesh-v2/render/GenericRendererAdapter.js +48 -0
- package/engine/graphics/ecs/mesh-v2/render/InstancedRendererAdapter.js +110 -0
- package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +98 -0
- package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +5 -0
- package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +23 -5
- package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +8 -3
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +23 -85
- package/engine/graphics/geometry/instancing/rewriteMaterial.js +9 -45
- package/engine/graphics/material/optimization/BUFFER_GEOMETRY_UVS.js +10 -0
- package/engine/graphics/material/optimization/MaterialDescriptor.js +46 -0
- package/engine/graphics/material/optimization/MaterialOptimizationContext.js +470 -201
- package/engine/graphics/material/optimization/UvContext.js +18 -0
- package/engine/graphics/material/optimization/is_compliant_mesh.js +71 -0
- package/engine/graphics/material/optimization/prepare_atlas_texture.js +23 -0
- package/engine/graphics/material/optimization/prototypeMaterialOptimizer.js +127 -0
- package/engine/graphics/micron/convert_three_object_to_micron.js +0 -2
- package/engine/graphics/micron/format/MicronGeometry.js +1 -3
- package/engine/graphics/micron/format/MicronGeometryPatch.js +34 -24
- package/engine/graphics/micron/format/VirtualGeometry.js +47 -11
- package/engine/graphics/micron/format/serialization/MicronGeometryBinarySerializationAdapter.js +22 -0
- package/engine/graphics/micron/prototypeVirtualGeometry.js +10 -5
- package/engine/graphics/micron/render/VirtualGeometryBuilder.js +14 -55
- package/engine/graphics/micron/render/instanced/AttributeDataTexture.js +1 -45
- package/engine/graphics/micron/render/instanced/ThreeInstancedAdapter.js +18 -7
- package/engine/graphics/micron/render/refinement/RefinementSpec.js +0 -12
- package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +118 -0
- package/engine/graphics/micron/render/v1/MaterialContext.js +3 -2
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +19 -4
- package/engine/graphics/render/utils/ThreeBypassRenderer.js +3 -2
- package/engine/graphics/texture/normalized_internal_format.js +48 -0
- package/engine/graphics/texture/sampler/Sampler2D.js +6 -0
- package/engine/graphics/texture/sampler/sampler2d_copy_channel_data.js +25 -0
- package/engine/graphics/texture/sampler/scaleSampler2D.js +3 -0
- package/engine/graphics/texture/sampler/util/drawSamplerHTML.js +14 -1
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { GLTFAssetLoader } from "../../../../asset/loaders/GLTFAssetLoader.js";
|
|
|
6
6
|
import { three_object_to_entity_composition } from "../three_object_to_entity_composition.js";
|
|
7
7
|
import { AttachmentSystem } from "../../../../ecs/attachment/AttachmentSystem.js";
|
|
8
8
|
import { TransformAttachmentSystem } from "../../../../ecs/transform-attachment/TransformAttachmentSystem.js";
|
|
9
|
+
import { Camera } from "../../camera/Camera.js";
|
|
9
10
|
|
|
10
11
|
const eh = new EngineHarness();
|
|
11
12
|
|
|
@@ -70,6 +71,10 @@ async function main(engine) {
|
|
|
70
71
|
enableTerrain: false
|
|
71
72
|
});
|
|
72
73
|
|
|
74
|
+
const camera = engine.entityManager.dataset.getAnyComponent(Camera);
|
|
75
|
+
camera.component.autoClip = false;
|
|
76
|
+
camera.component.object.far = 300;
|
|
77
|
+
|
|
73
78
|
// a small delay to let background tasks finish, so we can get better performance reading later on
|
|
74
79
|
timeout(20);
|
|
75
80
|
|
|
@@ -3,7 +3,7 @@ import { ShadedGeometrySystem } from "../ShadedGeometrySystem.js";
|
|
|
3
3
|
import EntityBuilder from "../../../../ecs/EntityBuilder.js";
|
|
4
4
|
import { Transform } from "../../../../ecs/transform/Transform.js";
|
|
5
5
|
import { ShadedGeometry } from "../ShadedGeometry.js";
|
|
6
|
-
import { BoxBufferGeometry,
|
|
6
|
+
import { BoxBufferGeometry, MeshStandardMaterial } from "three";
|
|
7
7
|
import { randomFloatBetween } from "../../../../../core/math/random/randomFloatBetween.js";
|
|
8
8
|
import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
|
|
9
9
|
import ViewportPosition from "../../../../ecs/gui/position/ViewportPosition.js";
|
|
@@ -13,9 +13,15 @@ import { downloadAsFile } from "../../../../../core/binary/ByteArrayTools.js";
|
|
|
13
13
|
import { convert_bvh_to_dot_format_string } from "../../../../../core/bvh2/visual/convert_bvh_to_dot_format_string.js";
|
|
14
14
|
import ViewportPositionSystem from "../../../../ecs/gui/position/ViewportPositionSystem.js";
|
|
15
15
|
import GUIElementSystem from "../../../../ecs/gui/GUIElementSystem.js";
|
|
16
|
+
import Vector3 from "../../../../../core/geom/Vector3.js";
|
|
17
|
+
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
18
|
+
import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
|
|
16
19
|
|
|
17
20
|
const eh = new EngineHarness();
|
|
18
21
|
|
|
22
|
+
const DRAW_METHOD_PLAIN = 0;
|
|
23
|
+
const DRAW_METHOD_INSTANCED = 1;
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
*
|
|
21
27
|
* @param {Engine} engine
|
|
@@ -26,12 +32,18 @@ async function main(engine) {
|
|
|
26
32
|
|
|
27
33
|
await em.addSystem(new ShadedGeometrySystem(engine));
|
|
28
34
|
|
|
29
|
-
EngineHarness.buildBasics({
|
|
35
|
+
EngineHarness.buildBasics({
|
|
36
|
+
engine,
|
|
37
|
+
yaw: -0.8,
|
|
38
|
+
pitch: 1,
|
|
39
|
+
distance: 46,
|
|
40
|
+
focus: new Vector3(10, 0, 10)
|
|
41
|
+
});
|
|
30
42
|
|
|
31
43
|
|
|
32
44
|
const ecd = em.dataset;
|
|
33
45
|
|
|
34
|
-
const material = new
|
|
46
|
+
const material = new MeshStandardMaterial({
|
|
35
47
|
color: 0xFFFFFF
|
|
36
48
|
});
|
|
37
49
|
|
|
@@ -45,6 +57,11 @@ async function main(engine) {
|
|
|
45
57
|
|
|
46
58
|
for (let i = 0; i < 100000; i++) {
|
|
47
59
|
|
|
60
|
+
const sg = ShadedGeometry.from(geometry, material);
|
|
61
|
+
|
|
62
|
+
sg.draw_method = DRAW_METHOD_INSTANCED;
|
|
63
|
+
sg.clearFlag(ShadedGeometryFlags.CastShadow | ShadedGeometryFlags.ReceiveShadow);
|
|
64
|
+
|
|
48
65
|
new EntityBuilder()
|
|
49
66
|
.add(Transform.fromJSON({
|
|
50
67
|
position: {
|
|
@@ -52,9 +69,10 @@ async function main(engine) {
|
|
|
52
69
|
y: randomFloatBetween(random, 0, 10),
|
|
53
70
|
z: randomFloatBetween(random, -50, 50)
|
|
54
71
|
},
|
|
55
|
-
|
|
72
|
+
rotation: Quaternion.random(random),
|
|
73
|
+
scale: 0.05
|
|
56
74
|
}))
|
|
57
|
-
.add(
|
|
75
|
+
.add(sg)
|
|
58
76
|
.build(ecd);
|
|
59
77
|
}
|
|
60
78
|
|
|
@@ -12,24 +12,29 @@ export function three_object_to_entity_composition(root) {
|
|
|
12
12
|
|
|
13
13
|
node.transform.fromMatrix4(root.matrix.elements);
|
|
14
14
|
|
|
15
|
-
node.entity
|
|
15
|
+
const entity = node.entity;
|
|
16
|
+
|
|
17
|
+
entity.add(new Transform());
|
|
16
18
|
|
|
17
19
|
if (root.isMesh) {
|
|
18
20
|
if (root.isSkinnedMesh) {
|
|
19
21
|
throw new Error(`Skinned meshes are not supported`);
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
const sg = ShadedGeometry.from(root.geometry, root.material);
|
|
25
|
+
sg.draw_method = 1;
|
|
26
|
+
|
|
27
|
+
entity.add(sg);
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
const children = root.children;
|
|
26
31
|
const child_count = children.length;
|
|
32
|
+
|
|
27
33
|
for (let i = 0; i < child_count; i++) {
|
|
28
34
|
const child = children[i];
|
|
29
35
|
|
|
30
36
|
const child_node = three_object_to_entity_composition(child);
|
|
31
37
|
|
|
32
|
-
|
|
33
38
|
node.addChild(child_node);
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -3,7 +3,8 @@ import {
|
|
|
3
3
|
InstancedBufferAttribute,
|
|
4
4
|
InstancedBufferGeometry,
|
|
5
5
|
MeshDepthMaterial,
|
|
6
|
-
RGBADepthPacking
|
|
6
|
+
RGBADepthPacking,
|
|
7
|
+
StreamDrawUsage
|
|
7
8
|
} from 'three';
|
|
8
9
|
import ThreeFactory from "../../three/ThreeFactory.js";
|
|
9
10
|
import { StaticMaterialCache } from "../../../asset/loaders/material/StaticMaterialCache.js";
|
|
@@ -66,21 +67,7 @@ export class InstancedMeshGroup {
|
|
|
66
67
|
* @type {InstancedBufferAttribute}
|
|
67
68
|
* @private
|
|
68
69
|
*/
|
|
69
|
-
this.
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
*
|
|
73
|
-
* @type {InstancedBufferAttribute}
|
|
74
|
-
* @private
|
|
75
|
-
*/
|
|
76
|
-
this.__attributeRotation = null;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
*
|
|
80
|
-
* @type {InstancedBufferAttribute}
|
|
81
|
-
* @private
|
|
82
|
-
*/
|
|
83
|
-
this.__attributeScale = null;
|
|
70
|
+
this.__attributeTransform = null;
|
|
84
71
|
|
|
85
72
|
/**
|
|
86
73
|
*
|
|
@@ -203,39 +190,16 @@ export class InstancedMeshGroup {
|
|
|
203
190
|
/**
|
|
204
191
|
*
|
|
205
192
|
* @param {number} index
|
|
206
|
-
* @param {number}
|
|
207
|
-
* @param {number} y
|
|
208
|
-
* @param {number} z
|
|
193
|
+
* @param {number[]|ArrayLike<number>|Float32Array} transform 4x4 transform matrix of the instance
|
|
209
194
|
*/
|
|
210
|
-
|
|
211
|
-
this.
|
|
212
|
-
this.__attributePosition.needsUpdate = true;
|
|
195
|
+
setTransformAt(index, transform) {
|
|
196
|
+
this.__attributeTransform.array.set(transform, index * 16);
|
|
213
197
|
}
|
|
214
198
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
* @param {number} index
|
|
218
|
-
* @param {number} x
|
|
219
|
-
* @param {number} y
|
|
220
|
-
* @param {number} z
|
|
221
|
-
* @param {number} w
|
|
222
|
-
*/
|
|
223
|
-
setRotationAt(index, x, y, z, w) {
|
|
224
|
-
this.__attributeRotation.setXYZW(index, x, y, z, w);
|
|
225
|
-
this.__attributeRotation.needsUpdate = true;
|
|
199
|
+
requestAttributeUpdate() {
|
|
200
|
+
this.__attributeTransform.needsUpdate = true;
|
|
226
201
|
}
|
|
227
202
|
|
|
228
|
-
/**
|
|
229
|
-
*
|
|
230
|
-
* @param {number} index
|
|
231
|
-
* @param {number} x
|
|
232
|
-
* @param {number} y
|
|
233
|
-
* @param {number} z
|
|
234
|
-
*/
|
|
235
|
-
setScaleAt(index, x, y, z) {
|
|
236
|
-
this.__attributeScale.setXYZ(index, x, y, z);
|
|
237
|
-
this.__attributeScale.needsUpdate = true;
|
|
238
|
-
}
|
|
239
203
|
|
|
240
204
|
/**
|
|
241
205
|
* Swap position in attribute arrays of two elements
|
|
@@ -327,25 +291,13 @@ export class InstancedMeshGroup {
|
|
|
327
291
|
delete references[index];
|
|
328
292
|
} else {
|
|
329
293
|
//not at the end, move the very last reference to this place, effectively shrinking the set
|
|
330
|
-
const index3 = index * 3;
|
|
331
|
-
const start3 = lastIndex * 3;
|
|
332
|
-
const end3 = start3 + 3;
|
|
333
294
|
|
|
334
|
-
const index4 = index * 4;
|
|
335
|
-
const start4 = lastIndex * 4;
|
|
336
|
-
const end4 = start4 + 4;
|
|
337
295
|
|
|
338
|
-
const
|
|
339
|
-
const a_rotation = this.__attributeRotation;
|
|
340
|
-
const a_scale = this.__attributeScale;
|
|
296
|
+
const a_transform = this.__attributeTransform;
|
|
341
297
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
a_scale.array.copyWithin(index3, start3, end3);
|
|
298
|
+
a_transform.array.copyWithin(index * 16, lastIndex * 16, lastIndex * 16 + 16);
|
|
299
|
+
a_transform.needsUpdate = true;
|
|
345
300
|
|
|
346
|
-
a_position.needsUpdate = true;
|
|
347
|
-
a_rotation.needsUpdate = true;
|
|
348
|
-
a_scale.needsUpdate = true;
|
|
349
301
|
|
|
350
302
|
//update moved reference index
|
|
351
303
|
const movedReference = references[lastIndex];
|
|
@@ -391,39 +343,25 @@ export class InstancedMeshGroup {
|
|
|
391
343
|
}
|
|
392
344
|
|
|
393
345
|
//build instanced attributes
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
//copy old data
|
|
400
|
-
const oldPositionArray = this.__attributePosition.array;
|
|
401
|
-
typed_array_copy(oldPositionArray, newPositionArray);
|
|
402
|
-
}
|
|
403
|
-
if (this.__attributeRotation !== null) {
|
|
404
|
-
//copy old data
|
|
405
|
-
const oldRotationArray = this.__attributeRotation.array;
|
|
406
|
-
typed_array_copy(oldRotationArray, newRotationArray);
|
|
407
|
-
}
|
|
408
|
-
if (this.__attributeScale !== null) {
|
|
409
|
-
const oldScaleArray = this.__attributeScale.array;
|
|
410
|
-
typed_array_copy(oldScaleArray, newScaleArray);
|
|
346
|
+
const newTransformArray = new Float32Array(this.capacity * 16);
|
|
347
|
+
|
|
348
|
+
if (this.__attributeTransform !== null) {
|
|
349
|
+
const oldTransformArray = this.__attributeTransform.array;
|
|
350
|
+
typed_array_copy(oldTransformArray, newTransformArray);
|
|
411
351
|
|
|
412
|
-
if (
|
|
413
|
-
//fill the rest of the array with
|
|
414
|
-
|
|
352
|
+
if (newTransformArray.length > oldTransformArray.length) {
|
|
353
|
+
//fill the rest of the array with 0s
|
|
354
|
+
// TODO consider writing identity matrix instead
|
|
355
|
+
newTransformArray.fill(0, oldTransformArray.length);
|
|
415
356
|
}
|
|
416
357
|
}
|
|
417
358
|
|
|
418
359
|
//rewrite old attributes
|
|
419
|
-
this.
|
|
420
|
-
this.
|
|
421
|
-
this.__attributeScale = new InstancedBufferAttribute(newScaleArray, 3);
|
|
360
|
+
this.__attributeTransform = new InstancedBufferAttribute(newTransformArray, 16);
|
|
361
|
+
this.__attributeTransform.setUsage(StreamDrawUsage);
|
|
422
362
|
|
|
423
363
|
//add attributes to newly created geometry
|
|
424
|
-
geometry.setAttribute("
|
|
425
|
-
geometry.setAttribute("instanceRotation", this.__attributeRotation);
|
|
426
|
-
geometry.setAttribute("instanceScale", this.__attributeScale);
|
|
364
|
+
geometry.setAttribute("instanceMatrix", this.__attributeTransform);
|
|
427
365
|
|
|
428
366
|
|
|
429
367
|
this.mesh.geometry = geometry;
|
|
@@ -1,55 +1,19 @@
|
|
|
1
1
|
const SHADER_PREAMBLE = `
|
|
2
|
-
attribute
|
|
3
|
-
|
|
4
|
-
attribute vec3 instanceScale;
|
|
5
|
-
|
|
6
|
-
vec3 instanceTransform( in vec3 position, vec3 T, vec4 R, vec3 S ){
|
|
7
|
-
vec3 result = position;
|
|
8
|
-
|
|
9
|
-
//applies the scale
|
|
10
|
-
result *= S;
|
|
11
|
-
//computes the rotation where R is a (vec4) quaternion
|
|
12
|
-
result += 2.0 * cross( R.xyz, cross( R.xyz, result ) + R.w * result );
|
|
13
|
-
//translates the transformed 'blueprint'
|
|
14
|
-
result += T;
|
|
15
|
-
|
|
16
|
-
return result;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
mat4 getInstanceMatrix(){
|
|
20
|
-
vec4 q = instanceRotation;
|
|
21
|
-
vec3 s = instanceScale;
|
|
22
|
-
vec3 v = instancePosition;
|
|
23
|
-
|
|
24
|
-
vec3 q2 = q.xyz + q.xyz;
|
|
25
|
-
vec3 a = q.xxx * q2.xyz;
|
|
26
|
-
vec3 b = q.yyz * q2.yzz;
|
|
27
|
-
vec3 c = q.www * q2.xyz;
|
|
28
|
-
|
|
29
|
-
vec3 r0 = vec3( 1.0 - (b.x + b.z) , a.y + c.z , a.z - c.y ) * s.xxx;
|
|
30
|
-
vec3 r1 = vec3( a.y - c.z , 1.0 - (a.x + b.z) , b.y + c.x ) * s.yyy;
|
|
31
|
-
vec3 r2 = vec3( a.z + c.y , b.y - c.x , 1.0 - (a.x + b.x) ) * s.zzz;
|
|
32
|
-
|
|
33
|
-
return mat4(
|
|
34
|
-
r0 , 0.0,
|
|
35
|
-
r1 , 0.0,
|
|
36
|
-
r2 , 0.0,
|
|
37
|
-
v , 1.0
|
|
38
|
-
);
|
|
39
|
-
}\n`;
|
|
2
|
+
attribute mat4 instanceMatrix;
|
|
3
|
+
\n`;
|
|
40
4
|
|
|
41
5
|
export function rewriteMaterial(shader) {
|
|
42
6
|
const originalVertexShader = shader.vertexShader;
|
|
43
7
|
|
|
44
8
|
const newVertexShader = SHADER_PREAMBLE
|
|
45
9
|
+ originalVertexShader
|
|
46
|
-
.replace(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
10
|
+
// .replace(
|
|
11
|
+
// '#include <uv_vertex>',
|
|
12
|
+
// `
|
|
13
|
+
// mat4 instanceMatrix = getInstanceMatrix();
|
|
14
|
+
// #include <uv_vertex>
|
|
15
|
+
// `
|
|
16
|
+
// )
|
|
53
17
|
.replace(
|
|
54
18
|
'#include <begin_vertex>',
|
|
55
19
|
`
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { traverseMaterialTextures } from "../../../asset/loaders/material/traverseMaterialTextures.js";
|
|
2
|
+
import { UvContext } from "./UvContext.js";
|
|
3
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
4
|
+
|
|
5
|
+
export class MaterialDescriptor {
|
|
6
|
+
constructor() {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @type {THREE.Material|null}
|
|
11
|
+
*/
|
|
12
|
+
this.source_material = null;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @type {UvContext[]}
|
|
17
|
+
*/
|
|
18
|
+
this.uvs = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
build_uvs() {
|
|
22
|
+
|
|
23
|
+
traverseMaterialTextures(this.source_material, (t, attachment) => {
|
|
24
|
+
const uv_index = attachment.uv_index;
|
|
25
|
+
|
|
26
|
+
let uv_context = this.uvs[uv_index];
|
|
27
|
+
|
|
28
|
+
if (uv_context === undefined) {
|
|
29
|
+
uv_context = new UvContext();
|
|
30
|
+
uv_context.resolution.set(1, 1);
|
|
31
|
+
|
|
32
|
+
this.uvs[uv_index] = uv_context;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const image = t.image;
|
|
36
|
+
|
|
37
|
+
if (image !== undefined && image.width !== undefined) {
|
|
38
|
+
uv_context.resolution.x = max2(uv_context.resolution.x, image.width);
|
|
39
|
+
uv_context.resolution.y = max2(uv_context.resolution.y, image.height);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|