A 型框架 + pdf.js:无法两次更新画布纹理,仅在 VR 模式下
我正在使用 A-Frame 和 pdf.js 创建一个应用程序来在 VR 中查看 PDF 文件。该应用程序在桌面上按预期工作,包括前进到 PDF 文档的下一页并重新渲染到画布。
当在 VR 浏览器中运行时(使用 Quest 2 进行测试),第一次尝试会按预期呈现。但是,当将第二个文档页面渲染到画布时,新图像将无法显示,除非退出 VR 模式,此时新纹理将按预期显示。
我尝试重复设置关联的材质map.needsUpdate
(在A-Frame组件滴答循环中),但没有效果。在实验过程中,我还注意到,如果您尝试第二次渲染一个新的 PDF 页面,然后第三次渲染另一个页面(在 VR 模式下前进两页),则退出 VR 模式时,只会出现第二次的纹理;第三次渲染的数据似乎丢失了 - 我想知道这是否与主要问题有关。
下面是一个最小示例的代码,实时版本可在 http://stemkoski 获取.net/test/quest-pdf-min.html 。在桌面模式下查看示例时,您可以通过打开浏览器 JavaScript 控制台并输入 testBook.nextPage();
前进到下一页,并看到图像按预期更改。您可以使用Quest耳机在VR模式下进行测试;按 A 按钮应前进到下一页。
问题是:如何在 A-Frame 的 VR 模式下多次将 PDF 文档的页面渲染到同一画布?
<!DOCTYPE html>
<html>
<head>
<title>A-Frame + PDF.js</title>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.6.347/pdf.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent("interactive-pdf", {
schema:
{
fileName: {type: 'string', default:"assets/test10.pdf"},
pageWidth: {type: 'float', default: 1200},
pageHeight: {type: 'float', default: 1500},
},
init: function ()
{
this.displayPlane = document.getElementById("plane1");
this.displayMaterial = this.displayPlane.getObject3D('mesh').material;
this.canvas = this.displayPlane.getAttribute("material").src
this.canvas.setAttribute("width", this.data.pageWidth);
this.canvas.setAttribute("height", this.data.pageHeight);
this.context = this.canvas.getContext('2d');
this.textArea = document.querySelector("#textArea");
this.pdf = null;
this.currentPage = 1;
pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.6.347/pdf.worker.js";
let self = this;
pdfjsLib.getDocument(this.data.fileName).promise.then( function(pdf) {
self.pdf = pdf;
self.render(1);
});
},
render(pageNumber = 1)
{
if (!this.pdf)
return;
let self = this;
let text = "rendering page " + pageNumber + " of " + this.pdf.numPages + " on canvas";
this.textArea.setAttribute("text", "value", text);
this.pdf.getPage(pageNumber).then( function(page) {
const pageViewport = page.getViewport({ scale: 2 });
const context = self.canvas.getContext("2d");
const renderContext = {
canvasContext: context,
viewport: pageViewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then( function() {
self.displayMaterial.map.needsUpdate = true;
});
});
},
nextPage: function()
{
this.currentPage++;
this.render( this.currentPage );
},
prevPage: function()
{
this.currentPage--;
this.render( this.currentPage );
},
tick: function()
{
// this.displayMaterial.map.needsUpdate = true;
}
});
AFRAME.registerComponent('page-turner', {
init: function ()
{
let bookComponent = document.getElementById("interactive-pdf").components["interactive-pdf"];
this.el.addEventListener('abuttondown', function(event) { bookComponent.nextPage(); } );
}
});
</script>
<a-scene>
<a-assets>
<!-- use to display pdf pages -->
<canvas id="canvas1"></canvas>
</a-assets>
<a-camera></a-camera>
<a-sky color = "#000337"></a-sky>
<a-plane id="plane1" material="shader: flat; src: #canvas1;" position="0 1 -2"></a-plane>
<a-entity id="interactive-pdf" position="0 1 -2"
interactive-pdf="fileName: assets/test10.pdf; pageWidth: 1224; pageHeight: 1584;">
</a-entity>
<a-entity id="left-controller" oculus-touch-controls="hand: left"></a-entity>
<a-entity id="right-controller" oculus-touch-controls="hand: right" page-turner></a-entity>
<!-- text area to print debug text -->
<a-entity id="textArea" position="0 2 -2"
geometry="primitive: plane; width: 3; height: auto"
material="color: #444444;"
text="anchor: center; color: #8888FF; value: debug text here">
</a-entity>
</a-scene>
<script>
var testBook = document.getElementById("interactive-pdf").components["interactive-pdf"];
</script>
</body>
</html>
I am using A-Frame and pdf.js to create an application to view PDF files in VR. The application works as expected on desktop, including advancing to the next page of the PDF document and re-rendering to a canvas.
When running in a browser in VR (tested with Quest 2), the first attempt renders as expected. However, when rendering a second document page to the canvas, the new image fails to appear unless exiting VR mode, at which point the new texture appears as expected.
I have tried setting the associated material map.needsUpdate
repeatedly (in an A-Frame component tick loop) to no effect. While experimenting, I also noticed that if you try to render a new PDF page a second time and then another page a third time (advancing by two pages while in VR mode), when exiting VR mode, only the texture from the second time appears; the data from the third render appears to be lost - I wonder if this is related to the primary issue.
Code for a minimal example is below, and a live version is available at http://stemkoski.net/test/quest-pdf-min.html . When viewing the example in desktop mode, you can advance to the next page by opening the browser JavaScript console and entering testBook.nextPage();
and see that the image changes as expected. You can test in VR mode with a Quest headset; pressing the A button should advance to the next page.
The question is: how can I render pages of a PDF document to the same canvas, multiple times, while in VR mode in A-Frame?
<!DOCTYPE html>
<html>
<head>
<title>A-Frame + PDF.js</title>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.6.347/pdf.js"></script>
</head>
<body>
<script>
AFRAME.registerComponent("interactive-pdf", {
schema:
{
fileName: {type: 'string', default:"assets/test10.pdf"},
pageWidth: {type: 'float', default: 1200},
pageHeight: {type: 'float', default: 1500},
},
init: function ()
{
this.displayPlane = document.getElementById("plane1");
this.displayMaterial = this.displayPlane.getObject3D('mesh').material;
this.canvas = this.displayPlane.getAttribute("material").src
this.canvas.setAttribute("width", this.data.pageWidth);
this.canvas.setAttribute("height", this.data.pageHeight);
this.context = this.canvas.getContext('2d');
this.textArea = document.querySelector("#textArea");
this.pdf = null;
this.currentPage = 1;
pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.6.347/pdf.worker.js";
let self = this;
pdfjsLib.getDocument(this.data.fileName).promise.then( function(pdf) {
self.pdf = pdf;
self.render(1);
});
},
render(pageNumber = 1)
{
if (!this.pdf)
return;
let self = this;
let text = "rendering page " + pageNumber + " of " + this.pdf.numPages + " on canvas";
this.textArea.setAttribute("text", "value", text);
this.pdf.getPage(pageNumber).then( function(page) {
const pageViewport = page.getViewport({ scale: 2 });
const context = self.canvas.getContext("2d");
const renderContext = {
canvasContext: context,
viewport: pageViewport
};
const renderTask = page.render(renderContext);
renderTask.promise.then( function() {
self.displayMaterial.map.needsUpdate = true;
});
});
},
nextPage: function()
{
this.currentPage++;
this.render( this.currentPage );
},
prevPage: function()
{
this.currentPage--;
this.render( this.currentPage );
},
tick: function()
{
// this.displayMaterial.map.needsUpdate = true;
}
});
AFRAME.registerComponent('page-turner', {
init: function ()
{
let bookComponent = document.getElementById("interactive-pdf").components["interactive-pdf"];
this.el.addEventListener('abuttondown', function(event) { bookComponent.nextPage(); } );
}
});
</script>
<a-scene>
<a-assets>
<!-- use to display pdf pages -->
<canvas id="canvas1"></canvas>
</a-assets>
<a-camera></a-camera>
<a-sky color = "#000337"></a-sky>
<a-plane id="plane1" material="shader: flat; src: #canvas1;" position="0 1 -2"></a-plane>
<a-entity id="interactive-pdf" position="0 1 -2"
interactive-pdf="fileName: assets/test10.pdf; pageWidth: 1224; pageHeight: 1584;">
</a-entity>
<a-entity id="left-controller" oculus-touch-controls="hand: left"></a-entity>
<a-entity id="right-controller" oculus-touch-controls="hand: right" page-turner></a-entity>
<!-- text area to print debug text -->
<a-entity id="textArea" position="0 2 -2"
geometry="primitive: plane; width: 3; height: auto"
material="color: #444444;"
text="anchor: center; color: #8888FF; value: debug text here">
</a-entity>
</a-scene>
<script>
var testBook = document.getElementById("interactive-pdf").components["interactive-pdf"];
</script>
</body>
</html>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在此处找到了答案:
它非常相关,因为在将图像渲染到画布上时,
pdf.js
默认使用requestAnimationFrame
。它可以切换 - 页面渲染功能 有一个选项
intent
,稍后用于确定是否使用 requestAnimationFrame。您使用的源略有不同(较旧?),但如果您搜索在
ProxyPDFPage
的render
函数中创建InternalRenderTask
- 它是全部都在那里:您可以在
renderContext
对象中将intent
设置为 print:并且它似乎工作正常:
我不确定将 Intent 设置为
print
是否不会导致不良效果(它也会影响其他设置),因此禁用useRequestAnimationFrame
在source 也能达到这个目的。查看具有“打印”意图的版本,或者带有 修改后的pdfjs源代码。
Found an answer here:
Its quite relevant because
pdf.js
usesrequestAnimationFrame
by default when rendering the image onto the canvas.It can be toggled though - the pages render function has an option
intent
, which is later on used to determine whether to use requestAnimationFrame.The sources You use are slightly different (older?), but if you search for creating the
InternalRenderTask
in therender
function of theProxyPDFPage
- it's all there:You can set the
intent
to print in yourrenderContext
object:And it seems to be working properly:
I'm not sure, if setting the intent to
print
won't cause undesired effects (it affects other settings as well), so disablinguseRequestAnimationFrame
in the source does the trick as well.Check out the version with the 'print' intent, or the one with the modified pdfjs source code.