Use ts
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
|
||||
// @:keep
|
||||
class BrushOutputNode extends LogicNode {
|
||||
|
||||
id = 0;
|
||||
texpaint: Image = null;
|
||||
texpaint_nor: Image = null;
|
||||
texpaint_pack: Image = null;
|
||||
texpaint_nor_empty: Image = null;
|
||||
texpaint_pack_empty: Image = null;
|
||||
|
||||
static inst: BrushOutputNode = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (inst == null) {
|
||||
{
|
||||
let t = new RenderTargetRaw();
|
||||
t.name = "texpaint";
|
||||
t.width = Config.getTextureResX();
|
||||
t.height = Config.getTextureResY();
|
||||
t.format = "RGBA32";
|
||||
texpaint = RenderPath.active.createRenderTarget(t).image;
|
||||
}
|
||||
{
|
||||
let t = new RenderTargetRaw();
|
||||
t.name = "texpaint_nor";
|
||||
t.width = Config.getTextureResX();
|
||||
t.height = Config.getTextureResY();
|
||||
t.format = "RGBA32";
|
||||
texpaint_nor = RenderPath.active.createRenderTarget(t).image;
|
||||
}
|
||||
{
|
||||
let t = new RenderTargetRaw();
|
||||
t.name = "texpaint_pack";
|
||||
t.width = Config.getTextureResX();
|
||||
t.height = Config.getTextureResY();
|
||||
t.format = "RGBA32";
|
||||
texpaint_pack = RenderPath.active.createRenderTarget(t).image;
|
||||
}
|
||||
{
|
||||
let t = new RenderTargetRaw();
|
||||
t.name = "texpaint_nor_empty";
|
||||
t.width = 1;
|
||||
t.height = 1;
|
||||
t.format = "RGBA32";
|
||||
texpaint_nor_empty = RenderPath.active.createRenderTarget(t).image;
|
||||
}
|
||||
{
|
||||
let t = new RenderTargetRaw();
|
||||
t.name = "texpaint_pack_empty";
|
||||
t.width = 1;
|
||||
t.height = 1;
|
||||
t.format = "RGBA32";
|
||||
texpaint_pack_empty = RenderPath.active.createRenderTarget(t).image;
|
||||
}
|
||||
}
|
||||
else {
|
||||
texpaint = inst.texpaint;
|
||||
texpaint_nor = inst.texpaint_nor;
|
||||
texpaint_pack = inst.texpaint_pack;
|
||||
}
|
||||
|
||||
inst = this;
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
inputs[from].getAsImage(done);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
// @:keep
|
||||
class ImageTextureNode extends LogicNode {
|
||||
|
||||
file: string;
|
||||
color_space: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
let index = Project.assetNames.indexOf(file);
|
||||
let asset = Project.assets[index];
|
||||
done(Project.getImage(asset));
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
let image: Image;
|
||||
getAsImage(0, (img: Image) => { image = img; });
|
||||
return image;
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Image Texture"),
|
||||
type: "ImageTextureNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Vector"),
|
||||
type: "VECTOR",
|
||||
color: 0xff6363c7,
|
||||
default_value: array_f32([0.0, 0.0, 0.0])
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Alpha"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 1.0
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: _tr("file"),
|
||||
type: "ENUM",
|
||||
default_value: 0,
|
||||
data: ""
|
||||
},
|
||||
{
|
||||
name: _tr("color_space"),
|
||||
type: "ENUM",
|
||||
default_value: 0,
|
||||
data: ["linear", "srgb"]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
|
||||
// @:keep
|
||||
class InpaintNode extends LogicNode {
|
||||
|
||||
static image: Image = null;
|
||||
static mask: Image = null;
|
||||
static result: Image = null;
|
||||
|
||||
static temp: Image = null;
|
||||
static prompt = "";
|
||||
static strength = 0.5;
|
||||
static auto = true;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
init();
|
||||
}
|
||||
|
||||
static init = () => {
|
||||
if (image == null) {
|
||||
image = Image.createRenderTarget(Config.getTextureResX(), Config.getTextureResY());
|
||||
}
|
||||
|
||||
if (mask == null) {
|
||||
mask = Image.createRenderTarget(Config.getTextureResX(), Config.getTextureResY(), TextureFormat.R8);
|
||||
Base.notifyOnNextFrame(() => {
|
||||
mask.g4.begin();
|
||||
mask.g4.clear(Color.fromFloats(1.0, 1.0, 1.0, 1.0));
|
||||
mask.g4.end();
|
||||
});
|
||||
}
|
||||
|
||||
if (temp == null) {
|
||||
temp = Image.createRenderTarget(512, 512);
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
result = Image.createRenderTarget(Config.getTextureResX(), Config.getTextureResY());
|
||||
}
|
||||
}
|
||||
|
||||
static buttons = (ui: zui.Zui, nodes: zui.Zui.Nodes, node: zui.Zui.TNode) => {
|
||||
auto = node.buttons[0].default_value == 0 ? false : true;
|
||||
if (!auto) {
|
||||
strength = ui.slider(zui.Zui.handle("inpaintnode_0", {value: strength}), tr("strength"), 0, 1, true);
|
||||
prompt = ui.textArea(zui.Zui.handle("inpaintnode_1"), true, tr("prompt"), true);
|
||||
node.buttons[1].height = 1 + prompt.split("\n").length;
|
||||
}
|
||||
else node.buttons[1].height = 0;
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
inputs[0].getAsImage((source: Image) => {
|
||||
|
||||
Console.progress(tr("Processing") + " - " + tr("Inpaint"));
|
||||
Base.notifyOnNextFrame(() => {
|
||||
image.g2.begin(false);
|
||||
image.g2.drawScaledImage(source, 0, 0, Config.getTextureResX(), Config.getTextureResY());
|
||||
image.g2.end();
|
||||
|
||||
auto ? texsynthInpaint(image, false, mask, done) : sdInpaint(image, mask, done);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
Base.notifyOnNextFrame(() => {
|
||||
inputs[0].getAsImage((source: Image) => {
|
||||
if (Base.pipeCopy == null) Base.makePipe();
|
||||
if (ConstData.screenAlignedVB == null) ConstData.createScreenAlignedData();
|
||||
image.g4.begin();
|
||||
image.g4.setPipeline(Base.pipeInpaintPreview);
|
||||
image.g4.setTexture(Base.tex0InpaintPreview, source);
|
||||
image.g4.setTexture(Base.texaInpaintPreview, mask);
|
||||
image.g4.setVertexBuffer(ConstData.screenAlignedVB);
|
||||
image.g4.setIndexBuffer(ConstData.screenAlignedIB);
|
||||
image.g4.drawIndexedVertices();
|
||||
image.g4.end();
|
||||
});
|
||||
});
|
||||
return image;
|
||||
}
|
||||
|
||||
getTarget = (): Image => {
|
||||
return mask;
|
||||
}
|
||||
|
||||
static texsynthInpaint = (image: Image, tiling: bool, mask: Image/* = null*/, done: (img: Image)=>void) => {
|
||||
let w = arm.Config.getTextureResX();
|
||||
let h = arm.Config.getTextureResY();
|
||||
|
||||
let bytes_img = image.getPixels();
|
||||
let bytes_mask = mask != null ? mask.getPixels() : new ArrayBuffer(w * h);
|
||||
let bytes_out = new ArrayBuffer(w * h * 4);
|
||||
Krom_texsynth.inpaint(w, h, bytes_out, bytes_img, bytes_mask, tiling);
|
||||
|
||||
result = Image.fromBytes(bytes_out, w, h);
|
||||
done(result);
|
||||
}
|
||||
|
||||
static sdInpaint = (image: Image, mask: Image, done: (img: Image)=>void) => {
|
||||
init();
|
||||
|
||||
let bytes_img = mask.getPixels().b.buffer;
|
||||
let u8 = new Uint8Array(bytes_img);
|
||||
let f32mask = new Float32Array(4 * 64 * 64);
|
||||
|
||||
Data.getBlob("models/sd_vae_encoder.quant.onnx", (vae_encoder_blob: ArrayBuffer) => {
|
||||
// for (let x = 0; x < Math.floor(image.width / 512); ++x) {
|
||||
// for (let y = 0; y < Math.floor(image.height / 512); ++y) {
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
for (let xx = 0; xx < 64; ++xx) {
|
||||
for (let yy = 0; yy < 64; ++yy;) {
|
||||
// let step = Math.floor(512 / 64);
|
||||
// let j = (yy * step * mask.width + xx * step) + (y * 512 * mask.width + x * 512);
|
||||
let step = Math.floor(mask.width / 64);
|
||||
let j = (yy * step * mask.width + xx * step);
|
||||
let f = u8[j] / 255.0;
|
||||
let i = yy * 64 + xx;
|
||||
f32mask[i ] = f;
|
||||
f32mask[i + 64 * 64 ] = f;
|
||||
f32mask[i + 64 * 64 * 2] = f;
|
||||
f32mask[i + 64 * 64 * 3] = f;
|
||||
}
|
||||
}
|
||||
|
||||
temp.g2.begin(false);
|
||||
// temp.g2.drawImage(image, -x * 512, -y * 512);
|
||||
temp.g2.drawScaledImage(image, 0, 0, 512, 512);
|
||||
temp.g2.end();
|
||||
|
||||
let bytes_img = temp.getPixels().b.buffer;
|
||||
let u8a = new Uint8Array(bytes_img);
|
||||
let f32a = new Float32Array(3 * 512 * 512);
|
||||
for (let i = 0; i < (512 * 512); ++i) {
|
||||
f32a[i ] = (u8a[i * 4 ] / 255.0) * 2.0 - 1.0;
|
||||
f32a[i + 512 * 512 ] = (u8a[i * 4 + 1] / 255.0) * 2.0 - 1.0;
|
||||
f32a[i + 512 * 512 * 2] = (u8a[i * 4 + 2] / 255.0) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
let latents_buf = Krom.mlInference(vae_encoder_blob, [f32a.buffer], [[1, 3, 512, 512]], [1, 4, 64, 64], Config.raw.gpu_inference);
|
||||
let latents = new Float32Array(latents_buf);
|
||||
for (let i = 0; i < latents.length; ++i) {
|
||||
latents[i] = 0.18215 * latents[i];
|
||||
}
|
||||
let latents_orig = latents.slice(0);
|
||||
|
||||
let noise = new Float32Array(latents.length);
|
||||
for (let i = 0; i < noise.length; ++i) noise[i] = Math.cos(2.0 * 3.14 * RandomNode.getFloat()) * Math.sqrt(-2.0 * Math.log(RandomNode.getFloat()));
|
||||
|
||||
let num_inference_steps = 50;
|
||||
let init_timestep = Math.floor(num_inference_steps * strength);
|
||||
let timestep = TextToPhotoNode.timesteps[num_inference_steps - init_timestep];
|
||||
let alphas_cumprod = TextToPhotoNode.alphas_cumprod;
|
||||
let sqrt_alpha_prod = Math.pow(alphas_cumprod[timestep], 0.5);
|
||||
let sqrt_one_minus_alpha_prod = Math.pow(1.0 - alphas_cumprod[timestep], 0.5);
|
||||
for (let i = 0; i < latents.length; ++i) {
|
||||
latents[i] = sqrt_alpha_prod * latents[i] + sqrt_one_minus_alpha_prod * noise[i];
|
||||
}
|
||||
|
||||
let start = num_inference_steps - init_timestep;
|
||||
|
||||
TextToPhotoNode.stableDiffusion(prompt, (img: Image) => {
|
||||
// result.g2.begin(false);
|
||||
// result.g2.drawImage(img, x * 512, y * 512);
|
||||
// result.g2.end();
|
||||
result = img;
|
||||
done(img);
|
||||
}, latents, start, true, f32mask, latents_orig);
|
||||
// }
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Inpaint"),
|
||||
type: "InpaintNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([1.0, 1.0, 1.0, 1.0])
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: _tr("auto"),
|
||||
type: "BOOL",
|
||||
default_value: true,
|
||||
output: 0
|
||||
},
|
||||
{
|
||||
name: "arm.nodes.InpaintNode.buttons",
|
||||
type: "CUSTOM",
|
||||
height: 0
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
|
||||
// @:keep
|
||||
class PhotoToPBRNode extends LogicNode {
|
||||
|
||||
static temp: Image = null;
|
||||
static images: Image[] = null;
|
||||
static modelNames = ["base", "occlusion", "roughness", "metallic", "normal", "height"];
|
||||
|
||||
static cachedSource: Image = null;
|
||||
static borderW = 64;
|
||||
static tileW = 2048;
|
||||
static tileWithBorderW = tileW + borderW * 2;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (temp == null) {
|
||||
temp = Image.createRenderTarget(tileWithBorderW, tileWithBorderW);
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
static init = () => {
|
||||
if (images == null) {
|
||||
images = [];
|
||||
for (let i = 0; i < modelNames.length; ++i) {
|
||||
images.push(Image.createRenderTarget(Config.getTextureResX(), Config.getTextureResY()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
let getSource = (done: (img: Image)=>void) => {
|
||||
if (cachedSource != null) done(cachedSource);
|
||||
else inputs[0].getAsImage(done);
|
||||
}
|
||||
|
||||
getSource((source: Image) => {
|
||||
cachedSource = source;
|
||||
|
||||
Console.progress(tr("Processing") + " - " + tr("Photo to PBR"));
|
||||
Base.notifyOnNextFrame(() => {
|
||||
let tileFloats: Float32Array[] = [];
|
||||
let tilesX = Math.floor(Config.getTextureResX() / tileW);
|
||||
let tilesY = Math.floor(Config.getTextureResY() / tileW);
|
||||
let numTiles = tilesX * tilesY;
|
||||
for (let i = 0; i < numTiles; ++i) {
|
||||
let x = i % tilesX;
|
||||
let y = Math.floor(i / tilesX);
|
||||
|
||||
temp.g2.begin(false);
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW, borderW - y * tileW, -Config.getTextureResX(), Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW, borderW - y * tileW, Config.getTextureResX(), -Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW, borderW - y * tileW, -Config.getTextureResX(), -Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW + tileW, borderW - y * tileW + tileW, Config.getTextureResX(), Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW + tileW, borderW - y * tileW + tileW, -Config.getTextureResX(), Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW + tileW, borderW - y * tileW + tileW, Config.getTextureResX(), -Config.getTextureResY());
|
||||
temp.g2.drawScaledImage(source, borderW - x * tileW, borderW - y * tileW, Config.getTextureResX(), Config.getTextureResY());
|
||||
temp.g2.end();
|
||||
|
||||
let bytes_img = temp.getPixels();
|
||||
let u8a = new Uint8Array(bytes_img);
|
||||
let f32a = new Float32Array(3 * tileWithBorderW * tileWithBorderW);
|
||||
for (let i = 0; i < (tileWithBorderW * tileWithBorderW)) {
|
||||
f32a[i ] = (u8a[i * 4 ] / 255 - 0.5) / 0.5;
|
||||
f32a[i + tileWithBorderW * tileWithBorderW ] = (u8a[i * 4 + 1] / 255 - 0.5) / 0.5;
|
||||
f32a[i + tileWithBorderW * tileWithBorderW * 2] = (u8a[i * 4 + 2] / 255 - 0.5) / 0.5;
|
||||
}
|
||||
|
||||
Data.getBlob("models/photo_to_" + modelNames[from] + ".quant.onnx", (model_blob: ArrayBuffer) => {
|
||||
let buf = Krom.mlInference(model_blob, [f32a.buffer], null, null, Config.raw.gpu_inference);
|
||||
let ar = new Float32Array(buf);
|
||||
let u8a = new Uint8Array(4 * tileW * tileW);
|
||||
let offsetG = (from == ChannelBaseColor || from == ChannelNormalMap) ? tileWithBorderW * tileWithBorderW : 0;
|
||||
let offsetB = (from == ChannelBaseColor || from == ChannelNormalMap) ? tileWithBorderW * tileWithBorderW * 2 : 0;
|
||||
for (let i = 0; i < (tileW * tileW); ++i) {
|
||||
let x = borderW + i % tileW;
|
||||
let y = borderW + Math.floor(i / tileW);
|
||||
u8a[i * 4 ] = Math.floor((ar[y * tileWithBorderW + x ] * 0.5 + 0.5) * 255);
|
||||
u8a[i * 4 + 1] = Math.floor((ar[y * tileWithBorderW + x + offsetG] * 0.5 + 0.5) * 255);
|
||||
u8a[i * 4 + 2] = Math.floor((ar[y * tileWithBorderW + x + offsetB] * 0.5 + 0.5) * 255);
|
||||
u8a[i * 4 + 3] = 255;
|
||||
}
|
||||
tileFloats.push(ar);
|
||||
|
||||
// Use border pixels to blend seams
|
||||
if (i > 0) {
|
||||
if (x > 0) {
|
||||
let ar = tileFloats[i - 1];
|
||||
for (let yy = 0; yy < tileW; ++yy) {
|
||||
for (let xx = 0; xx < borderW; ++xx) {
|
||||
let i = yy * tileW + xx;
|
||||
let a = u8a[i * 4];
|
||||
let b = u8a[i * 4 + 1];
|
||||
let c = u8a[i * 4 + 2];
|
||||
|
||||
let aa = Math.floor((ar[(borderW + yy) * tileWithBorderW + borderW + tileW + xx ] * 0.5 + 0.5) * 255);
|
||||
let bb = Math.floor((ar[(borderW + yy) * tileWithBorderW + borderW + tileW + xx + offsetG] * 0.5 + 0.5) * 255);
|
||||
let cc = Math.floor((ar[(borderW + yy) * tileWithBorderW + borderW + tileW + xx + offsetB] * 0.5 + 0.5) * 255);
|
||||
|
||||
let f = xx / borderW;
|
||||
let invf = 1.0 - f;
|
||||
a = Math.floor(a * f + aa * invf);
|
||||
b = Math.floor(b * f + bb * invf);
|
||||
c = Math.floor(c * f + cc * invf);
|
||||
|
||||
u8a[i * 4 ] = a;
|
||||
u8a[i * 4 + 1] = b;
|
||||
u8a[i * 4 + 2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (y > 0) {
|
||||
let ar = tileFloats[i - tilesX];
|
||||
for (let xx = 0; xx < tileW; ++xx) {
|
||||
for (let yy = 0; yy < borderW; ++yy) {
|
||||
let i = yy * tileW + xx;
|
||||
let a = u8a[i * 4];
|
||||
let b = u8a[i * 4 + 1];
|
||||
let c = u8a[i * 4 + 2];
|
||||
|
||||
let aa = Math.floor((ar[(borderW + tileW + yy) * tileWithBorderW + borderW + xx ] * 0.5 + 0.5) * 255);
|
||||
let bb = Math.floor((ar[(borderW + tileW + yy) * tileWithBorderW + borderW + xx + offsetG] * 0.5 + 0.5) * 255);
|
||||
let cc = Math.floor((ar[(borderW + tileW + yy) * tileWithBorderW + borderW + xx + offsetB] * 0.5 + 0.5) * 255);
|
||||
|
||||
let f = yy / borderW;
|
||||
let invf = 1.0 - f;
|
||||
a = Math.floor(a * f + aa * invf);
|
||||
b = Math.floor(b * f + bb * invf);
|
||||
c = Math.floor(c * f + cc * invf);
|
||||
|
||||
u8a[i * 4 ] = a;
|
||||
u8a[i * 4 + 1] = b;
|
||||
u8a[i * 4 + 2] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///if (krom_metal || krom_vulkan)
|
||||
if (from == ChannelBaseColor) bgraSwap(u8a.buffer);
|
||||
///end
|
||||
|
||||
let temp2 = Image.fromBytes(u8a.buffer, tileW, tileW);
|
||||
images[from].g2.begin(false);
|
||||
images[from].g2.drawImage(temp2, x * tileW, y * tileW);
|
||||
images[from].g2.end();
|
||||
Base.notifyOnNextFrame(() => {
|
||||
temp2.unload();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
done(images[from]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
///if (krom_metal || krom_vulkan)
|
||||
static bgraSwap = (buffer: ArrayBuffer) => {
|
||||
let u8a = new Uint8Array(buffer);
|
||||
for (let i = 0; i < Math.floor(buffer.byteLength / 4); ++i) {
|
||||
let r = u8a[i * 4];
|
||||
u8a[i * 4] = u8a[i * 4 + 2];
|
||||
u8a[i * 4 + 2] = r;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
///end
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Photo to PBR"),
|
||||
type: "PhotoToPBRNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Base Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Occlusion"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 1.0
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Roughness"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 1.0
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Metallic"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 0.0
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Normal Map"),
|
||||
type: "VECTOR",
|
||||
color: 0xffc7c729,
|
||||
default_value: f32([0.0, 0.0, 0.0, 1.0])
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Height"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 1.0
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
// @:keep
|
||||
class RGBNode extends LogicNode {
|
||||
|
||||
image: Image = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
if (image != null) {
|
||||
Base.notifyOnNextFrame(() => {
|
||||
image.unload();
|
||||
});
|
||||
}
|
||||
|
||||
let f32a = new Float32Array(4);
|
||||
let raw = ParserLogic.getRawNode(this);
|
||||
let default_value = raw.outputs[0].default_value;
|
||||
f32a[0] = default_value[0];
|
||||
f32a[1] = default_value[1];
|
||||
f32a[2] = default_value[2];
|
||||
f32a[3] = default_value[3];
|
||||
image = Image.fromBytes(f32a.buffer, 1, 1, TextureFormat.RGBA128);
|
||||
done(image);
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
getAsImage(0, (img: Image) => {});
|
||||
return image;
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("RGB"),
|
||||
type: "RGBNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xffb34f5a,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.8, 0.8, 0.8, 1.0])
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: _tr("default_value"),
|
||||
type: "RGBA",
|
||||
output: 0,
|
||||
default_value: array_f32([0.8, 0.8, 0.8, 1.0])
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,130 @@
|
||||
|
||||
// @:keep
|
||||
class TilingNode extends LogicNode {
|
||||
|
||||
result: Image = null;
|
||||
static image: Image = null;
|
||||
static prompt = "";
|
||||
static strength = 0.5;
|
||||
static auto = true;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
init();
|
||||
}
|
||||
|
||||
static init = () => {
|
||||
if (image == null) {
|
||||
image = Image.createRenderTarget(Config.getTextureResX(), Config.getTextureResY());
|
||||
}
|
||||
}
|
||||
|
||||
static buttons = (ui: zui.Zui, nodes: zui.Zui.Nodes, node: zui.Zui.TNode) => {
|
||||
auto = node.buttons[0].default_value == 0 ? false : true;
|
||||
if (!auto) {
|
||||
strength = ui.slider(zui.Zui.handle("tilingnode_0", {value: strength}), tr("strength"), 0, 1, true);
|
||||
prompt = ui.textArea(zui.Zui.handle("tilingnode_1"), true, tr("prompt"), true);
|
||||
node.buttons[1].height = 1 + prompt.split("\n").length;
|
||||
}
|
||||
else node.buttons[1].height = 0;
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
inputs[0].getAsImage((source: Image) => {
|
||||
image.g2.begin(false);
|
||||
image.g2.drawScaledImage(source, 0, 0, Config.getTextureResX(), Config.getTextureResY());
|
||||
image.g2.end();
|
||||
|
||||
Console.progress(tr("Processing") + " - " + tr("Tiling"));
|
||||
Base.notifyOnNextFrame(() => {
|
||||
let _done = (image: Image) => {
|
||||
result = image;
|
||||
done(image);
|
||||
}
|
||||
auto ? InpaintNode.texsynthInpaint(image, true, null, _done) : sdTiling(image, -1, _done);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
return result;
|
||||
}
|
||||
|
||||
static sdTiling = (image: Image, seed: i32/* = -1*/, done: (img: Image)=>void) => {
|
||||
TextToPhotoNode.tiling = false;
|
||||
let tile = Image.createRenderTarget(512, 512);
|
||||
tile.g2.begin(false);
|
||||
tile.g2.drawScaledImage(image, -256, -256, 512, 512);
|
||||
tile.g2.drawScaledImage(image, 256, -256, 512, 512);
|
||||
tile.g2.drawScaledImage(image, -256, 256, 512, 512);
|
||||
tile.g2.drawScaledImage(image, 256, 256, 512, 512);
|
||||
tile.g2.end();
|
||||
|
||||
let u8a = new Uint8Array(512 * 512);
|
||||
for (let i = 0; i < 512 * 512; ++i) {
|
||||
let x = i % 512;
|
||||
let y = Math.floor(i / 512);
|
||||
let l = y < 256 ? y : (511 - y);
|
||||
u8a[i] = (x > 256 - l && x < 256 + l) ? 0 : 255;
|
||||
}
|
||||
// for (let i = 0; i < 512 * 512; ++i) u8a[i] = 255;
|
||||
// for (let x = (256 - 32); x < (256 + 32); ++x) {
|
||||
// for (let y = 0; y < 512; ++y) {
|
||||
// u8a[y * 512 + x] = 0;
|
||||
// }
|
||||
// }
|
||||
// for (let x = 0; x < 512; ++x) {
|
||||
// for (let y = (256 - 32); y < 256 + 32); ++y) {
|
||||
// u8a[y * 512 + x] = 0;
|
||||
// }
|
||||
// }
|
||||
let mask = Image.fromBytes(u8a.buffer, 512, 512, TextureFormat.R8);
|
||||
|
||||
InpaintNode.prompt = prompt;
|
||||
InpaintNode.strength = strength;
|
||||
if (seed >= 0) RandomNode.setSeed(seed);
|
||||
InpaintNode.sdInpaint(tile, mask, done);
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Tiling"),
|
||||
type: "TilingNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: _tr("auto"),
|
||||
type: "BOOL",
|
||||
default_value: true,
|
||||
output: 0
|
||||
},
|
||||
{
|
||||
name: "arm.nodes.TilingNode.buttons",
|
||||
type: "CUSTOM",
|
||||
height: 0
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
|
||||
// @:keep
|
||||
class UpscaleNode extends LogicNode {
|
||||
|
||||
static temp: Image = null;
|
||||
static image: Image = null;
|
||||
static esrgan_blob: ArrayBuffer;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
inputs[0].getAsImage((_image: Image) => {
|
||||
image = _image;
|
||||
|
||||
Console.progress(tr("Processing") + " - " + tr("Upscale"));
|
||||
Base.notifyOnNextFrame(() => {
|
||||
loadBlob(() => {
|
||||
if (image.width < Config.getTextureResX()) {
|
||||
image = esrgan(image);
|
||||
while (image.width < Config.getTextureResX()) {
|
||||
let lastImage = image;
|
||||
image = esrgan(image);
|
||||
lastImage.unload();
|
||||
}
|
||||
}
|
||||
done(image);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static loadBlob = (done: ()=>void) => {
|
||||
Data.getBlob("models/esrgan.quant.onnx", (_esrgan_blob: ArrayBuffer) => {
|
||||
esrgan_blob = _esrgan_blob;
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
return image;
|
||||
}
|
||||
|
||||
static doTile = (source: Image) => {
|
||||
let result: Image = null;
|
||||
let size1w = source.width;
|
||||
let size1h = source.height;
|
||||
let size2w = Math.floor(size1w * 2);
|
||||
let size2h = Math.floor(size1h * 2);
|
||||
if (temp != null) {
|
||||
temp.unload();
|
||||
}
|
||||
temp = Image.createRenderTarget(size1w, size1h);
|
||||
temp.g2.begin(false);
|
||||
temp.g2.drawScaledImage(source, 0, 0, size1w, size1h);
|
||||
temp.g2.end();
|
||||
|
||||
let bytes_img = temp.getPixels();
|
||||
let u8a = new Uint8Array(bytes_img);
|
||||
let f32a = new Float32Array(3 * size1w * size1h);
|
||||
for (let i = 0; i < (size1w * size1h); ++i) {
|
||||
f32a[i ] = (u8a[i * 4 ] / 255);
|
||||
f32a[i + size1w * size1w ] = (u8a[i * 4 + 1] / 255);
|
||||
f32a[i + size1w * size1w * 2] = (u8a[i * 4 + 2] / 255);
|
||||
}
|
||||
|
||||
let esrgan2x_buf = Krom.mlInference(esrgan_blob, [f32a.buffer], [[1, 3, size1w, size1h]], [1, 3, size2w, size2h], Config.raw.gpu_inference);
|
||||
let esrgan2x = new Float32Array(esrgan2x_buf);
|
||||
for (let i = 0; i < esrgan2x.length; ++i) {
|
||||
if (esrgan2x[i] < 0) esrgan2x[i] = 0;
|
||||
else if (esrgan2x[i] > 1) esrgan2x[i] = 1;
|
||||
}
|
||||
|
||||
let u8a = new Uint8Array(4 * size2w * size2h);
|
||||
for (let i = 0; i < (size2w * size2h); ++i) {
|
||||
u8a[i * 4 ] = Math.floor(esrgan2x[i ] * 255);
|
||||
u8a[i * 4 + 1] = Math.floor(esrgan2x[i + size2w * size2w ] * 255);
|
||||
u8a[i * 4 + 2] = Math.floor(esrgan2x[i + size2w * size2w * 2] * 255);
|
||||
u8a[i * 4 + 3] = 255;
|
||||
}
|
||||
|
||||
result = Image.fromBytes(u8a.buffer, size2w, size2h);
|
||||
return result;
|
||||
}
|
||||
|
||||
static esrgan = (source: Image): Image => {
|
||||
let result: Image = null;
|
||||
let size1w = source.width;
|
||||
let size1h = source.height;
|
||||
let tileSize = 512;
|
||||
let tileSize2x = Math.floor(tileSize * 2);
|
||||
|
||||
if (size1w >= tileSize2x || size1h >= tileSize2x) { // Split into tiles
|
||||
let size2w = Math.floor(size1w * 2);
|
||||
let size2h = Math.floor(size1h * 2);
|
||||
result = Image.createRenderTarget(size2w, size2h);
|
||||
let tileSource = Image.createRenderTarget(tileSize + 32 * 2, tileSize + 32 * 2);
|
||||
for (let x = 0; x < Math.floor(size1w / tileSize); ++x) {
|
||||
for (let y = 0; y < Math.floor(size1h / tileSize); ++y) {
|
||||
tileSource.g2.begin(false);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize, 32 - y * tileSize, -source.width, source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize, 32 - y * tileSize, source.width, -source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize, 32 - y * tileSize, -source.width, -source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize + tileSize, 32 - y * tileSize + tileSize, source.width, source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize + tileSize, 32 - y * tileSize + tileSize, -source.width, source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize + tileSize, 32 - y * tileSize + tileSize, source.width, -source.height);
|
||||
tileSource.g2.drawScaledImage(source, 32 - x * tileSize, 32 - y * tileSize, source.width, source.height);
|
||||
tileSource.g2.end();
|
||||
let tileResult = doTile(tileSource);
|
||||
result.g2.begin(false);
|
||||
result.g2.drawSubImage(tileResult, x * tileSize2x, y * tileSize2x, 64, 64, tileSize2x, tileSize2x);
|
||||
result.g2.end();
|
||||
tileResult.unload();
|
||||
}
|
||||
}
|
||||
tileSource.unload();
|
||||
}
|
||||
else result = doTile(source); // Single tile
|
||||
return result;
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Upscale"),
|
||||
type: "UpscaleNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
|
||||
// @:keep
|
||||
class VarianceNode extends LogicNode {
|
||||
|
||||
static temp: Image = null;
|
||||
static image: Image = null;
|
||||
static inst: VarianceNode = null;
|
||||
static prompt = "";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
inst = this;
|
||||
init();
|
||||
}
|
||||
|
||||
static init = () => {
|
||||
if (temp == null) {
|
||||
temp = Image.createRenderTarget(512, 512);
|
||||
}
|
||||
}
|
||||
|
||||
static buttons = (ui: zui.Zui, nodes: zui.Zui.Nodes, node: zui.Zui.TNode) => {
|
||||
prompt = ui.textArea(zui.Zui.handle("variancenode_0"), true, tr("prompt"), true);
|
||||
node.buttons[0].height = prompt.split("\n").length;
|
||||
}
|
||||
|
||||
override getAsImage = (from: i32, done: (img: Image)=>void) => {
|
||||
let strength = inst.inputs[1].node.value;
|
||||
|
||||
inst.inputs[0].getAsImage((source: Image) => {
|
||||
temp.g2.begin(false);
|
||||
temp.g2.drawScaledImage(source, 0, 0, 512, 512);
|
||||
temp.g2.end();
|
||||
|
||||
let bytes_img = temp.getPixels().b.buffer;
|
||||
let u8a = new Uint8Array(bytes_img);
|
||||
let f32a = new Float32Array(3 * 512 * 512);
|
||||
for (let i = 0; i < (512 * 512); ++i) {
|
||||
f32a[i ] = (u8a[i * 4 ] / 255) * 2.0 - 1.0;
|
||||
f32a[i + 512 * 512 ] = (u8a[i * 4 + 1] / 255) * 2.0 - 1.0;
|
||||
f32a[i + 512 * 512 * 2] = (u8a[i * 4 + 2] / 255) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
Console.progress(tr("Processing") + " - " + tr("Variance"));
|
||||
Base.notifyOnNextFrame(() => {
|
||||
Data.getBlob("models/sd_vae_encoder.quant.onnx", (vae_encoder_blob: ArrayBuffer) => {
|
||||
let latents_buf = Krom.mlInference(vae_encoder_blob, [f32a.buffer], [[1, 3, 512, 512]], [1, 4, 64, 64], Config.raw.gpu_inference);
|
||||
let latents = new Float32Array(latents_buf);
|
||||
for (let i = 0; i < latents.length; ++i) {
|
||||
latents[i] = 0.18215 * latents[i];
|
||||
}
|
||||
|
||||
let noise = new Float32Array(latents.length);
|
||||
for (let i = 0; i < noise.length; ++i) noise[i] = Math.cos(2.0 * 3.14 * RandomNode.getFloat()) * Math.sqrt(-2.0 * Math.log(RandomNode.getFloat()));
|
||||
let num_inference_steps = 50;
|
||||
let init_timestep = Math.floor(num_inference_steps * strength);
|
||||
let timesteps = TextToPhotoNode.timesteps[num_inference_steps - init_timestep];
|
||||
let alphas_cumprod = TextToPhotoNode.alphas_cumprod;
|
||||
let sqrt_alpha_prod = Math.pow(alphas_cumprod[timesteps], 0.5);
|
||||
let sqrt_one_minus_alpha_prod = Math.pow(1.0 - alphas_cumprod[timesteps], 0.5);
|
||||
for (let i = 0; i < latents.length; ++i) {
|
||||
latents[i] = sqrt_alpha_prod * latents[i] + sqrt_one_minus_alpha_prod * noise[i];
|
||||
}
|
||||
let t_start = num_inference_steps - init_timestep;
|
||||
|
||||
TextToPhotoNode.stableDiffusion(prompt, (_image: Image) => {
|
||||
image = _image;
|
||||
done(image);
|
||||
}, latents, t_start);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override getCachedImage = (): Image => {
|
||||
return image;
|
||||
}
|
||||
|
||||
static def: zui.Zui.TNode = {
|
||||
id: 0,
|
||||
name: _tr("Variance"),
|
||||
type: "VarianceNode",
|
||||
x: 0,
|
||||
y: 0,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Strength"),
|
||||
type: "VALUE",
|
||||
color: 0xffa1a1a1,
|
||||
default_value: 0.5
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: 0,
|
||||
node_id: 0,
|
||||
name: _tr("Color"),
|
||||
type: "RGBA",
|
||||
color: 0xffc7c729,
|
||||
default_value: array_f32([0.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: "arm.nodes.VarianceNode.buttons",
|
||||
type: "CUSTOM",
|
||||
height: 1
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user