“在 WebGL 中如何繪制文本”是一個我們常見的問題。那么第一件事就是我們要問自己繪制文本的目的何在。現(xiàn)在有一個瀏覽器,瀏覽器用來顯示文本。所以你的第一個答案應該是如何使用 HTML 來顯示文本。
讓我們從最簡單的例子開始:你只是想在你的 WebGL 上繪制一些文本。我們可以稱之為一個文本覆蓋。基本上這是停留在同一個位置的文本。
簡單的方法是構造一些 HTML 元素,使用 CSS 使它們重疊。
例如:先構造一個容器,把畫布和一些 HTML 元素重疊放置在容器內(nèi)部。
<div class="container">
<canvas id="canvas" width="400" height="300"></canvas>
<div id="overlay">
<div>Time: <span id="time"></span></div>
<div>Angle: <span id="angle"></span></div>
</div>
</div>
接下來設置 CSS,以達到畫布和 HTML 重疊的目的。
.container {
position: relative;
}
#overlay {
position: absolute;
left: 10px;
top: 10px;
}
現(xiàn)在按照初始化和創(chuàng)建時間查找這些元素,或者查找你想要改變的區(qū)域。
// look up the elements we want to affect
var timeElement = document.getElementById("time");
var angleElement = document.getElementById("angle");
// Create text nodes to save some time for the browser.
var timeNode = document.createTextNode("");
var angleNode = document.createTextNode("");
// Add those text nodes where they need to go
timeElement.appendChild(timeNode);
angleElement.appendChild(angleNode);
最后在渲染時更新節(jié)點。
function drawScene() {
...
// convert rotation from radians to degrees
var angle = radToDeg(rotation[1]);
// only report 0 - 360
angle = angle % 360;
// set the nodes
angleNode.nodeValue = angle.toFixed(0); // no decimal place
timeNode.nodeValue = clock.toFixed(2); // 2 decimal places
這里有一個例子:
注意為了我想改變的部分,我是如何把 spans 置入特殊的 div 內(nèi)的。在這里我做一個假設,這比只使用 div 而沒有 spans 速度要快,類似的有:
timeNode.value = "Time " + clock.toFixed(2);
另外,我們可以使用文本節(jié)點,通過調(diào)用 node = document.createTextNode() 和 laternode.node = someMsg。我們也可以使用 someElement.innerHTML = someHTML。這將會更加靈活,雖然這樣可能會稍微慢一些,但是您卻可以插入任意的 HTML 字符串,因為你每次設置它,瀏覽器都不得不創(chuàng)建和銷毀節(jié)點。這對你來說更加方便。
不采用疊加技術很重要的一點是,WebGL 在瀏覽器中運行。要記得在適當?shù)臅r候使用瀏覽器的特征。大量的 OpenGL 程序員習慣于從一開始就 100% 靠他們自己實現(xiàn)應用的每一部分自己,因為 WebGL 要在一個已經(jīng)有很多特征的瀏覽器上運行。使用它們有很多好處。例如使用 CSS 樣式,你可以很容易就覆蓋一個有趣的風格。
這里有一個相同的例子,但是添加了一些風格。背景是圓形的,字母的周圍有光暈。這兒有一個紅色的邊界。你可以使用 HTML 免費得到所有。
我們要討論的下一件最常見的事情是文本相對于你渲染的東西的位置。我們也可以在 HTML 中做到這一點。
在本例中,我們將再次構造一個畫布容器和另一個活動的 HTML 容器。
<div class="container">
<canvas id="canvas" width="400" height="300"></canvas>
<div id="divcontainer"></div>
</div>
我們將設置 CSS
.container {
position: relative;
overflow: none;
}
#divcontainer {
position: absolute;
left: 0px;
top: 0px;
width: 400px;
height: 300px;
z-index: 10;
overflow: hidden;
}
.floating-div {
position: absolute;
}
相對于第一個 父類位置 position: relative 或者 position: absolute 風格,position: absolute; 部分使 #divcontainer 放置于絕對位置。在本例中,畫布和 #divcontainer 都在容器內(nèi)。
left: 0px; top: 0px 使 #divcontainer 結合一切。z-index: 10 使它浮在畫布上。overflow: hidden 讓它的子類被剪除。
最后,floating-div 將使用我們創(chuàng)建的可移式 div。
現(xiàn)在我們需要查找 div 容器,創(chuàng)建一個 div,將 div 附加到容器。
// look up the divcontainer
var divContainerElement = document.getElementById("divcontainer");
// make the div
var div = document.createElement("div");
// assign it a CSS class
div.className = "floating-div";
// make a text node for its content
var textNode = document.createTextNode("");
div.appendChild(textNode);
// add it to the divcontainer
divContainerElement.appendChild(div);
現(xiàn)在,我們可以通過設置它的風格定位 div。
div.style.left = Math.floor(x) + "px";
div.style.top = Math.floor(y) + "px";
textNode.nodeValue = clock.toFixed(2);
下面是一個例子,我們只需要限制 div 的邊界。
下一步,我們想在 3D 場景中設計它相對于某些事物的位置。我們該如何做?當我們透視投影覆蓋,我們?nèi)绾巫鰧嶋H上就是我們請求 GPU 如何做。
通過這個例子我們學習了如何使用模型,如何復制它們,以及如何應用一個投影模型將他們轉換成 clipspace。然后我們討論著色器的內(nèi)容,它在本地空間復制模型,并將其轉換成 clipspace。我們也可以在 JavaScript 中做所有的這些。然后我們可以增加 clipspace(-1 到 +1) 到像素和使用 div 位置。
gl.drawArrays(...);
// We just got through computing a matrix to draw our
// F in 3D.
// choose a point in the local space of the 'F'.
// X Y Z W
var point = [100, 0, 0, 1]; // this is the front top right corner
// compute a clipspace position
// using the matrix we computed for the F
var clipspace = matrixVectorMultiply(point, matrix);
// divide X and Y by W just like the GPU does.
clipspace[0] /= clipspace[3];
clipspace[1] /= clipspace[3];
// convert from clipspace to pixels
var pixelX = (clipspace[0] * 0.5 + 0.5) * gl.canvas.width;
var pixelY = (clipspace[1] * -0.5 + 0.5) * gl.canvas.height;
// position the div
div.style.left = Math.floor(pixelX) + "px";
div.style.top = Math.floor(pixelY) + "px";
textNode.nodeValue = clock.toFixed(2);
wahlah,我們 div 的左上角和 F 的右上角完全符合。
當然,如果你想要更多的文本構造更多的 div,如下:
你可以查看最后一個例子的源代碼來觀察細節(jié)。一個重要的點是我猜測從 DOM 創(chuàng)建、添加、刪除 HTML 元素是緩慢的,所以上面的示例用來創(chuàng)建它們,將它們保留在周圍。它將任何未使用的都隱藏起來,而不是把他們從 DOM 刪除。你必須明確知道是否可以更快。這只是我選擇的方法。
希望這已經(jīng)清楚地說明了如何使用 HTML 制造文本。接下來,我們將介紹如何使用 Canvas2D 制造文本。
更多建議: