Skip to content

Commit

Permalink
add dynamic packing
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjythebee committed Oct 17, 2024
1 parent fbdf7fa commit 097d28c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"jszip": "^3.10.1",
"ktx2-encoder": "^0.0.6",
"postprocessing": "^6.29.1",
"potpack": "^2.0.0",
"react": "^18.2.0",
"react-color": "^2.19.3",
"react-colorful": "^5.6.1",
Expand Down
49 changes: 40 additions & 9 deletions src/library/create-texture-atlas.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as THREE from "three";
import { mergeGeometry } from "./merge-geometry.js";
import { MToonMaterial } from "@pixiv/three-vrm";
import potpack, { PotpackBox } from 'potpack';

let container, cameraRTT, sceneRTT, material, quad, renderer, rtTexture;
function ResetRenderTextureContainer(){
Expand Down Expand Up @@ -295,15 +296,44 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,
IMAGE_NAMES.map((name) => [name, createContext({ width: ATLAS_SIZE_PX, height: ATLAS_SIZE_PX, transparent:transparentTexture && name == "diffuse" })])
);

const numTiles = Math.floor(Math.sqrt(meshes.length) + 1);
const tileSize = ATLAS_SIZE_PX / numTiles;
const meshTriangleSorted = bakeObjects.map<[THREE.Mesh,number]>((bakeObject) => {
const geometry = bakeObject.mesh.geometry;
return [bakeObject.mesh, geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3];
}).sort((a, b) => b[1] - a[1]);

console.log(meshTriangleSorted);
/**
* We use the log10 of the number of triangles for a better -more natural- distribution of the textures
*/
const sumOfTriangles = meshTriangleSorted.reduce((acc, [, count]) => acc + Math.log10(count), 0); // sum of all triangles
const triangleRatio = meshTriangleSorted.map(([, count]) => Math.log10(count) / sumOfTriangles); // ratio of each mesh
const textureSizes = triangleRatio.map((ratio) => Math.floor(ATLAS_SIZE_PX * ratio)); // size of each textures in the texture

// boxes are mutated by potpack; sorted by height
const boxes = textureSizes.map((size) => ({w:size, h:size}));

const {w,h,fill} = potpack(boxes);
console.log('Packing efficiency:', fill);
console.log( fill);

const ratio = ATLAS_SIZE_PX / Math.max(w,h);

// scale the boxes to the size of the texture
const scaledBoxes = boxes.map((box) => {
return {x:Math.ceil((box.x||0 )* ratio), y:Math.ceil((box.y||0) * ratio), width:Math.ceil(box.w*ratio), height:Math.ceil(box.h*ratio)}
});
console.log(scaledBoxes)

const tileSize = new Map(scaledBoxes.map((square, i) => {
return [bakeObjects[i].mesh, square];
}))

// get the min/max of the uvs of each mesh
const originalUVs = new Map(
bakeObjects.map((bakeObject, i) => {
const min = new THREE.Vector2(i % numTiles, Math.floor(i / numTiles)).multiplyScalar(1 / numTiles);
const max = new THREE.Vector2(min.x + 1 / numTiles, min.y + 1 / numTiles);
return [bakeObject.mesh, { min, max }];
scaledBoxes.map((square, i) => {
const min = new THREE.Vector2(square.x, square.y);
const max = new THREE.Vector2((square.x + square.width), (square.y + square.height));
return [bakeObjects[i].mesh, { min, max }];
})
);

Expand Down Expand Up @@ -339,9 +369,6 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,
const xScaleFactor = 1 / (maxUv.x - minUv.x);
const yScaleFactor = 1 / (maxUv.y - minUv.y);

const xTileSize = tileSize * xScaleFactor;
const yTileSize = tileSize * yScaleFactor;

const uvs = new Map(
bakeObjects.map((bakeObject) => {
let { min, max } = originalUVs.get(bakeObject.mesh);
Expand All @@ -358,6 +385,10 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,
bakeObjects.forEach((bakeObject) => {
const { material, mesh } = bakeObject;
const { min, max } = uvs.get(mesh);

const xTileSize = tileSize.get(mesh).width;
const yTileSize = tileSize.get(mesh).height;

IMAGE_NAMES.forEach((name) => {
const context = contexts[name];
//context.globalAlpha = transparent ? 0.2 : 1;
Expand Down

0 comments on commit 097d28c

Please sign in to comment.