整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          WebGL著色器簡明教程「2022」

          WebGL著色器簡明教程「2022」

          本文中,我們將了解如何使用超過 150 行代碼將圖像渲染到頁面!我知道可以只使用一個<img>標簽并完成它。但這樣做是一個很好的練習,因為它迫使我們引入許多重要的 WebGL 概念。

          我最近在一個需要使用 WebGL 的項目上工作。我試圖在瀏覽器中的地圖上渲染數千個多邊形,但結果證明 GeoJSON 太慢了。為了加快速度,我想盡可能降低到最低水平,并使用 WebGL 和著色器實際編寫可以直接在 GPU 上運行的代碼。我一直想了解著色器,但一直沒有機會,所以這是一個在解決非常具體的技術挑戰的同時學習新東西的好機會。

          起初,我很難弄清楚我需要做什么。復制和粘貼示例代碼通常不起作用,而且我并沒有真正了解如何從示例轉到我需要的自定義解決方案。然而,一旦我完全理解了這一切是如何結合在一起的,它突然在我腦海中響起,結果證明解決方案非常簡單。最困難的部分是圍繞一些概念思考。所以,我想寫一篇文章解釋我學到了什么,幫助你理解這些概念,并希望讓你更容易編寫你的第一個著色器。

          以下是我們將在本文中執行的操作:

          1. 我們將編寫兩個著色器程序,告訴 GPU 如何將坐標列表轉換為屏幕上的彩色三角形。
          2. 我們將向著色器傳遞一個坐標列表,告訴它在屏幕的何處繪制三角形。
          3. 我們將創建一個“圖像紋理”,將圖像上傳到 GPU,以便它可以將其繪制到三角形上。
          4. 我們將給著色器一個不同的坐標列表,以便它知道每個三角形內的圖像像素。

          希望你可以使用這些概念作為起點,使用 WebGL 做一些非常酷且有用的事情。

          即使你最終使用庫來幫助編寫 WebGL 代碼,我發現了解幕后的原始 API 調用對于了解實際發生的情況很有用,尤其是在出現問題時。

          1、WebGL 入門

          要在瀏覽器中使用 WebGL,你需要向<canvas>頁面添加標簽。使用畫布,你可以使用 2D Canvas API 進行繪制,也可以選擇使用 3D WebGL API版本 1 或 2。我實際上并不了解 WebGL 1 和 2 之間的區別,但我會希望有一天能了解更多。我將在這里討論的代碼和概念適用于這兩個版本。

          如果想讓你的畫布填充視口,你可以從這個簡單的 HTML 開始:

          <!doctype html>
          <html lang="en">
              <meta charset="UTF-8">
              <title>WebGL</title>
              <style>
                  html, body, canvas {
                      width: 100%;
                      height: 100%;
                      border: 0;
                      padding: 0;
                      margin: 0;
                      position: absolute;
                  }
              </style>
              <body>
                  <canvas></canvas>
                  <script></script>
              </body>
          </html>

          這會給你一個空白的、白色的、無用的頁面。你需要一些 JavaScript 來實現它。在<script>標簽內,添加這些行以訪問畫布的 WebGL API:

          const canvas=document.querySelector('canvas');
          const gl=canvas.getContext('webgl');

          2、編寫第一個 WebGL 著色器程序

          WebGL 基于 OpenGL,并使用相同的著色器語言。沒錯,著色器程序(Shader)是用他們自己的語言 GLSL 編寫的,它代表圖形庫著色器語言。

          GLSL 讓我想起了 C 或 JavaScript,但它有自己的特點,局限性非常大,但也非常強大。很酷的一點是,它直接在 GPU 上而不是在 CPU 上運行。因此它可以非常快速地完成普通 CPU 程序無法完成的事情。它針對使用向量和矩陣處理數學運算進行了優化。

          我們需要兩種類型的著色器:頂點(Vertex)著色器和片段(Fragment)著色器。頂點著色器可以進行計算以確定每個頂點(三角形的角)的位置。片段著色器計算出如何為三角形內的每個片段(像素)著色。

          這兩個著色器相似,但在不同的時間做不同的事情。頂點著色器首先運行,以確定每個三角形的去向,然后它可以將一些信息傳遞給片段著色器,因此片段著色器可以計算出如何繪制每個三角形。

          3、你好,頂點著色器的世界!

          這是一個基本的頂點著色器,它將接收一個帶有 x,y 坐標的向量。向量基本上只是一個具有固定長度的數組。vec2是有 2 個數字的數組,vec4是有 4 個數字的數組。所以,這個程序將采用一個全局“屬性”變量,一個名為“points”的 vec2(這是我編的一個名字)。

          然后它會告訴 GPU,這正是頂點將要去的地方,方法是將它分配給另一個內置于 GLSL 中的名為gl_Position 的變量。

          它將針對三角形的每個頂點運行,并且每次points都有不同的 x,y 值。稍后你將看到我們如何定義和傳遞這些坐標。

          這是我們的第一個“你好,世界!” 頂點著色器程序:

          attribute vec2 points;
          
          void main(void) {
              gl_Position=vec4(points, 0.0, 1.0);
          }

          此處不涉及任何計算,只是我們需要將 vec2 轉換為 vec4。前兩個數字是 x 和 y,第三個是 z,我們只需將其設置為 0.0,因為我們正在繪制二維圖片,我們不需要擔心第三維。我不知道第四個值是什么意思,但我們只是將其設置為 1.0。根據我的閱讀,我認為這與使矩陣數學更容易有關。

          我喜歡 GLSL 中的這一點,向量是一種基本數據類型,你可以使用其他向量輕松創建向量。我們可以這樣寫上面的行:

          gl_Position=vec4(points[0], points[1], 0.0, 1.0);

          但相反,我們能夠使用快捷方式,只需將 vec2 點作為第一個參數傳入,GLSL 就知道該怎么做。它讓我想起了在 JavaScript 中使用擴展運算符:

          // javascript
          gl_Position=[...points, 0.0, 1.0];

          因此,如果角形角之一的 x 為 0.2,y 為 0.3,我們的代碼將有效地執行以下操作:

          gl_Position=vec4(0.2, 0.3, 0.0, 1.0);

          但是我們不能像這樣將 x 和 y 坐標硬編碼到我們的程序中,否則所有的三角形都只是屏幕上的一個點。我們使用屬性向量(Attribute)代替,以便每個角(或頂點)可以位于不同的位置。

          4、使用片段著色器

          頂點著色器為每個三角形的每個角運行一次,而片段著色器為每個三角形內的每個彩色像素運行一次。

          頂點著色器使用名為 gl_Position的全局 vec4 變量定義每個頂點的位置,而片段著色器通過使用名為gl_FragColor 的局 vec4 變量定義每個像素的顏色。以下是我們如何用紅色像素填充所有三角形:

          void main() {
              gl_FragColor=vec4(1.0, 0.0, 0.0, 1.0);
          }

          這里顏色向量是 RGBA,因此紅色、綠色、藍色和 alpha 中的每一個都是介于 0 和 1 之間的數字。所以上面的例子只是將每個片段或像素設置為完全不透明的亮紅色。

          5、訪問著色器中的圖像

          你通常不會用純色填充所有三角形,因此,我們希望片段著色器引用圖像(或“紋理”)并為三角形內的每個像素提取正確的顏色。

          我們需要使用顏色信息訪問紋理,以及一些告訴我們圖像如何映射到形狀上的“紋理坐標”。

          首先,我們將修改頂點著色器以訪問坐標并將它們傳遞給片段著色器:

          attribute vec2 points;
          attribute vec2 texture_coordinate;
          
          varying highp vec2 v_texture_coordinate;
          
          void main(void) {
              gl_Position=vec4(points, 0.0, 1.0);
              v_texture_coordinate=texture_coordinate;
          }

          如果你像我一樣,可能會擔心會需要各種瘋狂的三角函數,但別擔心 - 事實證明這是最簡單的部分,這要歸功于 GPU 的魔力。

          我們為每個頂點獲取一個紋理坐標,然后將其傳遞給變量中的片段著色器,該varying變量將“插入”每個片段或像素的坐標。這本質上是兩個維度的百分比,因此對于三角形內的任何特定像素,我們將準確知道要選擇圖像的哪個像素。

          圖像存儲在一個名為 sampler的二維采樣器變量中。我們從頂點著色器接收varying紋理坐標,并使用GLSL 函數texture2D從紋理中采樣適當的單個像素。

          這聽起來很復雜,但由于 GPU 的魔力,它變得非常簡單。我們需要做任何數學運算的唯一部分是將三角形的每個頂點坐標與圖像的坐標相關聯,稍后我們將看到它變得非常簡單。

          precision highp float;
          varying highp vec2 v_texture_coordinate;
          uniform sampler2D sampler;
          
          void main() {
              gl_FragColor=texture2D(sampler, v_texture_coordinate);
          }

          6、編譯著色器程序

          我們剛剛研究了如何使用 GLSL 編寫兩個不同的著色器,但我們還沒有討論過如何在 JavaScript 中做到這一點。只需要將這些 GLSL 著色器轉換為 JavaScript 字符串,然后我們就可以使用 WebGL API 編譯它們并將它們放在 GPU 上。

          有些人喜歡把shader源代碼直接放在HTML中使用<script type="x-shader/x-vertex">之類的script標簽,然后用.innerText把代碼拉出來。你還可以將著色器放入單獨的文本文件中并使用fetch 加載 。具體怎么做取決于你。

          我發現直接在 JavaScript 中使用模板字符串編寫著色器源代碼是最簡單的。看起來是這樣的:

          const vertexShaderSource=`
              attribute vec2 points;
              attribute vec2 texture_coordinate;
          
              varying highp vec2 v_texture_coordinate;
          
              void main(void) {
                  gl_Position=vec4(points, 0.0, 1.0);
                  v_texture_coordinate=texture_coordinate;
              }
          `;
          
          const fragmentShaderSource=`
              precision highp float;
              varying highp vec2 v_texture_coordinate;
              uniform sampler2D sampler;
          
              void main() {
                  gl_FragColor=texture2D(sampler, v_texture_coordinate);
              }
          `;

          接下來,我們需要創建一個 GL“程序”并將這兩個不同的著色器添加到其中,如下所示:

          // create a program (which we'll access later)
          const program=gl.createProgram();
          
          // create a new vertex shader and a fragment shader
          const vertexShader=gl.createShader(gl.VERTEX_SHADER);
          const fragmentShader=gl.createShader(gl.FRAGMENT_SHADER);
          
          // specify the source code for the shaders using those strings
          gl.shaderSource(vertexShader, vertexShaderSource);
          gl.shaderSource(fragmentShader, fragmentShaderSource);
          
          // compile the shaders
          gl.compileShader(vertexShader);
          gl.compileShader(fragmentShader);
          
          // attach the two shaders to the program
          gl.attachShader(program, vertexShader);
          gl.attachShader(program, fragmentShader);

          最后,我們必須告訴 GL 鏈接并使用我們剛剛創建的程序。請注意,一次只能使用一個程序:

          gl.linkProgram(program);
          gl.useProgram(program);

          如果程序出現問題,我們應該將錯誤記錄到控制臺。否則,它將默默地失敗:

          if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
              console.error(gl.getProgramInfoLog(program));
          }

          如您所見,WebGL API 非常冗長。但是,如果仔細查看這些代碼,會發現它們并沒有做任何太令人驚訝的事情。這些代碼塊非常適合復制和粘貼,因為很難記住它們,而且它們很少更改。你可能需要更改的唯一部分是模板字符串中的著色器源代碼。

          7、繪制三角形

          現在我們的程序已經全部連接好,是時候給它一些坐標并讓它在屏幕上繪制一些三角形了!

          首先,我們需要了解 WebGL 的默認坐標系。它與屏幕上的常規像素坐標系完全不同。在 WebGL 中,畫布的中心是 0,0,左上角是 -1,-1,右下角是 1,1。

          如果我們想渲染一張照片,需要一個矩形。但是 WebGL 只知道如何繪制三角形。那么我們如何使用三角形繪制一個矩形呢?我們可以使用兩個三角形來創建一個矩形。我們將有一個三角形覆蓋左上角,另一個覆蓋右下角,如下所示:

          要繪制三角形,需要指定每個三角形三個角的坐標。讓我們創建一個數字數組。兩個三角形的 x 和 y 坐標都將在一個數組中,如下所示:

          const points=[
              // first triangle
              // top left
              -1, -1,
          
              // top right
              1, -1,
          
              // bottom left
              -1, 1,
          
              // second triangle
              // bottom right
              1, 1,
          
              // top right
              1, -1,
          
              // bottom left
              -1, 1,
          ];

          要將數字列表傳遞到我們的著色器程序中,我們必須創建一個“緩沖區”,然后將一個數組加載到緩沖區中,然后告訴 WebGL 將緩沖區中的數據用于我們的著色器程序中的屬性。

          我們不能只將 JavaScript 數組加載到 GPU 中,它必須是嚴格類型的。所以我們把它包裝在一個Float32Array 中。 我們也可以使用整數或任何對我們的數據有意義的類型,但對于坐標,浮點數最有意義。

          // create a buffer
          const pointsBuffer=gl.createBuffer();
          
          // activate the buffer, and specify that it contains an array
          gl.bindBuffer(gl.ARRAY_BUFFER, pointsBuffer);
          
          // upload the points array to the active buffer
          // gl.STATIC_DRAW tells the GPU this data won't change
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW);

          請記住,我在著色器程序的頂部創建了一個名為“points”的屬性,帶有attribute vec2 points;? 現在我們的數據在緩沖區中,并且緩沖區處于活動狀態,我們可以用需要的坐標填充那個“points”屬性:

          // get the location of our "points" attribute in our shader program
          const pointsLocation=gl.getAttribLocation(program, 'points');
          
          // pull out pairs of float numbers from the active buffer
          // each pair is a vertex that will be available in our vertex shader
          gl.vertexAttribPointer(pointsLocation, 2, gl.FLOAT, false, 0, 0);
          
          // enable the attribute in the program
          gl.enableVertexAttribArray(pointsLocation);

          8、將圖像加載到紋理中

          在 WebGL 中,紋理是一種在網格中提供大量數據的方法,這些數據可用于將像素繪制到形狀上。圖像是一個明顯的例子,它們是沿行和列的紅色、藍色、綠色和 alpha 值的網格。但是,你可以將紋理用于根本不是圖像的事物。就像計算機中的所有信息一樣,它最終只是數字列表。

          由于我們在瀏覽器中,我們可以使用常規的 JavaScript 代碼來加載圖像。加載圖像后,我們將使用它來填充紋理。

          在我們執行任何 WebGL 代碼之前先加載圖像可能是最簡單的,然后在圖像加載后運行整個 WebGL 初始化的東西,所以我們不需要等待任何東西,像這樣:

          const img=new Image();
          img.src='photo.jpg';
          img.onload=()=> {
              // assume this runs all the code we've been writing so far
              initializeWebGLStuff();
          };

          現在我們的圖像已經加載,我們可以創建一個紋理并將圖像數據上傳到其中。

          // create a new texture
          const texture=gl.createTexture();
          
          // specify that our texture is 2-dimensional
          gl.bindTexture(gl.TEXTURE_2D, texture);
          
          // upload the 2D image (img) and specify that it contains RGBA data
          gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);

          由于我們的圖像可能不是2的N次冪,因此還必須告訴 WebGL 在放大或縮小圖像時如何選擇要繪制的像素,否則會拋出錯誤。

          // tell WebGL how to choose pixels when drawing our non-square image
          gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
          gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
          gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
          
          // bind this texture to texture #0
          gl.activeTexture(gl.TEXTURE0);
          gl.bindTexture(gl.TEXTURE_2D, texture);

          最后,我們想在著色器程序中訪問這個紋理。我們用代碼uniform sampler2D sampler;定義了一個二維 uniform變量,告訴 GPU 應該使用我們的新紋理。

          // use the texture for the uniform in our program called "sampler",
          gl.uniform1i(gl.getUniformLocation(program, 'sampler'), 0);

          9、使用紋理坐標繪制帶有圖像的三角形

          我們快完成了!下一步非常重要。我們需要告訴著色器我們的圖像應該如何繪制到三角形上。我們希望將圖像的左上角繪制在左上三角形的左上角。等等。

          圖像紋理的坐標系與我們使用的三角形不同,所以我們必須考慮一下,不幸的是不能只使用完全相同的坐標。以下是它們的不同之處:

          紋理坐標應該與我們的三角形頂點坐標的順序完全相同,因為這就是它們在頂點著色器中一起顯示的方式。當我們的頂點著色器為每個頂點運行時,它還能夠訪問每個紋理坐標,并將其作為varying變量傳遞給片段著色器。

          我們將使用與上傳三角坐標數組幾乎相同的代碼,只是現在我們將把它與名為“texture_coordinate”的屬性相關聯。

          const textureCoordinates=[
              // first triangle
              // top left
              0, 1,
          
              // top right
              1, 1,
          
              // bottom left
              0, 0,
          
              // second triangle
              // bottom right
              1, 0,
          
              // top right
              1, 1,
          
              // bottom left
              0, 0,
          ];
          
          // same stuff we did earlier, but passing different numbers
          const textureCoordinateBuffer=gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordinateBuffer);
          gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
          
          // and associating it with a different attribute
          const textureCoordinateLocation=gl.getAttribLocation(program, 'texture_coordinate');
          gl.vertexAttribPointer(textureCoordinateLocation, 2, gl.FLOAT, false, 0, 0);
          gl.enableVertexAttribArray(textureCoordinateLocation);

          10、最后一步!繪制三角形

          現在我們已經將著色器、所有坐標和圖像加載到 GPU 中,我們已經準備好實際運行著色器程序并讓它將我們的圖像繪制到畫布上。

          為此,我們只需要一行代碼:

          gl.drawArrays(gl.TRIANGLES, 0, 6);

          這告訴 WebGL 使用我們的點數組和紋理坐標數組來繪制三角形。這里的數字6意味著我們數組中的每 6 個數字定義一個三角形。每個三角形都有 3 個角,每個角(或頂點)都有一個 x 和 y 坐標。

          11、結束語

          使用 GPU 繪制圖像需要學習許多不同的東西,我發現這存在一個陡峭的學習曲線,但是一旦了解著色器的實際作用、紋理是什么、如何為著色器提供一些數字列表以及它們如何組合在一起,它就開始變得有意義了,并且我意識到這一切有多么強大。

          我希望你已經能夠看到一些簡單和強大的功能。我知道 WebGL API 可能非常冗長,而且我仍然不能完全確定每個函數的作用,這對我來說絕對是一種新的編程范式,因為 GPU 與 CPU 如此不同,但這就是它如此令人興奮的原因。


          原文鏈接:http://www.bimant.com/blog/webgl-shader-crash-course/

          薦12個曾經讓我眼界大開的網站,每一個都像發現了新大陸!要么超級好玩,要么超級實用(能幫你省錢的那種)!相信總有一個你看了就會立馬愛上!


          1:正版中國 —— 以較低的價格買到正版軟件

          網址:https://getitfree.cn/

          正版中國是一個分享正版軟件限時免費信息的網站。像常見的Office軟件給的折扣力度都很大,有時候直接到了2折,真的能省不少錢!


          從網站的分類信息中我們可以看到,幾乎包含了不同系統的軟件產品,比如PC、Mac、iOS、Android、UMP……



          2:考拉新媒體導航 —— 新媒體人必備的好網站!

          網址:https://www.kaolamedia.com/

          作為新媒體人,無論是做內容運營、活動運營,還是用戶運營,工作中經常需要用到不少網站。

          前幾天,我發現了一個超贊的新媒體導航網站,里面搜集了100+個新媒體人常用的效率工具!!

          涵蓋:配圖網站、自媒體網站、公眾號輔助工具、數據分析工具、裂變工具、社群運營工具、表單工具、創意H5工具、小程序工具、視頻剪輯、效率管理等…

          簡直太用心了!我覺得自己可以清理一波收藏夾了……


          3:美麗化學 —— 可能會讓你瘋狂地愛上化學

          網址:http://www.envisioningchemistry.cn

          說到化學,很多人的反應就是充滿了危險,或者是難聞的氣味。但也有很多人就是喜歡化學反應的奇妙,甚至還專門建立了一個網站,從微觀的角度展示神奇的化學世界。


          比如這個硝酸鉀和氯化銨的結晶過程 ,在微觀世界實在是太美了!

          還有初中學化學時非常熟悉的沉淀反應:


          還有這個雙氧水的催化反應實驗:


          【美麗化學】的項目發起人是梁琰,本碩畢業于清華大學化學系,他曾在一席的舞臺上分享過自己這個項目背后的故事,大家感興趣的話也可以去看一看。

          一席 | 演講

          4:Office-converter —— 可能是最好用的在線格式轉換網站

          網址:https://cn.office-converter.com/說到格式轉換,相信很多人都是頭疼不已,比如PDF轉Word?flv格式的視頻如何轉換成mp4格式?使用這個萬能的在線格式轉換網站就好啦~

          無須下載專門的軟件,在線就可以免費轉換各種類型的文件格式,包括:文檔、視頻、音頻、圖片、電子書等。






          5:AlteredQualia —— 各種好玩的神器~

          網址:https://alteredqualia.com/

          這是一位WebGL大神的個人主頁,里面有各種好玩的工具。

          什么是WebGL?簡單來說,就是在無需安裝任何硬件的情況下,我們僅通過瀏覽器就能查看各種3D影像的技術。

          部分截圖

          每一個都非常有意思。

          比如下面的星球放射線工具 。截下來作為PPT的背景圖片也是非常好的素材

          https://alteredqualia.com/three/examples/lines_sphere_gl.html

          又比如這個會隨著鼠標移動同步轉動眼球的愛因斯坦

          https://alteredqualia.com/xg/examples/albert.html

          還有這個有點魔性的江南style舞蹈

          https://alteredqualia.com/three/examples/webgl_psy.html

          這里就只為大家展示這3個小工具,如果你喜歡,不妨把大神的每個WebGL工具都玩一遍~


          6:求字體網 —— 輕松識別不認識的字體

          網址:http://new.qiuziti.com/

          遇到喜歡但又不認識的字體怎么辦?別著急,給文字拍張照片,或截個圖,上傳到【求字體網】,就可以識別出來了

          比如這是@這是三金 做的一張讀書筆記PPT


          我想知道標題用了什么字體,就可以這么做:

          Step 1:截取標題字體部分

          頁面太復雜的話,網站識別效果較差,所以我們只截取標題區域。

          Step 2:上傳圖片

          Step 3:選中清晰且有特點的單字

          根據識別結果,發現「方正喵嗚體」最符合。另外,發現沒?網站還貼心地給出了字體的商用情況以及官方下載鏈接,可以說很貼心了

          類似網站:識字體網


          7:51PPT模板 —— 集結各路PPT大神的模板作品

          網址:http://www.51pptmoban.com/ppt/

          性質:全部免費;質量高

          這個網站是由個人運營的,站長會向每個PPT作品的原作者去申請授權,然后整理發布。該網站不僅僅提供免費的PPT模板,還有很多PPT教程、PPT圖表等資源!


          下載方法:

          ? 選擇你想要的模板

          ? 往下拉,找到「下載地址」按鈕


          ? 最后點擊「本地下載」。這樣模板就下好了,全程無須注冊~


          來看一下模板的質量:




          8:OfficePlus —— 微軟官方出品的免費模板下載網站

          網址:http://www.officeplus.cn/Template/Home.shtml性質:全部免費;質量高這是微軟Office官方網站,這個網站吧不光有PPT模板,還有Word、Excel模板,甚至還有很多高質量的圖片。


          里面的模板質量有多高呢?我放兩份給大家看看:



          直接秒殺很多付費模板呀!這樣的PPT模板OfficePlus上還有很多。

          另外呢,Office既然作為微軟自家孩子,自然有特殊福利。假如你的軟件為Office365,那么在新建PPT的時候,直接搜索關鍵詞,比如 “ 報告 ”,是可以直接搜索到OfficePLUS上的模板。



          9:OpenStax CNX —— 免費分享教科書的網站

          網址:https://cnx.org/

          看到滿屏的英文是不是慌啦?其實只要利用網頁的翻譯功能翻成中文就好。


          這是萊斯大學(Rice University) 的巴拉紐克博士( Dr. Richard Baraniuk)在1999年創辦的一個網站,分享的書籍涉及設計、藝術、商業、數學計算等領域。


          所有書籍會提供詳細的目錄 ↓


          下載的時候也無須注冊,而且免費。可以說是非常良心了。


          所以,如果你想找國外的教科書,不妨先來這個網站試試。


          10:tunefind —— 快速找到熱門影視劇的BGM!

          網址:https://www.tunefind.com/movie/zootopia-2016

          不知道你有沒有這樣的經歷?看到一部好看的片子(電影、美劇、綜藝都行)或者一款好玩的游戲,經常被里面的BGM吸引,每次為了找到歌名,恨不得把整個百度掀翻。如果是英文歌曲,完全不用這么麻煩,因為有個網站已經幫你整理好了!它就是【tunefind】。


          以最近非常火的《權利的游戲》(Game of Thrones)為例,看一下能搜到什么樣的結果?可以發現,它會按照不同的Season進行分類:


          我們點進最新的《Season 8 》看一下,發現它又細分為了不同的集數,而且可以試聽。一旦知道歌名,歌曲下載的事情不就很輕松了嗎?



          11:書格 —— 可能是最好用的古籍資料下載網站

          網址:https://www.shuge.org/

          【書格】是一個自由開放的在線古籍圖書館,致力于開放式分享、介紹、推薦有價值的古籍善本。分享內容限定為公共版權領域的書籍(參照標準伯爾尼公約)。


          該網站最大限度地還原書籍品貌、內容,借此計劃讓大家自由、免費地欣賞到那些難以現世的書籍,讓大家能從中感受到人類文明進程。

          使用方法:

          • 搜索關鍵詞,找到書籍后可直接下載使用,無需注冊。




          12:Firefox Send —— 火狐出品的臨時網盤

          網址:https://send.firefox.com/

          這是火狐(Firefox)旗下的一個臨時網盤,Send 允許上傳和加密很大的文件(登陸后最多 可上傳2.5GB)來分享到網上。如果你想給同事或朋友分享什么資料,但是又希望分享完后不留在自己電腦或網盤上,就可以試試這個網站。


          以 Send 創建的每個鏈接將在限定下載次數(最多100次)或限定時間內(最多7天) 后過期,有種「閱后即焚」的味道。

          輪事件:滾輪

          滾動(卷動)事件:滾輪、拖拽滾動條、鍵盤方向鍵

          <script type="text/javascript">
          //滾輪事件:滾輪
          //卷動事件:滾輪、拖拽滾動條、鍵盤?鍵
          
          //IE和Chrome
          gunlun.onmousewheel=function(){
          this.innerHTML +="IE和Chrome<br/>";
          }
          //Firefox
          gunlun.addEventListener("DOMMouseScroll", function(){
          this.innerHTML +="Firefox<br/>";
          })
          </script>

          判斷滾輪方向

          <script type="text/javascript">
          //滾輪事件:滾輪
          //卷動事件:滾輪、拖拽滾動條、鍵盤?鍵
          
          //IE和Chrome
          gunlun.onmousewheel=function(e){
          var ev=e || window.event;
          console.log(ev.wheelDelta);//判斷滾輪方向的
          //上120
          //下-120
          
          this.innerHTML +="IE和Chrome<br/>";
          }
          //Firefox
          gunlun.addEventListener("DOMMouseScroll",function(e){
          var ev=e || window.event;
          console.log(ev.detail);//滾輪方向
          //上-3
          //下3
          this.innerHTML +="Firefox<br/>";
          })
          </script>

          兼容性封裝


          主站蜘蛛池模板: 国产福利电影一区二区三区,亚洲国模精品一区 | 日韩精品无码一区二区三区| 国产成人一区二区三区| 国产一区二区三区播放心情潘金莲| 亚洲AV综合色一区二区三区| 国产丝袜美女一区二区三区| 男插女高潮一区二区| 日韩精品一区二区三区毛片 | 美女福利视频一区| 麻豆亚洲av熟女国产一区二| 国产精品香蕉一区二区三区 | 中文字幕一区二区三区日韩精品 | 亚洲一区二区免费视频| 日本免费一区尤物| 亚洲一区二区三区影院 | 精品欧洲av无码一区二区三区| 亚洲香蕉久久一区二区三区四区 | 无码av免费一区二区三区试看| 亚洲sm另类一区二区三区| 一区二区三区免费视频播放器| 天堂国产一区二区三区| 国产一区视频在线免费观看| 国产麻豆精品一区二区三区v视界 国产美女精品一区二区三区 | 精品视频一区二区三三区四区| 亚洲码一区二区三区| 国产成人久久精品麻豆一区| 国产乱码一区二区三区| 国产伦理一区二区| 日韩一区二区三区在线观看| 国产日韩一区二区三区在线播放| 国产精品无码不卡一区二区三区| 国产精品无码一区二区三区毛片| 日本不卡一区二区三区| 国产亚洲自拍一区| 亚洲视频在线一区二区| 欧洲精品码一区二区三区免费看 | 免费av一区二区三区| 国产精品乱码一区二区三区 | 亚洲一区二区三区首页| 中文字幕av无码一区二区三区电影| 波多野结衣在线观看一区二区三区 |