node-3d / 3d-core-raub

An extensible Node.js 3D core for desktop applications
https://github.com/node-3d/node-3d
MIT License
72 stars 4 forks source link

How to readPixels out? #22

Closed FlySkyPie closed 2 months ago

FlySkyPie commented 2 months ago

Hi, I want to dump render result and streaming to somewhere, what's the right way to do it with this library?

I had try:

import fs from 'fs-extra';  // ^11.2.0
import * as THREE from 'three'; // ^0.167.1
import { init, addThreeHelpers } from '3d-core-raub'; // ^4.3.0

const { doc, gl, requestAnimationFrame, } = init({
    isGles3: true,
    width: 400,
    height: 300,
    title: "OwO",
});
addThreeHelpers(THREE, gl);

const renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, });
renderer.setPixelRatio(doc.devicePixelRatio);
renderer.setSize(doc.innerWidth, doc.innerHeight);

const camera = new THREE.PerspectiveCamera(70, doc.innerWidth / doc.innerHeight, 1, 1000);
camera.position.z = 2;
camera.aspect = doc.innerWidth / doc.innerHeight;
camera.updateProjectionMatrix();

const scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xFACE8D });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

let i = 0;

const animate = () => {
    requestAnimationFrame(animate);
    const time = Date.now();
    mesh.rotation.x = time * 0.0005;
    mesh.rotation.y = time * 0.001;

    renderer.render(scene, camera);

    const ctx = renderer.getContext();
    const image: any = new Uint8Array(ctx.drawingBufferWidth * ctx.drawingBufferHeight * 3);

    ctx.readPixels(
        0,
        0,
        ctx.drawingBufferWidth,
        ctx.drawingBufferHeight,
        ctx.RGB,
        ctx.UNSIGNED_BYTE,
        image);

    fs.ensureDirSync("./data");
    fs.writeFileSync(`./data/${String(i).padStart(5, "0")}.bitmap`, image, {});
    i++;
};

animate();

and

import fs from 'fs-extra';  // ^11.2.0
import * as THREE from 'three'; // ^0.167.1
import { init, addThreeHelpers } from '3d-core-raub'; // ^4.3.0

const { doc, gl, requestAnimationFrame, } = init({
    isGles3: true,
    width: 400,
    height: 300,
    title: "OwO",
});
addThreeHelpers(THREE, gl);

const renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, });
renderer.setPixelRatio(doc.devicePixelRatio);
renderer.setSize(doc.innerWidth, doc.innerHeight);

const camera = new THREE.PerspectiveCamera(70, doc.innerWidth / doc.innerHeight, 1, 1000);
camera.position.z = 2;
camera.aspect = doc.innerWidth / doc.innerHeight;
camera.updateProjectionMatrix();

const scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xFACE8D });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

let i = 0;

const animate = () => {
    requestAnimationFrame(animate);
    const time = Date.now();
    mesh.rotation.x = time * 0.0005;
    mesh.rotation.y = time * 0.001;

    renderer.render(scene, camera);

    const image: any = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 3);

    gl.readPixels(
        0,
        0,
        gl.drawingBufferWidth,
        gl.drawingBufferHeight,
        gl.RGB,
        gl.UNSIGNED_BYTE,
        image);

    fs.ensureDirSync("./data");
    fs.writeFileSync(`./data/${String(i).padStart(5, "0")}.bitmap`, image, {});
    i++;
};

animate();

but I only got blob fill with "0".

raub commented 2 months ago

Hi! Can you please try this:

const memSize = screen.w * screen.h * 4; // estimated number of bytes
const storage = { data: Buffer.allocUnsafeSlow(memSize) };

gl.readPixels(
    0, 0,
    screen.w, screen.h,
    gl.RGBA,
    gl.UNSIGNED_BYTE,
    storage
);

const img = Image.fromPixels(screen.w, screen.h, 32, storage.data);

img.save(`${Date.now()}.jpg`);

This is an example from https://github.com/node-3d/image-raub

A similar approach is implemented here: https://github.com/node-3d/3d-core-raub/blob/master/js/objects/screen.js#L159

FlySkyPie commented 2 months ago

Ok, change to gl.RGBA works to me, thanks. here is full example:

import fs from 'fs-extra';  // ^11.2.0
import * as THREE from 'three'; // ^0.167.1
import { init, addThreeHelpers } from '3d-core-raub'; // ^4.3.0

const { doc, gl, requestAnimationFrame, } = init({
    isGles3: true,
    width: 400,
    height: 300,
    title: "OwO",
});
addThreeHelpers(THREE, gl);

const renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, });
renderer.setPixelRatio(doc.devicePixelRatio);
renderer.setSize(doc.innerWidth, doc.innerHeight);

const camera = new THREE.PerspectiveCamera(70, doc.innerWidth / doc.innerHeight, 1, 1000);
camera.position.z = 2;
camera.aspect = doc.innerWidth / doc.innerHeight;
camera.updateProjectionMatrix();

const scene = new THREE.Scene();

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0xFACE8D });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

let i = 0;

const animate = () => {
    requestAnimationFrame(animate);
    const time = Date.now();
    mesh.rotation.x = time * 0.0005;
    mesh.rotation.y = time * 0.001;

    renderer.render(scene, camera);

    const image: any = new Uint8Array(doc.w * doc.h * 4);

    gl.readPixels(
        0, 0,
        doc.w, doc.h,
        gl.RGBA,
        gl.UNSIGNED_BYTE,
        image);

    fs.ensureDirSync("./data");
    fs.writeFileSync(`./data/${String(i).padStart(5, "0")}.rgba`, image, {});
    i++;
};

animate();