Skip to content

Commit

Permalink
move texture renderer to own class
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjythebee committed Oct 20, 2024
1 parent a601638 commit 28c6a15
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 99 deletions.
103 changes: 4 additions & 99 deletions src/library/create-texture-atlas.js
Original file line number Diff line number Diff line change
@@ -1,100 +1,7 @@
import * as THREE from "three";
import { mergeGeometry } from "./merge-geometry.js";
import { MToonMaterial } from "@pixiv/three-vrm";

let container, cameraRTT, sceneRTT, material, quad, renderer, rtTexture;
function ResetRenderTextureContainer(){
if (renderer != null)
renderer.clear(true, true);
}

function createSolidColorTexture(color, width, height) {

const size = width * height;
const data = new Uint8Array( 4 * size );

const r = Math.floor( color.r * 255 );
const g = Math.floor( color.g * 255 );
const b = Math.floor( color.b * 255 );

for ( let i = 0; i < size; i ++ ) {
const stride = i * 4;
data[ stride ] = r;
data[ stride + 1 ] = g;
data[ stride + 2 ] = b;
data[ stride + 3 ] = 255;
}

// used the buffer to create a DataTexture
const texture = new THREE.DataTexture( data, width, height );
texture.needsUpdate = true;
return texture
}

function RenderTextureImageData(texture, multiplyColor, clearColor, width, height, isTransparent, sRGBEncoding = true) {
// if texture is null or undefined, create a texture only with clearColor (that is color type)
if (!texture) {
texture = createSolidColorTexture(clearColor, width, height);
}

if (container == null) {
container = document.createElement("div");
sceneRTT = new THREE.Scene();
cameraRTT = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, -10000, 10000);
cameraRTT.position.z = 100;

sceneRTT.add(cameraRTT);

material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
transparent: true,
opacity: 1,
color: new THREE.Color(1, 1, 1),
});

const plane = new THREE.PlaneGeometry(1, 1);
quad = new THREE.Mesh(plane, material);
quad.scale.set(width,height,1);
sceneRTT.add(quad);

renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(1);
renderer.setSize(width, height);
//renderer.setClearColor(new THREE.Color(1, 1, 1), 1);
renderer.autoClear = false;

container.appendChild(renderer.domElement);

} else {
cameraRTT.left = -width / 2;
cameraRTT.right = width / 2;
cameraRTT.top = height / 2;
cameraRTT.bottom = - height / 2;

cameraRTT.updateProjectionMatrix();
quad.scale.set(width,height,1)

renderer.setSize(width, height);
}

rtTexture = new THREE.WebGLRenderTarget(width, height);
rtTexture.texture.encoding = sRGBEncoding ? THREE.sRGBEncoding : THREE.NoColorSpace;

material.map = texture;
material.color = multiplyColor.clone();
// set opacoty to 0 if texture is transparent
renderer.setClearColor(clearColor.clone(), isTransparent ? 0 : 1);

renderer.setRenderTarget(rtTexture);
renderer.clear();
renderer.render(sceneRTT, cameraRTT);

let buffer = new Uint8ClampedArray(rtTexture.width * rtTexture.height * 4)
renderer.readRenderTargetPixels(rtTexture, 0, 0, width, height, buffer);
const imgData = new ImageData(buffer, width, height)

return imgData;
}
import TextureImageDataRenderer from "./textureImageDataRenderer.js";

function createContext({ width, height, transparent }) {
const canvas = document.createElement("canvas");
Expand Down Expand Up @@ -256,9 +163,6 @@ export const createTextureAtlasNode = async ({ meshes, atlasSize, mtoon, transpa
};

export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize, mtoon, transparentMaterial, transparentTexture, twoSidedMaterial }) => {
// make sure to reset texture renderer container
ResetRenderTextureContainer();

const ATLAS_SIZE_PX = atlasSize;
const IMAGE_NAMES = mtoon ? ["diffuse"] : ["diffuse", "orm", "normal"];// not using normal texture for now
const bakeObjects = [];
Expand Down Expand Up @@ -355,6 +259,7 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,


let usesNormal = false;
const textureImageDataRenderer = new TextureImageDataRenderer(ATLAS_SIZE_PX, ATLAS_SIZE_PX);
bakeObjects.forEach((bakeObject) => {
const { material, mesh } = bakeObject;
const { min, max } = uvs.get(mesh);
Expand Down Expand Up @@ -391,7 +296,7 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,
if (usesNormal == false && name == 'normal' && texture != null){
usesNormal = true;
}
const imgData = RenderTextureImageData(texture, multiplyColor, clearColor, ATLAS_SIZE_PX, ATLAS_SIZE_PX, name == 'diffuse' && transparentTexture, name != 'normal');
const imgData = textureImageDataRenderer.render(texture, multiplyColor, clearColor, ATLAS_SIZE_PX, ATLAS_SIZE_PX, name == 'diffuse' && transparentTexture, name != 'normal');
createImageBitmap(imgData)// bmp is trasnaprent
.then((bmp) => context.drawImage(bmp, min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, xTileSize, yTileSize));
});
Expand Down Expand Up @@ -432,7 +337,7 @@ export const createTextureAtlasBrowser = async ({ backColor, meshes, atlasSize,
// // meshBufferGeometry is a THREE.BufferGeometry
// const meshBufferGeometry = mesh.geometry;
});

textureImageDataRenderer.destroy();
// Create textures from canvases
const textures = Object.fromEntries(
await Promise.all(
Expand Down
124 changes: 124 additions & 0 deletions src/library/textureImageDataRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import * as THREE from 'three'

export default class TextureImageDataRenderer {
width
height
cameraRTT = null
sceneRTT = null
material = null
quad = null
renderer = null
rtTexture = null
constructor(width, height) {
this.width = width
this.height = height
}

render(texture, multiplyColor, clearColor, width, height, isTransparent,sRGBEncoding = true) {
// if texture is null or undefined, create a texture only with clearColor (that is color type)
if (!texture) {
texture = TextureImageDataRenderer.createSolidColorTexture(clearColor, width, height)
}

if (this.renderer == null) {
this.sceneRTT = new THREE.Scene()
this.cameraRTT = new THREE.OrthographicCamera(-width / 2, width / 2, height / 2, -height / 2, -10000, 10000)
this.cameraRTT.position.z = 100

this.sceneRTT.add(this.cameraRTT)

this.material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
transparent: true,
opacity: 1,
color: new THREE.Color(1, 1, 1),
})

const plane = new THREE.PlaneGeometry(1, 1)
this.quad = new THREE.Mesh(plane, this.material)
this.quad.scale.set(width, height, 1)
this.sceneRTT.add(this.quad)

this.renderer = new THREE.WebGLRenderer()
this.renderer.setPixelRatio(1)
this.renderer.setSize(width, height)
//renderer.setClearColor(new Color(1, 1, 1), 1);
this.renderer.autoClear = false
} else {
if(this.cameraRTT){
this.cameraRTT.left = -width / 2
this.cameraRTT.right = width / 2
this.cameraRTT.top = height / 2
this.cameraRTT.bottom = -height / 2

this.cameraRTT.updateProjectionMatrix()
}

this.quad?.scale.set(width, height, 1)

this.renderer.setSize(width, height)
}

this.rtTexture = new THREE.WebGLRenderTarget(width, height)
if('encoding' in this.rtTexture.texture){
// for THREE version < 0.151
this.rtTexture.texture.encoding = sRGBEncoding ? THREE.sRGBEncoding : THREE.NoColorSpace;
}else if ('colorSpace' in this.rtTexture.texture) {
// for THREE version > 0.151
this.rtTexture.texture.colorSpace = sRGBEncoding ? THREE.SRGBColorSpace : THREE.NoColorSpace;
}

if(this.material){
this.material.map = texture
this.material.color = multiplyColor.clone()

}
// set opacoty to 0 if texture is transparent
this.renderer.setClearColor(clearColor.clone(), isTransparent ? 0 : 1)

this.renderer.setRenderTarget(this.rtTexture)
this.renderer.clear()
if(this.sceneRTT && this.cameraRTT){
this.renderer.render(this.sceneRTT, this.cameraRTT)
}

let buffer = new Uint8ClampedArray(this.rtTexture.width * this.rtTexture.height * 4)
this.renderer.readRenderTargetPixels(this.rtTexture, 0, 0, width, height, buffer)
const imgData = new ImageData(buffer, width, height)

return imgData
}

destroy() {
this.cameraRTT = null
this.sceneRTT?.clear()
this.sceneRTT = null
this.material = null
this.quad = null
this.renderer?.dispose()
this.renderer = null
this.rtTexture = null
}

static createSolidColorTexture (color, width, height) {
const size = width * height
const data = new Uint8Array(4 * size)

const r = Math.floor(color.r * 255)
const g = Math.floor(color.g * 255)
const b = Math.floor(color.b * 255)

for (let i = 0; i < size; i++) {
const stride = i * 4
data[stride] = r
data[stride + 1] = g
data[stride + 2] = b
data[stride + 3] = 255
}

// used the buffer to create a DataTexture
const texture = new THREE.DataTexture(data, width, height)
texture.needsUpdate = true
return texture
}
}

0 comments on commit 28c6a15

Please sign in to comment.