The*_*m01 3 canvas three.js html5-canvas html2canvas
我正在尝试使用html2canvas.js渲染一个THREE.js场景+一些重叠的HTML元素.它大部分时间都有效,但不是所有时间.
在失败的情况下,HTML元素被渲染(背景,叠加等),但没有别的.THREE.js场景就像它完全是空的一样,即使它明显有数据.我可以说它通常不适用于较大的模型,但只能在渲染的早期.它最终适用于所有情况,但较大型号需要大约30秒.好像我必须给缓冲区一些时间来稳定.
html2canvas按照您的预期处理THREE.js画布 - 它只是用于drawImage将THREE.js画布绘制到最终由库返回的新画布上.
否则,我会尽量确保没有其他东西忙于画布,就像这个小提琴一样:http://jsfiddle.net/TheJim01/k6dto5sk/63/(以下js代码)
正如您所看到的,我正在尝试阻止渲染循环,并且当我想捕获场景时再执行一次渲染.但即使所有这些预防措施似乎都没有帮助.
有没有更好的方法从THREE.js画布中获取图像?我可以手动执行该部分,然后将THREE.js画布替换为获取的图像,只需要足够长的时间让html2canvas完成它的工作,然后将THREE.js画布交换回来.我宁愿不这样做如果用户制作大量快照(图像资源,图像资源无处不在......),那么我就不会混淆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();
}
Run Code Online (Sandbox Code Playgroud)
编辑: 以所描述的方式调用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;
}
}
Run Code Online (Sandbox Code Playgroud)
(为了未来Google员工的利益):您需要设置preserveDrawingBuffer为true实例化时WebGLRenderer:
renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
Run Code Online (Sandbox Code Playgroud)
(原始代码有这个,但有一个错字).这是必需的,因为默认情况下,WebGL不需要浏览器在每个绘图框之后保存深度/颜色缓冲区,因此如果要使用readPixels或toDataURL,则需要明确告诉实现使用该标志保存绘图缓冲区.
但是,这样做会带来性能损失; 如果这对您有问题,那么规范会提供一些指导:
虽然有时需要保留绘图缓冲区,但它可能会在某些平台上造成严重的性能损失.只要有可能,该标志应保持为假并使用其他技术.诸如同步绘图缓冲区访问(例如,在呈现给绘图缓冲区的相同函数中调用readPixels或toDataURL)之类的技术可用于获取绘图缓冲区的内容.如果作者需要通过一系列调用渲染到同一个绘图缓冲区,则可以使用Framebuffer对象.
我不确定这些建议在当前版本的three.js(r68)中是否可行,但是在其他几个问题上讨论了另一种替代解决方案(调用readPixels或toDataURL在画布的副本上)(为什么我的画布去了转换成影像之后的空白?,你如何保存从three.js所画布上的图像?).
| 归档时间: |
|
| 查看次数: |
1604 次 |
| 最近记录: |