webgl 著色器_如何在WebAssembly中使用WebGL著色器

webgl 著色器

by Dan Ruta

通過Dan Ruta

在WebAssembly中使用WebGL著色器 (Using WebGL shaders in WebAssembly)

WebAssembly is blazing fast for number crunching, game engines, and many other things, but nothing can quite compare to the extreme parallelization of shaders, running on the GPU.

WebAssembly正在為數字運算 , 游戲引擎和許多其他事情快速發展,但是沒有什么可以與在GPU上運行的著色器的極端并行化相比。

This is especially so if you’re looking to do some image processing. Usually, on the web, this is done through WebGL, but how would you access its APIs when using WebAssembly?

如果您要進行一些圖像處理,則尤其如此。 通常,在Web上,這是通過WebGL完成的,但是使用WebAssembly時如何訪問其API?

配置 (Setting up)

We’ll very briefly go through setting up an example project, then we’ll look at how an image can be loaded as a texture. Then, in a separate context, we’ll apply an edge detection GLSL shader to the image.

我們將簡要地設置一個示例項目,然后看一下如何將圖像作為紋理加載。 然后,在單獨的上下文中,我們將對圖像應用邊緣檢測GLSL著色器。

All the code is in a repo here, if you’d prefer to jump straight to that. Note that you have to serve your files via a server for WebAssembly to work.

如果您希望直接跳轉到此處 ,所有代碼都在此處的存儲庫中。 請注意,您必須通過服務器提供文件才能使WebAssembly正常工作。

As a prerequisite, I’m going to assume you already have your WebAssembly project set up. If not, you can check out the article here on how to do it, or just fork the repo linked above.

作為前提,我將假設您已經設置了WebAssembly項目。 如果沒有,您可以在此處查看有關操作方法的文章,也可以只分叉上面鏈接的倉庫。

For demoing the below code, I’m using a basic html file which serves only to load an image, get its imageData, and pass it to the WebAssembly code using the ccallArrays function.

為了演示以下代碼,我使用一個基本的html文件,該文件僅用于加載圖像,獲取其imageData并使用ccallArrays函數將其傳遞給WebAssembly代碼。

As for the C++ code, there is an emscripten.cpp file which manages and routes method calls to context instances created in the Context.cpp file. The Context.cpp file is structured as follows:

對于C ++代碼,有一個emscripten.cpp文件,用于管理方法調用并將其路由到Context.cpp文件中創建的上下文實例。 Context.cpp文件的結構如下:

匯編 (Compilation)

WebGL is based on and follows the OpenGL ES (Embedded Systems) spec, which is a subset of OpenGL. When compiling, emscripten will map our code to the WebGL API.

WebGL基于并遵循OpenGL ES(嵌入式系統)規范,該規范是OpenGL的子集。 編譯時,emscripten會將我們的代碼映射到WebGL API。

There are a couple of different versions we can target. OpenGL ES 2 maps to WebGL 1, whereas OpenGL ES 3 maps to WebGL 2. By default you should target WebGL 2, as it comes with some free optimizations and improvements.

我們可以定位幾個不同的版本。 OpenGL ES 2映射到WebGL 1,而OpenGL ES 3映射到WebGL2。默認情況下,您應該以WebGL 2為目標,因為它帶有一些免費的優化和改進功能 。

To do this, we must add the USE_WEBGL2=1 flag to the compilation.

為此,我們必須在編譯中添加USE_WEBGL2=1標志 。

If you are planning to use some OpenGL ES features not present in the WebGL spec, you can use the FULL_ES2=1 and/or FULL_ES3=1 flags.

如果您打算使用WebGL規范中未提供的某些OpenGL ES功能,則可以使用FULL_ES2=1和/或FULL_ES3=1標志 。

To be able to handle large textures/images, we can also add the ALLLOW_MEMORY_GROWTH=1 flag. This removes the memory limit of the WebAssembly program, at the cost of some optimizations.

為了能夠處理大的紋理/圖像,我們還可以添加ALLLOW_MEMORY_GROWTH=1標志 。 這以一些優化為代價,消除了WebAssembly程序的內存限制。

If you know ahead of time how much memory you’ll need, you can instead use the TOTAL_MEMORY=X flag, where X is the memory size.

如果您提前知道需要多少內存,則可以使用TOTAL_MEMORY=X標志,其中X是內存大小。

So we’re going to end up with something like this:

因此,我們將最終得到如下結果:

emcc -o ./dist/appWASM.js ./dev/cpp/emscripten.cpp -O3 -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1 -std=c++1z

emcc -o ./dist/appWASM.js ./dev/cpp/emscripten.cpp -O3 -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1 -std=c++1z

Finally, we need the following imports, in our code:

最后,我們需要在代碼中進行以下導入:

#include <emscripten.h>#include <string>#include <GLES2/gl2.h>#include <EGL/egl.h>extern "C" {       #include "html5.h" // emscripten module}

實作 (Implementation)

If you have previous experience with WebGL or OpenGL, then this bit may seem familiar.

如果您以前有使用WebGL或OpenGL的經驗,那么這一點可能看起來很熟悉。

When writing OpenGL, the API will not work until you create a context. This is normally done using platform specific APIs. However, the web is not platform bound, and we can instead use an API integrated into OpenGL ES.

在編寫OpenGL時,除非創建上下文,否則該API將無法工作。 通常使用平臺特定的API完成此操作。 但是,網絡不受平臺限制,因此我們可以使用集成到OpenGL ES中的API。

The majority of the legwork, however, can be more easily implemented using emscripten’s APIs in the html5.h file. The functions we’re interested in are:

但是,使用html5.h文件中的emscripten的API可以更輕松地實現大部分工作 。 我們感興趣的功能是:

  • emscripten_webgl_create_context — This will instantiate a context for the given canvas and attributes

    emscripten_webgl_create_context —這將為給定的畫布和屬性實例化上下文

  • emscripten_webgl_destroy_context — This is needed for cleaning up memory when destructing context instances

    emscripten_webgl_destroy_context —銷毀上下文實例時清理內存是必需的

  • emscripten_webgl_make_context_current — This will assign and switch which context WebGL will render to

    emscripten_webgl_make_context_current —這將分配并切換WebGL渲染到的上下文

創建上下文 (Create the context)

To start implementing, you have to first create the canvas elements in your JavaScript code. Then, when using the emscripten_webgl_create_context function, you pass the id of the canvas as the first parameter, with any configurations as the second. The emscripten_webgl_make_context_current function is used to set the new context as the one currently in use.

要開始實施,您必須首先在JavaScript代碼中創建canvas元素。 然后,在使用emscripten_webgl_create_context函數時,您將畫布的ID作為第一個參數傳遞,將任何配置作為第二個參數傳遞。 emscripten_webgl_make_context_current函數用于將新上下文設置為當前使用的上下文。

Next, the vertex shader (to specify coordinates) and the fragment shader (to calculate the colour at each pixel) are both compiled, and the program is built.

接下來,編譯頂點著色器(用于指定坐標)和片段著色器(以計算每個像素的顏色),并構建程序。

Finally, the shaders are attached to the program, which is then linked, and validated.

最后,將著色器附加到程序,然后將其鏈接并驗證。

Though that sounds like a lot, the code for this is as follows:

盡管這聽起來很多,但其代碼如下:

The shader compilation is done within the CompileShader helper function which performs the compilation, printing out any errors:

著色器編譯是在CompileShader幫助器函數中完成的,該函數執行編譯,并打印出所有錯誤:

創建著色器 (Create the shader)

The shader code for this example is minimal, and it just maps each pixel to itself, to display the image as a texture:

此示例的著色器代碼很少,它僅將每個像素映射到自身,以將圖像顯示為紋理:

You can access the canvas’ context in JavaScript in addition to the context in the C++ code, but it must be of the same type, ‘webgl2’. While defining multiple context types does nothing when just using JavaScript, if you do it before creating the webgl2 context in WebAssembly, it will throw an error when the code execution gets there.

除了C ++代碼中的上下文,您還可以在JavaScript中訪問canvas的上下文,但是它必須是相同的類型“ webgl2”。 盡管僅使用JavaScript定義多個上下文類型并沒有任何作用,但是如果在WebAssembly中創建webgl2上下文之前進行了定義,則在執行代碼時會引發錯誤。

加載紋理 (Loading the texture)

The first thing to do when applying the shader is to call the emscripten_webgl_make_context_currentfunction to make sure that we are still using the correct context, and glUseProgramto make sure we are using the correct program.

應用著色器時要做的第一件事是調用emscripten_webgl_make_context_current函數以確保我們仍在使用正確的上下文,并glUseProgram來確保我們在使用正確的程序。

Next, we get the indices of the GLSL variables (similar to getting a pointer) via theglGetAttribLocationand glGetUniformLocation functions, so we can assign our own values to those locations. The function used to do that depends on the value type.

接下來,我們通過glGetAttribLocationglGetUniformLocation獲取GLSL變量的索引(類似于獲取指針) 函數,因此我們可以將自己的值分配給這些位置。 用于執行此操作的函數取決于值類型。

For example, an integer, such as the texture location needs glUniform1i, whereas a float would need glUniform1f. This is a good resource for seeing which function you need to use.

例如,整數(例如紋理位置)需要glUniform1i ,而浮點數則需要glUniform1f 。 這是查看需要使用哪個功能的好資源 。

Next, we get the texture object via glGenTextures, assign it as the active texture, and load the imageData buffer. The vertex and indices buffers are then bound, to set the boundaries of the texture to fill the canvas.

接下來,我們通過glGenTextures獲得紋理對象,將其分配為活動紋理,并加載imageData緩沖區。 然后綁定頂點和索引緩沖區,以設置紋理的邊界以填充畫布。

Finally, we clear the existing content, define our remaining variables with data, and draw to the canvas.

最后,我們清除現有內容,使用數據定義剩余的變量,然后繪制到畫布上。

使用著色器檢測邊緣 (Detect edges using a shader)

To add another context, where the edge detection is done, we load a different fragment shader (which applies the Sobel filter), and we bind the width and height as extra variables, in the code.

為了添加另一個完成邊緣檢測的上下文,我們在代碼中加載了一個不同的片段著色器(應用了Sobel濾波器),并將寬度和高度綁定為額外的變量。

To pick between different fragment shaders, for the different contexts, we just add an if-else statement in the constructor, like so:

為了在不同的片段著色器之間進行選擇,針對不同的上下文,我們只需在構造函數中添加if-else語句,如下所示:

And to load the width and height variables, we add the following to the run function:

為了加載width和height變量,我們將以下內容添加到run函數中:

If you run into an error similar toERROR: GL_INVALID_OPERATION : glUniform1i: wrong uniform function for type, then there’s a mismatched assignment function for the given variable.

如果遇到類似于ERROR: GL_INVALID_OPERATION : glUniform1i: wrong uniform function for type ,則給定變量的賦值函數不匹配。

One thing to look out for when sending the imageData, is to use the correct heap, unsigned integer (the Uint8Array typed array). You can learn more about those here, but if you’re using the ccallArray function, set the ‘heapIn’ config to “HEAPU8”, as seen above.

發送imageData時要注意的一件事是使用正確的堆(無符號整數)(Uint8Array類型的數組)。 您可以在此處了解更多信息,但是,如果您使用的是ccallArray函數,則將“ heapIn ”配置設置為“ HEAPU8 ”,如上所示。

If the type is not correct, the texture will still load, but you’re going to be seeing strange renderings, like these:

如果類型不正確,紋理仍會加載,但是您將看到奇怪的渲染,如下所示:

結論 (Conclusion)

We’ve gone through a mini “Hello World!”-style project to show how to load textures and apply GLSL shaders to them in WebAssembly. The complete code is hosted on GitHub here, for further reference.

我們已經完成了一個迷你的“ Hello World!”風格的項目,以展示如何加載紋理并將GLSL著色器應用到WebAssembly中。 完整的代碼是在GitHub托管在這里 ,以備將來參考。

For a real project, you may want to add some additional error handling. I omitted it here, for clarity.

對于真實項目,您可能需要添加一些其他錯誤處理。 為了清楚起見,我在這里省略了它。

It may also be more efficient (in the above example) to share data such as the imageData texture between contexts. You can read more about this and more here.

(在上述示例中)在上下文之間共享數據(例如imageData紋理)也可能更為有效。 您可以在此處有關此內容的信息 。

For some further reading, you can check out this link for common mistakes, or you can look through some demo projects in emscripten’s glbook folder, on GitHub.

若要進一步閱讀,可以查看此鏈接以查找常見錯誤,也可以在GitHub上emscripten的glbook文件夾中瀏覽一些演示項目。

To see WebGL being used in a WebAssembly project, you can check out the dev branch on jsNet, a web based deep learning framework, where I’ll be working on moving heavier computations onto shaders, over the next few weeks (support for WebGL compute shaders via OpenGL ES 3.1 can’t come soon enough ? ).

要查看WebGL在WebAssembly項目中的使用情況,您可以在jsNet上檢查一下dev分支,jsNet是一個基于Web的深度學習框架,在接下來的幾周中,我將在其中致力于將較重的計算轉移到著色器上(支持WebGL計算通過OpenGL ES 3.1創建的著色器還不夠快嗎?)。

Update

更新資料

To see what GPU compute using shaders would look like in WebAssembly, you can check out the repo for GPGPU, a small library I’m working on, with both JavaScript and WebAssembly versions.

若要查看在WebAssembly中使用著色器進行GPU計算的外觀,您可以檢出GPGPU (我正在使用的一個小型庫,包含JavaScript和WebAssembly版本)的存儲庫。

翻譯自: https://www.freecodecamp.org/news/how-to-use-webgl-shaders-in-webassembly-1e6c5effc813/

webgl 著色器

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394788.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394788.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394788.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【洛谷P1966】火柴排隊

兩列排序后將編號一一對應 歸并排序求逆序對 &#xff08;每一次交換就去掉一個逆序對&#xff09; 1 #include<cstdio>2 #include<cstring>3 #include<algorithm>4 #define ll long long5 using namespace std;6 const int N100100;7 const ll P99999997;8 …

python字符串補空格輸出_Python去除空格,Python中常見字符串去除空格的方法總結...

今天小編就為大家分享一篇關于Python去除字符串前后空格的幾種方法&#xff0c;小編覺得內容挺不錯的&#xff0c;現在分享給大家&#xff0c;具有很好的參考價值&#xff0c;需要的朋友一起跟隨小編來看看吧&#xff1a; Python去除空格方法一&#xff1a; strip()方法&#x…

Alan Walker MV 合輯01 by defender

Alan Walker MV合輯 出來啦&#xff01; 百度網盤下載地址&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/10WSool70XBe_8tJOae8V-w 提取碼&#xff1a;uckq 地址查看Microsoft Onedrive Download Address:  BE DELETED Google Drive Download Address&#xff1a; …

scanf函數具體解釋與緩沖區

1.基本信息 函數原型&#xff1a; int scanf( char *format, args, ...); 函數返回值&#xff1a; 讀入并賦給args的數據個數。遇到文件結束返回EOF&#xff0c;出錯返回0。 函數功能&#xff1a; scanf函數是格式化輸入函數&#xff0c;它從標準輸入設備(鍵盤)讀取輸入的信息。…

linux中win文件轉為unix,如何將文本文件從Windows轉換為Unix

從Unix轉換到Windows時&#xff0c;我得到正確的輸出;但是&#xff0c;從Windows到Unix時&#xff0c;我得到了一些奇怪的輸出。我認為我必須允許的是刪除回車\ r。雖然這不起作用。當我運行代碼后打開文本文件時&#xff0c;我得到了一些奇怪的結果&#xff0c;第一行是正確的…

程序員偽造一年工作經驗_試火—如何偽造程序員

程序員偽造一年工作經驗2017年9月6日 (6 September 2017) Sweat is running down my face. I’m staring down a blank sublime text document. What on earth am I doing? My hands are resting above the keyboard of my MacBook pro.汗水順著我的臉。 我盯著一個空白的崇高…

在unity中設置多種怪物數據_Unity可編程渲染管線(SRP)系列(三)——光照(單通道 正向渲染)...

本文重點:1、漫反射著色2、支持方向光、點光源和聚光燈3、每幀允許16個可見光源4、每個對象最多計算四個像素光和四個頂點光這是涵蓋Unity可編寫腳本的渲染管線的教程系列的第三部分。這次&#xff0c;我們將通過一個Drawcall為每個對象最多著色8個燈光來增加對漫反射光照的支持…

Java內部類的定義和使用

為什么要用到內部類&#xff1a; 在java開發學習中我們經常會碰到內部類。內部類又有很多的優勢&#xff1a;首先舉一個簡單的例子&#xff0c;如果你想實現一個接口&#xff0c;但是這個接口中的一個方法和你構想的這個類中的一個方法名稱參數相同&#xff0c;你應該怎么辦&am…

蛋清打發奶油狀

在做蛋糕、冰淇凌、面包之類的時候往往都需要奶油狀蛋清&#xff0c;讓蛋糕、面包更蓬松&#xff0c;冰激凌也可以使用其當做奶油來用。用料 雞蛋4個 根據用量選擇鹽(只做冰激凌用奶油放)5g(根據蛋量)白醋(可以不放&#xff0c;根據喜好)5g(根據蛋量)白砂糖40g(分三次放)根據…

react構建_您應該了解的有關React的一切:開始構建所需的基礎知識

react構建by Scott Domes由斯科特多姆斯(Scott Domes) 您應該了解的有關React的一切&#xff1a;開始構建所需的基礎知識 (Everything You Should Know About React: The Basics You Need to Start Building) Are you curious about React and haven’t had the chance to lea…

榮新linux培訓,51CTO博客-專業IT技術博客創作平臺-技術成就夢想

切換用戶 su - root文件夾管理 mkdir(新建文件夾) rmdir(刪除空目錄)文件管理 touch(新建文件) rm(刪除文件)rm -rf(刪除文件夾) cat(查詢文件)文件文件夾 mv(剪切文件) cp(復制文件)默認拷貝文件&#xff0c;cp -r 就可以拷貝文件夾啦批量建文件 touch /root/tes…

Educational Codeforces Round 33 (Rated for Div. 2) E. Counting Arrays

題目鏈接 題意&#xff1a;給你兩個數x,yx,yx,y,讓你構造一些長為yyy的數列&#xff0c;讓這個數列的累乘為xxx&#xff0c;輸出方案數。 思路:考慮對xxx進行質因數分解&#xff0c;設某個質因子PiP_iPi?的的冪為kkk,則這個質因子的貢獻就相當于把kkk個PiP_iPi?放到yyy個盒子…

《面向對象分析與設計》一第2章 什么是面向對象分析

第2章 什么是面向對象分析 面向對象分析&#xff08;ObjectOriented Analysis&#xff0c;OOA&#xff09;&#xff0c;就是運用面向對象方法進行系統分析。它是軟件生命周期的一個階段&#xff0c;具有一般分析方法所共同具有的內容、目標及策略。但是OOA強調運用面向對象方…

hql可以使用distinct嗎_輸送食品可以使用白色PVC輸送帶嗎?

食品&#xff0c;是給人們吃到肚子里的&#xff0c;因此不管在加工環節、制造環節還是其他環節&#xff0c;都需要做好食品的安全問題。根據不同的食品&#xff0c;其制造的環境也不同&#xff0c;所使用到的食品輸送帶的材質也是不一樣的&#xff0c;這些是需要根據輸送的食品…

htc one m7 linux驅動,HTC One M7官方RUU固件包(可救磚)

在網上找了找關于HTC One M7 (801e)的官方ruu固件包還不多&#xff0c;找了一些&#xff0c;不過有些不能下載&#xff0c;在這里整理了幾款可以下載的官方ruu包&#xff0c;這些包都是官方原版的&#xff0c;都是支持線刷的&#xff0c;大家可以下載下來備用了&#xff0c;也可…

emoji .png_根據我對3.5GB聊天記錄的分析,Emoji開發人員使用最多

emoji .pngby Evaristo Caraballo通過Evaristo Caraballo 根據我對3.5GB聊天記錄的分析&#xff0c;Emoji開發人員使用最多 (The Emoji developers use most — based on my analysis of 3.5GB of chat logs) Emoji have drastically changed the way we communicate in socia…

forward和redirect的區別

1.從地址欄顯示來說forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器.瀏覽器根本不知道服務器發送的內容從哪里來的,所以它的地址欄還是原來的地址.redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求…

CF662C Binary Table(FWT)

[Luogu-CF662C] FWT_xor 題目描述 有一個 \(n\) 行 \(m\) 列的表格&#xff0c;每個元素都是 $0/1 $&#xff0c;每次操作可以選擇一行或一列&#xff0c;把 \(0/1\) 翻轉&#xff0c;即把 \(0\) 換為 \(1\) &#xff0c;把 \(1\) 換為 \(0\) 。請問經過若干次操作后&#xff0…

c語言fmin最小公倍數,matlab小函數

8種機械鍵盤軸體對比本人程序員&#xff0c;要買一個寫代碼的鍵盤&#xff0c;請問紅軸和茶軸怎么選&#xff1f;(記得按字母序索引)矩陣向量化操作A(:)拉成一個向量 ($a_{11},a_{21},…$)&#xff0c;注意先列后行repmat用途&#xff1a;創建由小型矩陣重復組合成的矩陣&#…

spring管理的類如何調用非spring管理的類

spring管理的類如何調用非spring管理的類. 就是使用一個spring提供的感知概念,在容器啟動的時候,注入上下文即可. 下面是一個工具類. 1 import org.springframework.beans.BeansException;2 import org.springframework.context.ApplicationContext;3 import org.springframewo…