minerender 2.1.0-alpha.73 → 2.1.0-alpha.74

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.
@@ -291,7 +291,7 @@ declare class Materials {
291
291
  */
292
292
  static createEntityCanvasMaterial(canvas: HTMLCanvasElement, mode?: EntityRenderMode, tint?: ColorRepresentation): MeshBasicMaterial;
293
293
  static createGuiCanvasMaterial(canvas: HTMLCanvasElement): MeshBasicMaterial;
294
- static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent?: boolean, shade?: boolean): Material;
294
+ static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent?: boolean, shade?: boolean, boundUvs?: boolean): Material;
295
295
  static getImage(key: MaterialKey): Material;
296
296
  static needsUpdate(mat: Material): void;
297
297
  }
@@ -693,6 +693,8 @@ declare class UVMapper {
693
693
  static setCubeUvs(geometry: BoxGeometry, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, faces: ModelFaces): void;
694
694
  static facesToUvArray(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): number[];
695
695
  static facesToUv(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): Float32BufferAttribute;
696
+ /** Bounds texture sampling to texel centres without changing cropped face UVs. */
697
+ static setAtlasUvBounds(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas): void;
696
698
  static lockUvs(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas, rotation: Euler): void;
697
699
  static getAtlas(model: Model): Promise<Maybe<TextureAtlas>>;
698
700
  static fillMissingTextureKeys<T>(textures: ModelTextures, target: {
@@ -291,7 +291,7 @@ declare class Materials {
291
291
  */
292
292
  static createEntityCanvasMaterial(canvas: HTMLCanvasElement, mode?: EntityRenderMode, tint?: ColorRepresentation): MeshBasicMaterial;
293
293
  static createGuiCanvasMaterial(canvas: HTMLCanvasElement): MeshBasicMaterial;
294
- static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent?: boolean, shade?: boolean): Material;
294
+ static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent?: boolean, shade?: boolean, boundUvs?: boolean): Material;
295
295
  static getImage(key: MaterialKey): Material;
296
296
  static needsUpdate(mat: Material): void;
297
297
  }
@@ -693,6 +693,8 @@ declare class UVMapper {
693
693
  static setCubeUvs(geometry: BoxGeometry, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, faces: ModelFaces): void;
694
694
  static facesToUvArray(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): number[];
695
695
  static facesToUv(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): Float32BufferAttribute;
696
+ /** Bounds texture sampling to texel centres without changing cropped face UVs. */
697
+ static setAtlasUvBounds(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas): void;
696
698
  static lockUvs(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas, rotation: Euler): void;
697
699
  static getAtlas(model: Model): Promise<Maybe<TextureAtlas>>;
698
700
  static fillMissingTextureKeys<T>(textures: ModelTextures, target: {
@@ -982,7 +982,7 @@ var init_Materials = __esm({
982
982
  };
983
983
  return material;
984
984
  }
985
- static createShadedCanvasMaterial(canvas, transparent = false, shade = false) {
985
+ static createShadedCanvasMaterial(canvas, transparent = false, shade = false, boundUvs = false) {
986
986
  const vertShader = `
987
987
  uniform bool SHADE;
988
988
 
@@ -992,6 +992,10 @@ var init_Materials = __esm({
992
992
  #else
993
993
  varying vec2 vUv;
994
994
  #endif
995
+ #ifdef BOUND_UVS
996
+ attribute vec4 uvBounds;
997
+ flat out vec4 vUvBounds;
998
+ #endif
995
999
  varying vec3 vTint;
996
1000
  varying float light;
997
1001
  varying float lift;
@@ -1027,13 +1031,17 @@ var init_Materials = __esm({
1027
1031
  }
1028
1032
 
1029
1033
  vUv = uv;
1034
+ #ifdef BOUND_UVS
1035
+ vUvBounds = uvBounds;
1036
+ #endif
1030
1037
  vTint = color;
1031
1038
 
1039
+ vec4 mvPosition = vec4(position, 1.0);
1032
1040
  #ifdef USE_INSTANCING
1033
- gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
1034
- #else
1035
- gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
1041
+ mvPosition = instanceMatrix * mvPosition;
1036
1042
  #endif
1043
+ mvPosition = modelViewMatrix * mvPosition;
1044
+ gl_Position = projectionMatrix * mvPosition;
1037
1045
 
1038
1046
  }
1039
1047
  `;
@@ -1053,13 +1061,22 @@ var init_Materials = __esm({
1053
1061
  #else
1054
1062
  varying vec2 vUv;
1055
1063
  #endif
1064
+ #ifdef BOUND_UVS
1065
+ flat in vec4 vUvBounds;
1066
+ #endif
1056
1067
  varying vec3 vTint;
1057
1068
  varying float light;
1058
1069
  varying float lift;
1059
1070
 
1060
1071
  void main(void)
1061
1072
  {
1062
- vec4 color = texture2D(map, vUv);
1073
+ #ifdef BOUND_UVS
1074
+ // Keep edge samples inside their texture even without centroid interpolation.
1075
+ vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);
1076
+ #else
1077
+ vec2 mapUv = vUv;
1078
+ #endif
1079
+ vec4 color = texture2D(map, mapUv);
1063
1080
  color.rgb *= vTint;
1064
1081
 
1065
1082
  if (color.a < 0.01) discard;
@@ -1080,7 +1097,8 @@ var init_Materials = __esm({
1080
1097
  }
1081
1098
  `;
1082
1099
  try {
1083
- return new import_three5.ShaderMaterial({
1100
+ const material = new import_three5.ShaderMaterial({
1101
+ defines: boundUvs ? { BOUND_UVS: true } : {},
1084
1102
  uniforms: {
1085
1103
  SHADE: { value: true },
1086
1104
  BRIGHTNESS: { value: 1 },
@@ -1098,6 +1116,8 @@ var init_Materials = __esm({
1098
1116
  side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1099
1117
  alphaTest: 0.5
1100
1118
  });
1119
+ Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
1120
+ return material;
1101
1121
  } catch (e) {
1102
1122
  console.warn(e);
1103
1123
  }
@@ -2979,6 +2999,37 @@ var init_UVMapper = __esm({
2979
2999
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2980
3000
  return new import_three9.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2981
3001
  }
3002
+ /** Bounds texture sampling to texel centres without changing cropped face UVs. */
3003
+ static setAtlasUvBounds(geometry, faces, atlas) {
3004
+ const uv = geometry.getAttribute("uv");
3005
+ const bounds = new Float32Array(uv.count * 4);
3006
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
3007
+ const texture = faces[faceName]?.texture?.substring(1);
3008
+ const position = texture && atlas.positions[texture];
3009
+ const size = texture && atlas.sizes[texture];
3010
+ let minU = Infinity, minV = Infinity, maxU = -Infinity, maxV = -Infinity;
3011
+ if (position && size) {
3012
+ minU = position[0] / atlas.image.width;
3013
+ maxU = (position[0] + size[0]) / atlas.image.width;
3014
+ minV = 1 - (position[1] + size[1]) / atlas.image.height;
3015
+ maxV = 1 - position[1] / atlas.image.height;
3016
+ } else {
3017
+ for (let corner = 0; corner < 4; corner++) {
3018
+ const index = faceIndex * 4 + corner;
3019
+ minU = Math.min(minU, uv.getX(index));
3020
+ minV = Math.min(minV, uv.getY(index));
3021
+ maxU = Math.max(maxU, uv.getX(index));
3022
+ maxV = Math.max(maxV, uv.getY(index));
3023
+ }
3024
+ }
3025
+ const insetU = Math.min(0.5 / atlas.image.width, (maxU - minU) / 2);
3026
+ const insetV = Math.min(0.5 / atlas.image.height, (maxV - minV) / 2);
3027
+ for (let corner = 0; corner < 4; corner++) {
3028
+ bounds.set([minU + insetU, minV + insetV, maxU - insetU, maxV - insetV], (faceIndex * 4 + corner) * 4);
3029
+ }
3030
+ }
3031
+ geometry.setAttribute("uvBounds", new import_three9.Float32BufferAttribute(bounds, 4));
3032
+ }
2982
3033
  static lockUvs(geometry, faces, atlas, rotation) {
2983
3034
  const uv = geometry.getAttribute("uv");
2984
3035
  for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
@@ -5376,6 +5427,7 @@ var init_ModelObject = __esm({
5376
5427
  if (this.options.uvLockRotation) {
5377
5428
  UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three25.Euler(...this.options.uvLockRotation));
5378
5429
  }
5430
+ UVMapper.setAtlasUvBounds(elGeo, el.faces, this.atlas);
5379
5431
  if (this.options.tints) {
5380
5432
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
5381
5433
  for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
@@ -5441,7 +5493,7 @@ var init_ModelObject = __esm({
5441
5493
  }
5442
5494
  applyTextures() {
5443
5495
  if (this.atlas) {
5444
- const mat = Materials.createShadedCanvasMaterial(this.atlas.image.canvas, this.atlas.hasTransparency, false);
5496
+ const mat = Materials.createShadedCanvasMaterial(this.atlas.image.canvas, this.atlas.hasTransparency, false, true);
5445
5497
  this.atlasMaterial = mat;
5446
5498
  this.atlasTexture = mat.uniforms?.map?.value ?? mat.map;
5447
5499
  this.iterateAllMeshes((mesh) => {
@@ -15549,14 +15601,17 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
15549
15601
  for (const { atlas, x, y } of page.placements) {
15550
15602
  context.drawImage(atlas.image.canvas, x, y);
15551
15603
  }
15552
- const positions = [], normals = [], uvs = [], colors = [], indices = [];
15604
+ const positions = [], normals = [], uvs = [], uvBounds = [], colors = [], indices = [];
15553
15605
  for (const { index, template, cullMask } of page.entries) {
15554
15606
  const position = template.geometry.getAttribute("position");
15555
15607
  const normal = template.geometry.getAttribute("normal");
15556
15608
  const uv = template.geometry.getAttribute("uv");
15609
+ const bounds = template.geometry.getAttribute("uvBounds");
15557
15610
  const color = template.geometry.getAttribute("color");
15558
15611
  const sourceIndices = template.geometry.getIndex();
15559
15612
  const placement = locations.get(template.atlas).placement;
15613
+ const mapU = (u) => (placement.x + u * template.atlas.image.width) / page.width;
15614
+ const mapV = (v) => 1 - (placement.y + (1 - v) * template.atlas.image.height) / page.height;
15560
15615
  const offsetX = index % 16 * 16;
15561
15616
  const offsetY = Math.floor(index / 256) * 16;
15562
15617
  const offsetZ = Math.floor(index / 16) % 16 * 16;
@@ -15567,9 +15622,12 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
15567
15622
  const vertex = face * 4 + corner;
15568
15623
  positions.push(position.getX(vertex) + offsetX, position.getY(vertex) + offsetY, position.getZ(vertex) + offsetZ);
15569
15624
  normals.push(normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex));
15570
- uvs.push(
15571
- (placement.x + uv.getX(vertex) * template.atlas.image.width) / page.width,
15572
- 1 - (placement.y + (1 - uv.getY(vertex)) * template.atlas.image.height) / page.height
15625
+ uvs.push(mapU(uv.getX(vertex)), mapV(uv.getY(vertex)));
15626
+ uvBounds.push(
15627
+ mapU(bounds?.getX(vertex) ?? 0),
15628
+ mapV(bounds?.getY(vertex) ?? 0),
15629
+ mapU(bounds?.getZ(vertex) ?? 1),
15630
+ mapV(bounds?.getW(vertex) ?? 1)
15573
15631
  );
15574
15632
  colors.push(color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1);
15575
15633
  }
@@ -15580,11 +15638,12 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
15580
15638
  geometry.setAttribute("position", new import_three40.Float32BufferAttribute(positions, 3));
15581
15639
  geometry.setAttribute("normal", new import_three40.Float32BufferAttribute(normals, 3));
15582
15640
  geometry.setAttribute("uv", new import_three40.Float32BufferAttribute(uvs, 2));
15641
+ geometry.setAttribute("uvBounds", new import_three40.Float32BufferAttribute(uvBounds, 4));
15583
15642
  geometry.setAttribute("color", new import_three40.Float32BufferAttribute(colors, 3));
15584
15643
  geometry.setIndex(indices);
15585
15644
  geometry.computeBoundingBox();
15586
15645
  geometry.computeBoundingSphere();
15587
- const material = Materials.createShadedCanvasMaterial(canvas, false);
15646
+ const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
15588
15647
  material.vertexColors = true;
15589
15648
  const texture = material.uniforms?.map?.value ?? material.map;
15590
15649
  const mesh = new import_three40.Mesh(geometry, material);