WebGL 文本 HTML

2018-10-03 11:48 更新

WebGL 文本 HTML

“在 WebGL 中如何繪制文本”是一個(gè)我們常見的問(wèn)題。那么第一件事就是我們要問(wèn)自己繪制文本的目的何在。現(xiàn)在有一個(gè)瀏覽器,瀏覽器用來(lái)顯示文本。所以你的第一個(gè)答案應(yīng)該是如何使用 HTML 來(lái)顯示文本。

讓我們從最簡(jiǎn)單的例子開始:你只是想在你的 WebGL 上繪制一些文本。我們可以稱之為一個(gè)文本覆蓋?;旧线@是停留在同一個(gè)位置的文本。

簡(jiǎn)單的方法是構(gòu)造一些 HTML 元素,使用 CSS 使它們重疊。

例如:先構(gòu)造一個(gè)容器,把畫布和一些 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>

接下來(lái)設(shè)置 CSS,以達(dá)到畫布和 HTML 重疊的目的。

.container {
position: relative;
}
#overlay {
position: absolute;
left: 10px;
top: 10px;
}

現(xiàn)在按照初始化和創(chuàng)建時(shí)間查找這些元素,或者查找你想要改變的區(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);

最后在渲染時(shí)更新節(jié)點(diǎn)。

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

這里有一個(gè)例子:

注意為了我想改變的部分,我是如何把 spans 置入特殊的 div 內(nèi)的。在這里我做一個(gè)假設(shè),這比只使用 div 而沒有 spans 速度要快,類似的有:

timeNode.value = "Time " + clock.toFixed(2);

另外,我們可以使用文本節(jié)點(diǎn),通過(guò)調(diào)用 node = document.createTextNode()laternode.node = someMsg。我們也可以使用 someElement.innerHTML = someHTML。這將會(huì)更加靈活,雖然這樣可能會(huì)稍微慢一些,但是您卻可以插入任意的 HTML 字符串,因?yàn)槟忝看卧O(shè)置它,瀏覽器都不得不創(chuàng)建和銷毀節(jié)點(diǎn)。這對(duì)你來(lái)說(shuō)更加方便。

不采用疊加技術(shù)很重要的一點(diǎn)是,WebGL 在瀏覽器中運(yùn)行。要記得在適當(dāng)?shù)臅r(shí)候使用瀏覽器的特征。大量的 OpenGL 程序員習(xí)慣于從一開始就 100% 靠他們自己實(shí)現(xiàn)應(yīng)用的每一部分自己,因?yàn)?WebGL 要在一個(gè)已經(jīng)有很多特征的瀏覽器上運(yùn)行。使用它們有很多好處。例如使用 CSS 樣式,你可以很容易就覆蓋一個(gè)有趣的風(fēng)格。

這里有一個(gè)相同的例子,但是添加了一些風(fēng)格。背景是圓形的,字母的周圍有光暈。這兒有一個(gè)紅色的邊界。你可以使用 HTML 免費(fèi)得到所有。

我們要討論的下一件最常見的事情是文本相對(duì)于你渲染的東西的位置。我們也可以在 HTML 中做到這一點(diǎn)。

在本例中,我們將再次構(gòu)造一個(gè)畫布容器和另一個(gè)活動(dòng)的 HTML 容器。

<div class="container">
  <canvas id="canvas" width="400" height="300"></canvas>
  <div id="divcontainer"></div>
</div>

我們將設(shè)置 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;
}

相對(duì)于第一個(gè) 父類位置 position: relative 或者 position: absolute 風(fēng)格,position: absolute; 部分使 #divcontainer 放置于絕對(duì)位置。在本例中,畫布和 #divcontainer 都在容器內(nèi)。

left: 0px; top: 0px 使 #divcontainer 結(jié)合一切。z-index: 10 使它浮在畫布上。overflow: hidden 讓它的子類被剪除。

最后,floating-div 將使用我們創(chuàng)建的可移式 div。

現(xiàn)在我們需要查找 div 容器,創(chuàng)建一個(gè) 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)在,我們可以通過(guò)設(shè)置它的風(fēng)格定位 div。

div.style.left = Math.floor(x) + "px";
div.style.top  = Math.floor(y) + "px";
textNode.nodeValue = clock.toFixed(2);

下面是一個(gè)例子,我們只需要限制 div 的邊界。

下一步,我們想在 3D 場(chǎng)景中設(shè)計(jì)它相對(duì)于某些事物的位置。我們?cè)撊绾巫觯慨?dāng)我們透視投影覆蓋,我們?nèi)绾巫鰧?shí)際上就是我們請(qǐng)求 GPU 如何做。

通過(guò)這個(gè)例子我們學(xué)習(xí)了如何使用模型,如何復(fù)制它們,以及如何應(yīng)用一個(gè)投影模型將他們轉(zhuǎn)換成 clipspace。然后我們討論著色器的內(nèi)容,它在本地空間復(fù)制模型,并將其轉(zhuǎn)換成 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 的右上角完全符合。

當(dāng)然,如果你想要更多的文本構(gòu)造更多的 div,如下:

你可以查看最后一個(gè)例子的源代碼來(lái)觀察細(xì)節(jié)。一個(gè)重要的點(diǎn)是我猜測(cè)從 DOM 創(chuàng)建、添加、刪除 HTML 元素是緩慢的,所以上面的示例用來(lái)創(chuàng)建它們,將它們保留在周圍。它將任何未使用的都隱藏起來(lái),而不是把他們從 DOM 刪除。你必須明確知道是否可以更快。這只是我選擇的方法。

希望這已經(jīng)清楚地說(shuō)明了如何使用 HTML 制造文本。接下來(lái),我們將介紹如何使用 Canvas2D 制造文本。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)