threejs glft model strange lines - javascript

I am trying to create something like on this photo
So, how to remove that strange lines from the model
http://weblife.su/WineBazar/1/
You can see those lines while rorating the model.
What is the problem? I need to use opacity, to get result like on that scrinshot.
At least, can I hide the background for user, but reflectivity and metalness will be on my model?
My threeJs script is here
Thank you for the help!
<script type="module">
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://threejs.org/examples/jsm/loaders/GLTFLoader.js';
import { RGBELoader } from 'https://threejs.org/examples/jsm/loaders/RGBELoader.js';
import { RoughnessMipmapper } from 'https://threejs.org/examples/jsm/utils/RoughnessMipmapper.js';
var container, controls;
var camera, scene, renderer;
init();
render();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20);
camera.position.set(-1.8, 0.6, 2.7);
scene = new THREE.Scene();
new RGBELoader()
.setDataType(THREE.UnsignedByteType)
.setPath('https://threejs.org/examples/textures/equirectangular/')
.load('royal_esplanade_1k.hdr', function(texture) {
var envMap = pmremGenerator.fromEquirectangular(texture).texture;
scene.background = envMap;
scene.environment = envMap;
texture.dispose();
pmremGenerator.dispose();
render();
// model
// use of RoughnessMipmapper is optional
var roughnessMipmapper = new RoughnessMipmapper(renderer);
var loader = new GLTFLoader()
loader.load('http://weblife.su/WineBazar/1/ws_r_2-5.glb', function(gltf) {
gltf.scene.traverse(function(child) {
if (child.isMesh) {
child.material.color.setHex(0x9ed7f5);
child.material.emissive.setHex(0x062f61);
child.material.transparent = true;
child.material.opacity = 0.5;
child.material.needsUpdate = true;
child.material.reflectivity = 0.8;
child.material.roughness = 0.2;
child.material.metalness = 0.5;
child.depthWrite = true;
}
});
scene.add(gltf.scene);
roughnessMipmapper.dispose();
render();
});
});
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1;
renderer.outputEncoding = THREE.sRGBEncoding;
container.appendChild(renderer.domElement);
var pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileEquirectangularShader();
controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render); // use if there is no animation loop
controls.minDistance = 2;
controls.maxDistance = 32;
controls.target.set(0, 0, -0.2);
controls.update();
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
//
function render() {
renderer.render(scene, camera);
}
</script>

Looks like self-transparency artifacts. You should always set depthWrite to false if you encounter such rendering problems. But even this setting might not help to remove all glitches since correctly rendering transparency is very tricky. You would need a special Order-independent transparency algorithm like depth-peeling which is not supported by three.js.
https://en.wikipedia.org/wiki/Order-independent_transparency
Related issue at GitHub: https://github.com/mrdoob/three.js/issues/9977

Related

Can't implement post.processing with EffectComposer in Three.js

Im trying to implement post-processing effects in Three.js through this example here:
https://threejs.org/docs/#manual/en/introduction/How-to-use-post-processing
With the following code:
import * as THREE from 'three';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
var scene, camera, renderer, box, composer;
init();
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color("#333333");
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: new THREE.Color('skyblue') });
box = new THREE.Mesh(geometry, material);
scene.add(box);
const light = new THREE.DirectionalLight();
light.position.set(0, 1, 2);
scene.add(light);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement);
// add EFFECT
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const filmPass = new FilmPass(0.35, 0.025, 648, false,);
filmPass.renderToScreen = true;
composer.addPass(filmPass);
window.addEventListener('resize', onResize, false);
update();
}
function update() {
requestAnimationFrame(update);
box.rotation.y += 0.01;
composer.render(scene, camera);
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
composer.setSize(window.innerWidth, window.innerHeight);
}
This gives me error that it cant find /node_modules/three/examples/jsm/postprocessing/
This is indead true. The file does not exist anymore for some reason in my version of three
I found this:
https://www.npmjs.com/package/postprocessing
and did try to install and use that instead but without success:
npm install three postprocessing
And the following code:
import * as THREE from 'three';
import { BloomEffect, EffectComposer, EffectPass, RenderPass } from "postprocessing";
var scene, camera, renderer, box, composer;
init();
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color("#333333");
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: new THREE.Color('skyblue') });
box = new THREE.Mesh(geometry, material);
scene.add(box);
const light = new THREE.DirectionalLight();
light.position.set(0, 1, 2);
scene.add(light);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement);
// add EFFECT
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
// const filmPass = new BloomEffect());
// filmPass.renderToScreen = true;
composer.addPass(new BloomEffect());
window.addEventListener('resize', onResize, false);
update();
}
function update() {
requestAnimationFrame(update);
box.rotation.y += 0.01;
composer.render(scene, camera);
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
composer.setSize(window.innerWidth, window.innerHeight);
}
This render my scene all black.
What am I doing wrong? How do I implement EffectComposer in Three.js

Play a GLTF animation? three.js

Hi I have been messing around with three.js for the past week or so, I am completely new to the lib so apologies for anything stupid I may say or ask.
I have my code which throws no errors but it does have 1 warning:
three.module.js:18314 THREE.WebGLProgram: gl.getProgramInfoLog() C:\fakepath(193,23-137): warning X3571: pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values
I'm not sure if that is important or not but anyway! Everything is working fine the model shows but the problem is it doesn't play any animation what am I doing wrong? here is the code:
import * as THREE from './js/three.module.js';
import {
RGBELoader
} from './js/RGBELoader.js';
import {
OrbitControls
} from './js/OrbitControls.js';
import {
GLTFLoader
} from './js/GLTFLoader.js';
import {
RoughnessMipmapper
} from './js/RoughnessMipmapper.js';
var container, controls;
var camera, scene, renderergl, model, mixer, clock;
init();
animate();
function init() {
container = document.createElement('div');
container.className = "experience-div";
$('body').prepend(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 0.6, 5.7);
scene = new THREE.Scene();
clock = new THREE.Clock();
new RGBELoader()
.load('royal_esplanade_1k.hdr', function(texture) {
var envMap = pmremGenerator.fromEquirectangular(texture).texture;
scene.environment = envMap;
texture.dispose();
pmremGenerator.dispose();
render();
var roughnessMipmapper = new RoughnessMipmapper(renderergl);
let mixer;
const loader = new GLTFLoader();
loader.load('untitled.gltf', function(gltf) {
const model = gltf.scene;
scene.add(model);
mixer = new THREE.AnimationMixer(model);
gltf.animations.forEach((clip) => {
mixer.clipAction(clip).play();
});
gltf.scene.traverse(function(child) {
if (child.isMesh) {
roughnessMipmapper.generateMipmaps(child.material);
}
});
roughnessMipmapper.dispose();
});
});
renderergl = new THREE.WebGLRenderer({
antialias: true
});
renderergl.setPixelRatio(window.devicePixelRatio);
renderergl.setSize(window.innerWidth, window.innerHeight);
renderergl.toneMapping = THREE.ACESFilmicToneMapping;
renderergl.toneMappingExposure = 0.8;
renderergl.outputEncoding = THREE.sRGBEncoding;
container.appendChild(renderergl.domElement);
$('.experience-div canvas').attr('id', 'canvas');
var pmremGenerator = new THREE.PMREMGenerator(renderergl);
pmremGenerator.compileEquirectangularShader();
controls = new OrbitControls(camera, renderergl.domElement);
controls.enableKeys = false;
controls.enableZoom = false;
controls.enableDamping = true;
controls.maxPolarAngle = 2.2;
controls.minPolarAngle = 1.1;
controls.dampingFactor = 0.1;
controls.rotateSpeed = 0.2;
controls.minDistance = 2;
controls.maxDistance = 500;
controls.update();
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderergl.setSize(window.innerWidth, window.innerHeight);
render();
}
function animate() {
controls.update();
requestAnimationFrame(animate);
var delta = clock.getDelta();
if (mixer) mixer.update(delta);
render();
}
function render() {
renderergl.render(scene, camera);
}
Thank you for any help
you can get the model I am using from here:
https://ui-unicorn.co.uk/model-key.zip
Try it with this code instead:
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three#0.114/build/three.module.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/loaders/GLTFLoader.js';
import { RGBELoader } from 'https://cdn.jsdelivr.net/npm/three#0.114/examples/jsm/loaders/RGBELoader.js';
var container, controls;
var camera, scene, renderer, mixer, clock;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
camera.position.set( - 2.8, 0.6, 3.7 );
scene = new THREE.Scene();
clock = new THREE.Clock();
new RGBELoader()
.setDataType( THREE.UnsignedByteType )
.setPath( 'https://threejs.org/examples/textures/equirectangular/' )
.load( 'royal_esplanade_1k.hdr', function ( texture ) {
var envMap = pmremGenerator.fromEquirectangular( texture ).texture;
scene.background = envMap;
scene.environment = envMap;
texture.dispose();
pmremGenerator.dispose();
// model
var loader = new GLTFLoader();
loader.load( 'https://cdn.glitch.com/378a8eca-f405-469a-b32e-b603069e5372%2Funtitled.glb?v=1584360698775', function ( gltf ) {
scene.add( gltf.scene );
mixer = new THREE.AnimationMixer( gltf.scene );
gltf.animations.forEach( ( clip ) => {
mixer.clipAction( clip ).play();
} );
} );
} );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.8;
renderer.outputEncoding = THREE.sRGBEncoding;
container.appendChild( renderer.domElement );
var pmremGenerator = new THREE.PMREMGenerator( renderer );
pmremGenerator.compileEquirectangularShader();
controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 2;
controls.maxDistance = 10
controls.target.set( 0, 0, - 0.2 );
controls.update();
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
var delta = clock.getDelta();
if ( mixer ) mixer.update( delta );
renderer.render( scene, camera );
}
</script>
three.js R114

Three.js showing white model

I am trying to display a 3D .obj model in a webpage using three.js. The model is an obj file. I can see the model using the three.js script but it has a weird while color.
The original model looks like Original. (Used a 3D viewer to upload the obj file). But the output I am getting is totally white. three.js
<script>
if (!Detector.webgl) {
Detector.addGetWebGLMessage();
}
var container;
var camera, controls, scene, renderer;
var lighting, ambient, keyLight, fillLight, backLight;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
/* Camera */
camera = new THREE.PerspectiveCamera(45, window.innerWidth /window.innerHeight, 1, 90000000000);
camera.position.z = 4000;
/* Scene */
scene = new THREE.Scene();
lighting = false;
ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 10%, 7%)'), 1.0);
keyLight.position.set(-100, 0, 100);
fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 10%, 7%)'), 0.75);
fillLight.position.set(100, 0, 100);
backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
/* Model */
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl('caster/');
mtlLoader.setPath('caster/');
mtlLoader.load('edger-QLgame.mtl', function (materials) {
materials.preload();
//materials.materials.default.map.magFilter = THREE.NearestFilter;
//materials.materials.default.map.minFilter = THREE.LinearFilter;
var objLoader = new THREE.OBJLoader();
//objLoader.setMaterials(materials);
mtlLoader.setBaseUrl('caster/');
objLoader.setPath('caster/');
objLoader.load('edger-QLgame.obj', function (object) {
scene.add(object);
});
});
/* Renderer */
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color("hsl(0, 0%, 10%)"));
renderer.gammaOutput = true;
container.appendChild(renderer.domElement);
/* Controls */
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
/* Events */
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('keydown', onKeyboardEvent, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onKeyboardEvent(e) {
if (e.code === 'KeyL') {
lighting = !lighting;
if (lighting) {
ambient.intensity = 0.25;
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
} else {
ambient.intensity = 1.0;
scene.remove(keyLight);
scene.remove(fillLight);
scene.remove(backLight);
}
}
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
function render() {
renderer.render(scene, camera);
}
function onDocumentMouseWheel( event ) {
var fovMAX = 160;
var fovMIN = 1;
camera.fov -= event.wheelDeltaY * 0.05;
camera.fov = Math.max( Math.min( camera.fov, fovMAX ), fovMIN );
camera.projectionMatrix = new THREE.Matrix4().makePerspective(camera.fov, window.innerWidth / window.innerHeight, camera.near, camera.far);
}

How do I position geometry in Threejs to the bottom maintaining its aspect ratio

I am new to Threejs and facing a problem in the positioning of geometry. I want to position geometry at the bottom and it should be half cut i.e like half area should be visible but when try adding position.setY(-300), it moves down but stretches the geometry. I don't know what I am doing wrong or what will be the correct way to position the geometry without losing its aspect ratio. Can some help me to solve this?
I am also attaching the link of fiddle and code: link to fiddle
var camera, scene, renderer;
var geometry, material, muesum;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 600;
scene = new THREE.Scene();
geometry = new THREE.IcosahedronGeometry(350, 2);
material = new THREE.MeshPhongMaterial({
wireframe: true,
});
muesum = new THREE.Mesh(geometry, material);
scene.add(muesum);
muesum.position.setY(-300);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
muesum.rotation.x += 0.001;
muesum.rotation.y += 0.002;
renderer.clear();
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
What you call "losing its aspect ratio.", is the perspective projection, of an big object, that is very close to the camera.
If you don't want that, then you have to use the OrthographicCamera, which creates an orthographic projection matrix and projects the scene parallel on the viewport.
See the Example:
var camera, scene, renderer;
var geometry, material, muesum;
init();
animate();
function updateCameraProjection() {
var aspect = window.innerWidth / window.innerHeight;
var wndHeight = 700;
camera.right = aspect*wndHeight/2
camera.left = -camera.right;
camera.top = wndHeight/2;
camera.bottom = -camera.top;
camera.near = 1;
camera.far = 1000;
camera.updateProjectionMatrix();
}
function init() {
camera = new THREE.OrthographicCamera();
updateCameraProjection();
camera.position.z = 500;
scene = new THREE.Scene();
geometry = new THREE.IcosahedronGeometry(350, 2);
material = new THREE.MeshPhongMaterial({
wireframe: true,
});
muesum = new THREE.Mesh(geometry, material);
scene.add(muesum);
muesum.position.setY(camera.bottom);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
updateCameraProjection();
muesum.position.setY(camera.bottom);
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
muesum.rotation.x += 0.001;
muesum.rotation.y += 0.002;
renderer.clear();
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>

Three.js: How can I make a 2D SnapShot of a Scene as a JPG Image?

I have a three.js scene like the following:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
Is it possible to make a 2D SnapShot or ScreenShot from a Scene and export it as a JPG Image?
There are a couple of things you will have to do to save the frame as a jpg image.
Firstly initialize the WebGL context like this
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true
});
preserveDrawingBuffer flag will help you to get the base64 encoding of the current frame
The code for that will be something like this
var strMime = "image/jpeg";
imgData = renderer.domElement.toDataURL(strMime);
Now secondly you might want to save the file using a .jpg extension, but not all browsers allow you to specify the file name.
The best solution I found was in this SO thread.
So our script will check if the browser allows it will create a new anchor element and set its download and click it(which will save the file in a specified filename) else it will just download the file but the user will have to rename it with a .jpg extension to open it.
Codepen Link
var camera, scene, renderer;
var mesh;
var strDownloadMime = "image/octet-stream";
init();
animate();
function init() {
var saveLink = document.createElement('div');
saveLink.style.position = 'absolute';
saveLink.style.top = '10px';
saveLink.style.width = '100%';
saveLink.style.background = '#FFFFFF';
saveLink.style.textAlign = 'center';
saveLink.innerHTML =
'Save Frame';
document.body.appendChild(saveLink);
document.getElementById("saveLink").addEventListener('click', saveAsImage);
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry(200, 200, 200);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
function saveAsImage() {
var imgData, imgNode;
try {
var strMime = "image/jpeg";
var strDownloadMime = "image/octet-stream";
imgData = renderer.domElement.toDataURL(strMime);
saveFile(imgData.replace(strMime, strDownloadMime), "test.jpg");
} catch (e) {
console.log(e);
return;
}
}
var saveFile = function (strData, filename) {
var link = document.createElement('a');
if (typeof link.download === 'string') {
document.body.appendChild(link); //Firefox requires the link to be in the body
link.download = filename;
link.href = strData;
link.click();
document.body.removeChild(link); //remove the link when done
} else {
location.replace(uri);
}
}
html, body {
padding:0px;
margin:0px;
}
canvas {
width: 100%;
height: 100%
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r69/three.min.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>
Edit Dec 2022
As Mohammad Tbeishat pointed out in a comment this is a more preformat API available now canvas.toBlob you can refer to at
https://r105.threejsfundamentals.org/threejs/lessons/threejs-tips.html

Categories