gpt4 book ai didi

canvas - Three.js canvas.toDataURL 有时为空

转载 作者:行者123 更新时间:2023-12-02 07:22:00 27 4
gpt4 key购买 nike

我正在尝试使用 html2canvas.js 渲染 THREE.js 场景 + 一些重叠的 HTML 元素。它大多数时候都有效,但并非总是有效。

在失败的情况下,HTML 元素会被渲染(背景、覆盖层等),但不会渲染其他元素。 THREE.js 场景表现得好像完全是空的,尽管它明显包含数据。我可以说,对于较大的模型,它通常会失败,但只是在渲染的早期阶段。它最终在所有情况下都有效,但较大的模型大约需要 30 秒。就好像我必须给缓冲区一些时间来稳定。

html2canvas 按照您的预期处理 THREE.js Canvas - 它只是使用 drawImage 将 THREE.js Canvas 绘制到库最终返回的新 Canvas 上。

否则,我会尝试确保 Canvas 上没有其他任何事情,就像这个 fiddle 一样: http://jsfiddle.net/TheJim01/k6dto5sk/63/ (下面是js代码)

正如您所看到的,我做了很多努力来尝试阻止渲染循环,并在我想要捕获场景时再执行一次渲染。但即使所有这些预防措施似乎也没有帮助。

是否有更好的方法从 THREE.js Canvas 中获取图像?我可以手动完成该部分,然后将 THREE.js Canvas 换成足够长的时间,以便 html2canvas 完成其工作,然后将 THREE.js Canvas 换回。我不想这样做,所以如果用户制作大量快照(图像资源,到处都是图像资源......),我不会弄乱 DOM。

无论如何,这是代码。欢迎任何想法或建议。谢谢!

var hostDiv, scene, renderer, camera, root, controls, light, shape, theta, aniLoopId, animating;
function snap() {
animating = false;
cancelAnimationFrame(aniLoopId);
renderer.render(scene, camera);

// html2canvas version:
/*
var element = document.getElementById('scenePlusOverlays');
// the input buttons represent my overlays
html2canvas( element, function(canvas) {
// I'd convert the returned canvas to a PNG
animating = true;
animate();
});
*/

// This is basically what html2canvas does with the THREE.js canvas.
var c = document.getElementById('rendererCanvas');
var toC = document.createElement('canvas');
toC.width = c.width;
toC.height = c.height;
var toCtx = toC.getContext('2d');
toCtx.drawImage(c, 0, 0);
console.log(toC.toDataURL('image/png'));
animating = true;
animate();
}
function addGeometry() {
//var geo = new THREE.BoxGeometry(1, 1, 1);
var geo = new THREE.SphereGeometry(5, 32, 32);
var beo = new THREE.BufferGeometry().fromGeometry(geo);
geo.dispose();
geo = null;
var mat = new THREE.MeshPhongMaterial({color:'red'});
var msh;

var count = 10;
count /= 2;
var i = 20;
var topLayer = new THREE.Object3D();
var zLayer, xLayer, yLayer;
for(var Z = -count; Z < count; Z++){
zLayer = new THREE.Object3D();
for(var X = -count; X < count; X++){
xLayer = new THREE.Object3D();
for(var Y = -count; Y < count; Y++){
yLayer = new THREE.Object3D();
msh = new THREE.Mesh(beo, mat);
yLayer.add(msh);
msh.position.set((X*i)+(i/2), (Y*i)+(i/2), (Z*i)+(i/2));
xLayer.add(yLayer);
}
zLayer.add(xLayer);
}
topLayer.add(zLayer);
}
scene.add(topLayer);
}
var WIDTH = '500';//window.innerWidth,
HEIGHT = '500';//window.innerHeight,
FOV = 35,
NEAR = 0.1,
FAR = 10000;

function init() {
hostDiv = document.getElementById('hostDiv');
document.body.insertBefore(hostDiv, document.body.firstElementChild);

renderer = new THREE.WebGLRenderer({ antialias: true, preserverDrawingBuffer: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.domElement.setAttribute('id', 'rendererCanvas');
hostDiv.appendChild(renderer.domElement);

camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 500;

controls = new THREE.TrackballControls(camera, renderer.domElement);

light = new THREE.PointLight(0xffffff, 1, Infinity);
light.position.copy(camera.position);

scene = new THREE.Scene();
scene.add(camera);
scene.add(light);

animating = true;
animate();
}

function animate() {
if(animating){
light.position.copy(camera.position);
aniLoopId = requestAnimationFrame(animate);
}
renderer.render(scene, camera);
controls.update();
}

编辑:以所描述的方式调用 readPixels 或 toDataURL 是可能的——我曾考虑过使用类似的方法来获取缓冲区,但由于所需的异步代码量而推迟了。像这样的事情:

var global_callback = null;
function snapshot_method() {
global_callback = function(returned_image) {
// do something with the image
}
}
// ...
function render() {
renderer.render();
if(global_callback !== null) {
global_callback(renderer.domElement.toDataURL());
global_callback = null;
}
}

最佳答案

(为了 future Google 员工的利益):实例化 WebGLRenderer 时,您需要将 preserveDrawingBuffer 设置为 true:

renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });

(原始代码有这个,但有一个拼写错误)。这是必需的,因为默认情况下,WebGL 不要求浏览器在每个绘图帧后保存深度/颜色缓冲区,因此如果您想使用 readPixelstoDataURL,您可以需要明确告诉实现使用该标志保存绘图缓冲区。

但是,这样做会降低性能; the spec provides some guidance if this is a problem for you :

While it is sometimes desirable to preserve the drawing buffer, it can cause significant performance loss on some platforms. Whenever possible this flag should remain false and other techniques used. Techniques like synchronous drawing buffer access (e.g., calling readPixels or toDataURL in the same function that renders to the drawing buffer) can be used to get the contents of the drawing buffer. If the author needs to render to the same drawing buffer over a series of calls, a Framebuffer Object can be used.

我不确定这些建议在当前版本的 Three.js (r68) 中是否可行,但还有另一种替代解决方案(调用 readPixelstoDataURL在 Canvas 的副本上)讨论了其他几个问题( Why does my canvas go blank after converting to image?How do you save an image from a Three.js canvas? )。

关于canvas - Three.js canvas.toDataURL 有时为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26431862/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com