开心六月综合激情婷婷|欧美精品成人动漫二区|国产中文字幕综合色|亚洲人在线成视频

    1. 
      
        <b id="zqfy3"><legend id="zqfy3"><fieldset id="zqfy3"></fieldset></legend></b>
          <ul id="zqfy3"></ul>
          <blockquote id="zqfy3"><strong id="zqfy3"><dfn id="zqfy3"></dfn></strong></blockquote>
          <blockquote id="zqfy3"><legend id="zqfy3"></legend></blockquote>
          打開APP
          userphoto
          未登錄

          開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

          開通VIP
          X3D:現(xiàn)代Web的聲明式3D技術(shù)
          作者|Adrian Sureshkumar
          譯者|夏夜
          編輯|王文婧
          現(xiàn)代 Web 技術(shù)使開發(fā)人員能夠創(chuàng)建干凈而視覺豐富的用戶體驗(yàn),這些體驗(yàn)被所有主流瀏覽器作為標(biāo)準(zhǔn)進(jìn)行廣泛支持。那么,如何為 Web 編寫基于標(biāo)準(zhǔn)的可視化程序呢?對 3D 圖形的支持到底又有哪些呢?讓我們首先回顧 HTML 標(biāo)準(zhǔn)中支持的兩種主要方法:SVG 和 Canvas。
          SVG:可伸縮的矢量圖形 

          SVG 本身是基于 XML 的一種獨(dú)立的數(shù)據(jù)格式,用于聲明式的 2D 矢量圖形。但是,它也可以嵌入到 HTML 文檔中,這是所有主流瀏覽器都支持的。

          讓我們考慮一個例子,如何使用 SVG 繪制一個可調(diào)整大小的圓:
          <html style='height: 100%; width: 100%'>
            <body style='height: 100%; width: 100%; margin: 0px'>
              <svg style='height: 100%; width: 100%; display: block' viewBox='0 0 100 100'>
                <circle cx='50' cy='50' r='25' fill='red' stroke='black'
                        vector-effect='non-scaling-stroke' />
              </svg>
            </body>
          </html>

          想要理解這段代碼很容易!我們只是向?yàn)g覽器描述了要繪制什么(與傳統(tǒng) HTML 文檔非常相似)。它保留了這個描述,并負(fù)責(zé)如何在屏幕上繪制它。

          當(dāng)瀏覽器窗口調(diào)整大小或縮放時,它將重新縮放圖像,而不會丟失圖像的任何質(zhì)量(因?yàn)閳D像是根據(jù)形狀定義的,而不是根據(jù)像素定義的)。當(dāng) SVG 元素被 JavaScript 代碼修改時,它還會自動重新繪制圖像,這使得 SVG 特別適合與 JavaScript 庫(如 D3)一起使用,D3 將數(shù)據(jù)綁定到 DOM 中的元素,從而能夠創(chuàng)建從簡單圖表到更奇特的交互式數(shù)據(jù)可視化的任何內(nèi)容。

          這種聲明性方法也稱為保留模式圖形繪制(retained-mode graphics rendering)。

           畫  布 
          canvas 元素只是在網(wǎng)頁上提供了一個可以繪圖的區(qū)域。使用 JavaScript 代碼,首先從畫布獲取上下文,然后使用提供的 API,定義繪制圖像的函數(shù)。
          const canvas = document.getElementById(id);
          const context = canvas.getContext(contextType);

          // call some methods on context to draw onto the canvas

          當(dāng)腳本執(zhí)行時,圖像立即繪制成了底層位圖的像素,瀏覽器不保留繪制方式的任何信息。為了更新繪圖,需要再次執(zhí)行腳本。重新縮放圖像時,也會觸發(fā)更新繪圖,否則,瀏覽器只會拉伸原始位圖,導(dǎo)致圖像明顯模糊或像素化。

          這種函數(shù)式方法也稱為即時模式圖形繪制(immediate-mode graphics rendering)。

          上下文:2D

          首先讓我們考慮 2D 繪制的上下文,它提供了一個用于在畫布上繪制 2D 圖形的高級 API。

          讓我們來看一個例子,看看如何使用它來繪制我們可調(diào)整大小的圓:
          <html style='height: 100%; width: 100%'>
            <body style='height: 100%; width: 100%; margin: 0px'>
              <canvas id='my-canvas' style='height: 100%; width: 100%; display: block'></canvas>
              <script>
                const canvas = document.getElementById('my-canvas');
                const context = canvas.getContext('2d');

                function render() {
                  // Size the drawing surface to match the actual element (no stretch).
                  canvas.height = canvas.clientHeight;
                  canvas.width = canvas.clientWidth;

                  context.beginPath();

                  // Calculate relative size and position of circle in pixels.
                  const x = 0.5 * canvas.width;
                  const y = 0.5 * canvas.height;
                  const radius = 0.25 * Math.min(canvas.height, canvas.width);

                  context.arc(x, y, radius, 0, 2 * Math.PI);

                  context.fillStyle = 'red';
                  context.fill();

                  context.strokeStyle = 'black';
                  context.stroke();
                }

                render();
                addEventListener('resize', render);
              </script>
            </body>
          </html>

          同樣,這非常簡單,但肯定比前面的示例更冗長!我們必須自己根據(jù)畫布的當(dāng)前大小,以像素為單位計(jì)算圓的半徑和中心位置。這也意味著我們必須監(jiān)聽縮放的事件并相應(yīng)地重新繪制。

          那么,既然更加復(fù)雜,為什么還要使用這種方法而不是 SVG 呢?在大多數(shù)情況下,你可能不會使用該方法。然而,這給了你對渲染的內(nèi)容更多的控制。對于要繪制更多對象的、更復(fù)雜的動態(tài)可視化,它可能比更新 DOM 中的大量元素,并讓瀏覽器來決定何時呈現(xiàn)和呈現(xiàn)什么,帶來更好的性能。

          上下文:WebGL 

          大多數(shù)現(xiàn)代瀏覽器也支持 webgl 上下文。這為您提供了使用 WebGL 標(biāo)準(zhǔn)繪制硬件加速圖形的底層 API,盡管這需要 GPU 支持。它可以用來渲染 2D,更重要的是,也可以用來渲染本篇博客所說的 3D 圖形。

          現(xiàn)在讓我們來看一個例子,看看如何使用 WebGL 渲染我們的圓圈:
          <html style='height: 100%; width: 100%'>
            <body style='height: 100%; width: 100%; margin: 0px'>
              <canvas id='my-canvas' style='height: 100%; width: 100%; display: block'></canvas>
              <script>
                const canvas = document.getElementById('my-canvas');
                const context = canvas.getContext('webgl');

                const redColor = new Float32Array([1.0, 0.0, 0.0, 1.0]);
                const blackColor = new Float32Array([0.0, 0.0, 0.0, 1.0]);

                // Use an orthogonal projection matrix as we're rendering in 2D.
                const projectionMatrix = new Float32Array([
                  1.0, 0.0, 0.0, 0.0,
                  0.0, 1.0, 0.0, 0.0,
                  0.0, 0.0, 0.0, 0.0,
                  0.0, 0.0, 0.0, 1.0,
                ]);

                // Define positions of the vertices of the circle (in clip space).
                const radius = 0.5;
                const segmentCount = 360;
                const positions = [0.0, 0.0];
                for (let i = 0; i < segmentCount + 1; i++) {
                    positions.push(radius * Math.sin(2 * Math.PI * i / segmentCount));
                  positions.push(radius * Math.cos(2 * Math.PI * i / segmentCount));
                }

                const positionBuffer = context.createBuffer();
                context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
                context.bufferData(context.ARRAY_BUFFER, new Float32Array(positions), context.STATIC_DRAW);

                // Create shaders and program.
                const vertexShader = context.createShader(context.VERTEX_SHADER);
                context.shaderSource(vertexShader, `
                  attribute vec4 position;
                  uniform mat4 projection;

                  void main() {
                    gl_Position = projection * position;
                  }
                `);
                context.compileShader(vertexShader);

                const fragmentShader = context.createShader(context.FRAGMENT_SHADER);
                context.shaderSource(fragmentShader, `
                  uniform lowp vec4 color;

                  void main() {
                    gl_FragColor = color;
                  }
                `);
                context.compileShader(fragmentShader);

                const program = context.createProgram();
                context.attachShader(program, vertexShader);
                context.attachShader(program, fragmentShader);
                context.linkProgram(program);

                const positionAttribute = context.getAttribLocation(program, 'position');

                const colorUniform = context.getUniformLocation(program, 'color');
                const projectionUniform = context.getUniformLocation(program, 'projection');

                function render() {
                  // Size the drawing surface to match the actual element (no stretch).
                  canvas.height = canvas.clientHeight;
                  canvas.width = canvas.clientWidth;

                  context.viewport(0, 0, canvas.width, canvas.height);

                  context.useProgram(program);

                  // Scale projection to maintain 1:1 ratio between height and width on canvas.
                  projectionMatrix[0] = canvas.width > canvas.height ? canvas.height / canvas.width : 1.0;
                  projectionMatrix[5] = canvas.height > canvas.width ? canvas.width / canvas.height : 1.0;
                  context.uniformMatrix4fv(projectionUniform, false, projectionMatrix);

                  const vertexSize = 2;
                  const vertexCount = positions.length / vertexSize;

                  context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
                  context.vertexAttribPointer(positionAttribute, vertexSize, context.FLOAT, false, 0, 0);
                  context.enableVertexAttribArray(positionAttribute);

                  context.uniform4fv(colorUniform, redColor);
                  context.drawArrays(context.TRIANGLE_FAN, 0, vertexCount);

                  context.uniform4fv(colorUniform, blackColor);
                  context.drawArrays(context.LINE_STRIP, 1, vertexCount - 1);
                }

                render();
                addEventListener('resize', render);
              </script>
            </body>
          </html>

          復(fù)雜度升級得相當(dāng)快!在我們渲染任何東西之前,要做很多設(shè)置。我們必須使用頂點(diǎn)列表,將圓定義為由小三角形組成的一個序列。我們還必須定義一個投影矩陣,將我們的 3D 模型(一個平面圓)投影到 2D 畫布上。然后,我們必須編寫“著色器”(用一種稱為 GLSL 的語言),在 GPU 上編譯并運(yùn)行,以確定頂點(diǎn)的位置和顏色。

          但是,額外的復(fù)雜性和較底層的 API,確實(shí)能夠讓我們更好地控制 2D 圖形繪制的性能(如果我們真的需要的話)。它還為我們提供了渲染 3D 可視化的能力,即使我們還沒有考慮過這樣的例子。

          面向聲明式的 3D 圖形 

          現(xiàn)在我們已經(jīng)了解了 WebGL,并了解了如何使用它來繪制一個圓。隨著我們進(jìn)入 3D 圖形的世界,下一個步驟就是使用它來繪制一個球體。然而,這增加了另一層次的復(fù)雜性,因?yàn)槲覀儗⒁伎?,如何使用一組頂點(diǎn)來表示球面。我們還需要添加一些燈光效果,這樣我們就可以看到一個球體的輪廓,而不是從任何角度都只能看到一個平坦的紅色圓圈。

          我們還看到,對于絕對性能并不重要的場景,SVG 等簡單而簡潔的聲明式方法可以發(fā)揮多大的作用。它們還可以讓我們使用 D3 這樣的庫,輕松地生成與數(shù)據(jù)連接起來的可視化。所以,如果我們能以類似的方式表示基于 Web 的 3D 圖形,那不是更好嗎?

          遺憾的是,目前 HTML 中的標(biāo)準(zhǔn)還不支持這個操作。但也許還有另一種方法……

          正如 Mike Bostock(D3 的創(chuàng)建者)在 POC(Proof of Concept)中所演示的,在 DOM 中定義 2D“素描”的定制化 XML 表示,并將其與一些 JavaScript 代碼結(jié)合,使用 2D 上下文將其繪制到畫布上,這相對來說會更加簡單。

          這意味著在所有主流瀏覽器上運(yùn)行的聲明式 3D 真正需要的是:
          • 基于 XML 格式的 3D 模型聲明;
          • 使用 webgl 上下文將它們繪制到畫布上的 JavaScript 代碼。

           X3D ——拼圖中缺失的這塊? 

          X3D 是表示 3D 模型的 ISO 標(biāo)準(zhǔn),是虛擬現(xiàn)實(shí)建模語言(VRML)的后續(xù)標(biāo)準(zhǔn)。它可以表示為各種編碼,包括 JSON 和 XML。后者特別適合嵌入到 HTML 文檔中。它由 Web3D 聯(lián)盟維護(hù),他們希望它能像 SVG 一樣在 HTML5 中得到原生支持。

          目前有兩種被 Web3D 聯(lián)盟認(rèn)可的 JavaScript 開源 X3D 實(shí)現(xiàn):X3DOM 和 X_ite。

          X3DOM 是由弗勞恩霍夫計(jì)算機(jī)圖形研究所 IGD(The Fraunhofer Institute for Computer Graphics Research IGD)開發(fā)的,IGD 本身也是 Web3D 聯(lián)盟的成員。為了使用它,您只需要在 HTML 頁面中包含 X3DOM JavaScript 代碼和樣式表。

          讓我們來看看用 X3D 和 X3DOM 繪制圓圈的例子:
          <html style='height: 100%; width: 100%'>
            <head>
              <script type='text/javascript' src='http://www.x3dom.org/release/x3dom-full.js'></script>
              <link rel='stylesheet' type='text/css' href='http://www.x3dom.org/release/x3dom.css'>
              <style>x3d > canvas { display: block; }</style>
            </head>
            <body style='height: 100%; width: 100%; margin: 0px'>
              <x3d style='height: 100%; width: 100%'>
                <scene>
                  <orthoviewpoint></orthoviewpoint>
                  <shape>
                    <appearance>
                      <material diffuseColor='1 0 0'></material>
                    </appearance>
                    <disk2d outerRadius='0.5'></disk2d>
                  </shape>
                  <shape>
                    <appearance>
                      <material emissiveColor='0 0 0'></material>
                    </appearance>
                    <circle2d radius='0.5'></circle2d>
                  </shape>
                </scene>
              </x3d>
            </body>
          </html>

          這比 WebGL 示例更容易接受一些!但是,如果您將 X3DOM 圓與我們的 WebGL 版本進(jìn)行比較,您會注意到圓周看起來不那么光滑。這是因?yàn)?X3DOM 庫對形狀的近似只使用了 32 條線段。而我們的 WebGL 繪制中選擇了 360 條線段。我們對要渲染什么有一個更簡單的描述,但同時也會放棄對如何渲染的一些控制。

          現(xiàn)在是時候走出我們的“平面”世界,渲染一些 3D 的東西了!如前所述,讓我們來看看一個球體的繪制:
          <html style='height: 100%; width: 100%'>
            <head>
              <script type='text/javascript' src='http://www.x3dom.org/release/x3dom-full.js'></script>
              <link rel='stylesheet' type='text/css' href='http://www.x3dom.org/release/x3dom.css'>
              <style>x3d > canvas { display: block; }</style>
            </head>
            <body style='height: 100%; width: 100%; margin: 0px'>
              <x3d style='height: 100%; width: 100%'>
                <scene>
                  <orthoviewpoint></orthoviewpoint>
                  <navigationinfo headlight='false'></navigationinfo>
                  <directionallight direction='1 -1 -1' on='true' intensity='1.0'></directionallight>
                  <shape>
                    <appearance>
                      <material diffuseColor='1 0 0'></material>
                    </appearance>
                    <sphere radius='0.5'></sphere>
                  </shape>
                </scene>
              </x3d>
            </body>
          </html>

          這又是很直接的。我們使用一個 XML 元素定義了一個球體,該元素具有單一屬性:半徑。為了看到球體的輪廓,我們還調(diào)整了光線,移除了與觀察者頭部對齊的默認(rèn)光源,并用與我們視角成一定角度的定向光替換它。這不需要為球體的表面定義一個復(fù)雜的網(wǎng)格或者編寫一個著色器來控制光照效果。

          X3DOM 還提供了開箱即用的導(dǎo)航功能,允許您旋轉(zhuǎn)、平移和縮放模型。根據(jù)您正在編寫的應(yīng)用程序的類型,還可以使用各種不同的控制方案和導(dǎo)航模式。

           結(jié)  論 

          就是這樣!我們已經(jīng)看到可以使用 X3D 和 X3DOM 庫來編寫聲明式的 3D 圖形應(yīng)用,這些圖形將在大多數(shù)現(xiàn)代 Web 瀏覽器中運(yùn)行。這是一種比直接深鉆 WebGL 更簡單的 Web 3D 圖形入門方法,代價是增加對底層繪制的控制。如果您有興趣了解這個庫的更多信息,官方 X3DOM 文檔中有一些教程。

          在我的下一篇博客文章中,我將演示如何將 X3DOM 與 D3 結(jié)合起來生成動態(tài) 3D 圖表。

          英文原文:

          https://blog.scottlogic.com/2019/08/27/declarative-3d-for-the-modern-web.html

          本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
          打開APP,閱讀全文并永久保存 查看更多類似文章
          猜你喜歡
          類似文章
          WebKit源碼分析系列之(1) html5 canvas
          微信小程序官方組件展示之畫布canvas源碼
          初探JavaScript的截屏實(shí)現(xiàn)
          html5中canvas學(xué)習(xí)筆記1
          可視化了解一下?ECharts 4.0最全技術(shù)攻略
          繪制動畫 擦除法
          更多類似文章 >>
          生活服務(wù)
          分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
          綁定賬號成功
          后續(xù)可登錄賬號暢享VIP特權(quán)!
          如果VIP功能使用有故障,
          可點(diǎn)擊這里聯(lián)系客服!

          聯(lián)系客服