日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

PixiJS 源碼解讀:繪制矩形的渲染過程講解

來源: 責編: 時間:2023-10-10 18:32:13 317觀看
導讀大家好,我是前端西瓜哥。之前寫了一篇 PixiJS 繪制矩形,簡單說了一下 PixiJS 是怎么繪制矩形的。《PixiJS 源碼解讀:繪制矩形,底層都做了什么?》它更多的講解上層的東西,沒花太多筆墨描繪底層渲染的流程。所以我寫了這篇文

iOz28資訊網——每日最新資訊28at.com

大家好,我是前端西瓜哥。iOz28資訊網——每日最新資訊28at.com

之前寫了一篇 PixiJS 繪制矩形,簡單說了一下 PixiJS 是怎么繪制矩形的。iOz28資訊網——每日最新資訊28at.com

《PixiJS 源碼解讀:繪制矩形,底層都做了什么?》iOz28資訊網——每日最新資訊28at.com

它更多的講解上層的東西,沒花太多筆墨描繪底層渲染的流程。所以我寫了這篇文章,對渲染流程進行補充講解。iOz28資訊網——每日最新資訊28at.com

PixiJS 版本為 7.2.4。iOz28資訊網——每日最新資訊28at.com

要求讀者熟悉 WebGL 的基礎知識。iOz28資訊網——每日最新資訊28at.com

本文會 以繪制設置了填充和描邊的矩形為例子,看底層 WebGL 的調用執行。iOz28資訊網——每日最新資訊28at.com

業務層代碼:iOz28資訊網——每日最新資訊28at.com

const app = new PIXI.Application({  width: 500,  height: 300,  background: "#cc0", //(土黃色)});document.body.appendChild(app.view);const graph = new PIXI.Graphics();graph.beginFill(0xff0044); // 紅色填充色graph.lineStyle({ color: "blue", width: 4 }); // 藍色描邊graph.drawRect(90, 70, 300, 100);app.stage.addChild(graph);

繪制結果為:iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

創建 gl

第一步是創建 gl 對象,上下文類型優先使用 "webgl2"。iOz28資訊網——每日最新資訊28at.com

如果不支持,會降級為 "webgl"、"experimental-webgl"。iOz28資訊網——每日最新資訊28at.com

gl = canvas.getContext("webgl2", options);

gl 在 renderer 渲染器初始化的時候構建的,可通過 app.renderer.gl 拿到。iOz28資訊網——每日最新資訊28at.com

構建著色器代碼片段

定義 頂點著色器 和 片元著色器。iOz28資訊網——每日最新資訊28at.com

著色器(Shader)是一種類 C 語言 GLSL,用于描述需要繪制的 頂點信息和顏色信息。iOz28資訊網——每日最新資訊28at.com

著色器模板

首先是 字符串模板,等著根據配置填充成一個完整的著色器代碼片段。iOz28資訊網——每日最新資訊28at.com

頂點著色器的模板(后面會基于它生成真正可用的著色器)位于 packages/core/src/batch/texture.vert 中。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

batch 文件夾都是和 批量繪制 有關的邏輯,批量、減少 draw call 正是 PixiJS 高效繪制的秘訣。iOz28資訊網——每日最新資訊28at.com

precision highp float;attribute vec2 aVertexPosition;attribute vec2 aTextureCoord;attribute vec4 aColor;attribute float aTextureId;uniform mat3 projectionMatrix;uniform mat3 translationMatrix;uniform vec4 tint;varying vec2 vTextureCoord;varying vec4 vColor;varying float vTextureId;void main(void){    gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);    vTextureCoord = aTextureCoord;    vTextureId = aTextureId;    vColor = aColor * tint;}

片元著色器和顏色有關。iOz28資訊網——每日最新資訊28at.com

varying vec2 vTextureCoord;varying vec4 vColor;varying float vTextureId;uniform sampler2D uSamplers[%count%];void main(void){    vec4 color;    %forloop%    gl_FragColor = color * vColor;}

這里的 %count% 和%forloop% 是占位符,會在之后進行替換。iOz28資訊網——每日最新資訊28at.com

最終著色器代碼片段

在 renderer 初始化時,上面的模板會進行一系列的改造,兩個著色器最終轉換為下面的樣子。iOz28資訊網——每日最新資訊28at.com

頂點著色器(Vertex Shader)和頂點的位置、大小有關。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

補充一些簡單注釋說明。iOz28資訊網——每日最新資訊28at.com

頂點著色器

precision highp float; // 浮點數使用高精度#define SHADER_NAME pixi-shader-2precision highp float;attribute vec2 aVertexPosition; // 頂點位置 x 和 yattribute vec2 aTextureCoord; // 紋理坐標,會傳給片元著色器attribute vec4 aColor; // 顏色,rgba,會傳給片元著色器attribute float aTextureId; // 紋理單元 ID,會傳給片元著色器uniform mat3 projectionMatrix; // 投影矩陣uniform mat3 translationMatrix; // 平移變換矩陣uniform vec4 tint; // 改變顏色,實現濾鏡效果,會和 aColor 相乘傳給片元著色器varying vec2 vTextureCoord; // varing 都是用來傳遞的varying vec4 vColor;varying float vTextureId;void main(void){    //  進行一系列矩陣乘法運算,將最后的點傳給內置的著色器變量,設置點的位置    gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);   // 下面都是要傳給片元著色器的變量    vTextureCoord = aTextureCoord;    vTextureId = aTextureId;    vColor = aColor * tint;}

片元著色器

片元著色器(Fragment Shader)用于描述頂點圍成區域的像素顏色。iOz28資訊網——每日最新資訊28at.com

下面是片元著色器的最終代碼,同樣我會加一些注釋說明iOz28資訊網——每日最新資訊28at.com

precision mediump float;#define SHADER_NAME pixi-shader-2varying vec2 vTextureCoord; // 紋理坐標,varying vec4 vColor; // 顏色varying float vTextureId; // 使用哪一個紋理采樣器uniform sampler2D uSamplers[16]; // 16 個紋理采樣器void main(void){  vec4 color;   if(vTextureId < 0.5) {    // 從紋理采樣器(比如圖片轉換過來的像素點集合)中,提取特定位置的像素點    color = texture2D(uSamplers[0], vTextureCoord);  }else if(vTextureId < 1.5) {    color = texture2D(uSamplers[1], vTextureCoord);  }  // ...  } else {    color = texture2D(uSamplers[15], vTextureCoord);  }    // 疊加顏色值,和紋理采樣器取得的顏色值,賦值給片元著色器內置變量  gl_FragColor = color * vColor;}

如果沒有設置紋理,PixiJS 會給一個默認的兜底用紋理對象,一個 16x16 的白色方形。iOz28資訊網——每日最新資訊28at.com

這兩個著色器片段會保存到 Shader 實例中,放到 app.render.shader 下。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

編譯著色器程序

第一次調用 renderer 渲染器 render 方法時,PixiJS 會 創建頂點著色器對象和片元著色器對象。iOz28資訊網——每日最新資訊28at.com

這些邏輯是在 generateProgram 方法中實現的。該方法的核心代碼:iOz28資訊網——每日最新資訊28at.com

function generateProgram(gl, program) {  //(1)創建頂點著色器對象、片元著色器對象等  const glVertShader = compileShader(gl, gl.VERTEX_SHADER, program.vertexSrc);  const glFragShader = compileShader(    gl,    gl.FRAGMENT_SHADER,    program.fragmentSrc  );  // 創建程序對象  const webGLProgram = gl.createProgram();  //(2)綁定 attribute  // keys 為 ['aColor', 'aTextureCoord', 'aTextureId', 'aVertexPosition']  for (let i = 0; i < keys.length; i++) {    program.attributeData[keys[i]].location = i;    // 將屬性綁定到頂點著色器的制定位置    // 如:gl.bindAttribLocation(gl.program, 0, "aColor");    gl.bindAttribLocation(webGLProgram, i, keys[i]);  }  // 刪除著色器對象,釋放內存  gl.deleteShader(glVertShader);  gl.deleteShader(glFragShader);  //(3)綁定 uniformLocation(準確來說是拿地址,還沒正式綁定)  // 屬性(對應 i 變量)有:projectionMatrix、tint、translationMatrix、uSamplers  for (const i in program.uniformData) {    const data = program.uniformData[i];    uniformData[i] = {      location: gl.getUniformLocation(webGLProgram, i),      value: defaultValue(data.type, data.size),    };  }  const glProgram = new GLProgram(webGLProgram, uniformData);  return glProgram;}

分成三個主要步驟。iOz28資訊網——每日最新資訊28at.com

創建著色器對象、程序對象。iOz28資訊網——每日最新資訊28at.com

compileShader 實現:iOz28資訊網——每日最新資訊28at.com

function compileShader(gl, type, src) {  const shader = gl.createShader(type);  gl.shaderSource(shader, src);  gl.compileShader(shader);    gl.attachShader(webGLProgram, glVertShader);  gl.attachShader(webGLProgram, glFragShader);  // ...  gl.linkProgram(webGLProgram);  return shader;}

綁定 attribute 類型的變量 (但此時還沒傳入 Buffer 數據,只是設置了如何訪問等操作);iOz28資訊網——每日最新資訊28at.com

綁定 uniform 類型的變量。iOz28資訊網——每日最新資訊28at.com

之后在 app.renderer.shader.bind 方法內執行下面代碼,應用剛剛創建的程序對象。iOz28資訊網——每日最新資訊28at.com

this.gl.useProgram(glProgram.program);

渲染階段

前面做的是準備工作,編譯著色器。iOz28資訊網——每日最新資訊28at.com

接下來就是渲染階段。iOz28資訊網——每日最新資訊28at.com

PIXI.Ticker 定時器會在渲染下一幀前調用 renderer.render 方法,進入 WebGL 的渲染流程。iOz28資訊網——每日最新資訊28at.com

清空畫布填充背景色

首先是清空畫布。iOz28資訊網——每日最新資訊28at.com

// 入口方法:renderer.renderTexture.clearclass ObjectRendererSystem {  render(displayObject, options) {    // ...    // (1) 清空畫布,并指定顏色    renderer.renderTexture.clear();    // ...  }}

它會執行 clear 方法iOz28資訊網——每日最新資訊28at.com

class FramebufferSystem {  clear(r, g, b, a, mask = BUFFER_BITS.COLOR | BUFFER_BITS.DEPTH) {    const { gl } = this;    // 背景色 #cc0 轉換為 rbga 格式:    // (0.800000011920929, 0.800000011920929, 0, 1)    gl.clearColor(r, g, b, a);    // 清空顏色和深度緩存    gl.clear(mask);  }}

遞歸調用 render

遞歸圖形樹(app.stage),調用它們(繼承了 IRenderableObject 接口類型)的 render 方法,它們會拿到 renderer 對象,然后執行自己的渲染邏輯。iOz28資訊網——每日最新資訊28at.com

// app.stage 是 Container 實例class Container extends DisplayObject {  render(renderer) {    // ...    this._render(renderer); // 真正的渲染邏輯    for (let i = 0, j = this.children.length; i < j; ++i) {      this.children[i].render(renderer);    }  }}

對于前文的示例代碼,會分析矩形屬性,構建頂點和片元數據,然后執行 WebGL 的繪制 API。iOz28資訊網——每日最新資訊28at.com

對矩形三角化,構建頂點和片元數據

先基于 x、y、width、height 計算出矩形的 4 個頂點放到 points。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

然后進行三角化。三角化就是將圖形轉換為對應的三角形的組合。iOz28資訊網——每日最新資訊28at.com

所謂圖形的渲染,其實就是繪制一個個小的三角形,組成特定的形狀。這些三角形的點,根據不同圖形(比如矩形和圓形),需要用不同算法去計算出來,然后把數據通過 WebGL 命令交給 GPU,讓它幫我們繪制出來。iOz28資訊網——每日最新資訊28at.com

首先是填充的三角化(對應  buildRectangle.triangulate() )。iOz28資訊網——每日最新資訊28at.com

基于前面的 4 個點得到填充塊的 4 個點,并設置對應的索引值 indices,之后調用 gl.drawElements() 需要用到。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

接著是描邊的三角化(對應 buildLine())。iOz28資訊網——每日最新資訊28at.com

下面是繪制描邊的代碼片段:iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

PixiJS 的計算邏輯很復雜,這是因為涉及到連接方式、末端樣式的情況。iOz28資訊網——每日最新資訊28at.com

同樣,也要計算它的頂點、索引、紋理坐標。iOz28資訊網——每日最新資訊28at.com

西瓜哥我將最終的填充和描邊產生的點,做了一下可視化。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

用的是 desmos 可視化工具,這里給一下這個可視化鏈接:iOz28資訊網——每日最新資訊28at.com

https://www.desmos.com/calculator/r3dwqeweu2?lang=zh-CN。iOz28資訊網——每日最新資訊28at.com

最后計算好的三角化數據會保存到 graph 對象的 batches 數組下(batches 表示要批量處理的意思)。iOz28資訊網——每日最新資訊28at.com

batch 對象包括頂點坐標(vertexData)、顏色(_batchRGB)、索引(indices)和紋理坐標(uvs)。iOz28資訊網——每日最新資訊28at.com

下面是填充色對應的數據:iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

批量渲染

這里產生了兩個 batch 對象(對應填充和描邊),然后遍歷傳給 BatchRender 類的 render 方法。說是 render 方法,其實并不立即 render,而是將 batch 對象的數據解讀和保存起來,之后 flush 時才正式將數據加到 WebGL 里。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

這些屬性會組合拼裝在一個類型數組里。6 個一組,逐頂點繪制。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

傳完后,會調用 BatchRender 類的 flush 方法,將頂點數據和索引數組通過 gl.bufferData() 進行綁定。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

綁定 uniform 值

在 ShaderSystem 類的 syncUniforms 中,會依次設置好各個 uniform 變量:tint、translationMatrix、uSamplers、projectionMatrix。iOz28資訊網——每日最新資訊28at.com

class ShaderSystem {    syncUniforms(group, glProgram, syncData) {    // 生成同步 uniform 的函數(不同 uniform 的函數不同)    const syncFunc =         group.syncUniforms[this.shader.program.id] ||         this.createSyncGroups(group);    // 同步!    syncFunc(glProgram.uniformData, group.uniforms, this.renderer, syncData);  }  createSyncGroups(group) {    const id = this.getSignature(group, this.shader.program.uniformData, "u");    if (!this.cache[id]) {      this.cache[id] = generateUniformsSync(group, this.shader.program.uniformData);    }    group.syncUniforms[this.shader.program.id] = this.cache[id];    return group.syncUniforms[this.shader.program.id];  }  }

下面是設置 tint 的方法:iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

綁定紋理

綁定紋理。iOz28資訊網——每日最新資訊28at.com

class TextureSystem {  bind(texture, location = 0) {    const { gl } = this;    // 開啟    gl.activeTexture(gl.TEXTURE0 + location);    // ...    gl.bindTexture(texture.target, glTexture.texture);    // ...  }}

因為示例并不繪制圖片,PixiJS 會提供默認的的白色紋理對象(所有值都是 1),這樣顏色值和其相乘,結果還是原來的顏色值。iOz28資訊網——每日最新資訊28at.com

渲染

最后調用 drawBatches 進行繪制。iOz28資訊網——每日最新資訊28at.com

drawBatches() {  const dcCount = this._dcIndex;  const { gl, state: stateSystem } = this.renderer;  const drawCalls = _BatchRenderer._drawCallPool;  let curTexArray = null;  for (let i = 0; i < dcCount; i++) {    const { texArray, type, size, start, blend } = drawCalls[i];    if (curTexArray !== texArray) {      curTexArray = texArray;      // 剛剛提到的紋理綁定邏輯      this.bindAndClearTexArray(texArray);    }    this.state.blendMode = blend;    stateSystem.set(this.state);    // 繪制 API    gl.drawElements(type, size, gl.UNSIGNED_SHORT, start * 2);  }}

最后我們就繪制出一個有填充和描邊的矩形了。iOz28資訊網——每日最新資訊28at.com

iOz28資訊網——每日最新資訊28at.com

之后 Ticker 會不斷地在繪制下一幀時調用 renderer 的 render 方法進行渲染,如果圖形沒改變(比如通過 dirtyId 和 cacheDirty 是否相同判斷),我們會跳過三角化的環節,使用緩存好的數據去繪制渲染。iOz28資訊網——每日最新資訊28at.com

結尾

PixiJS 繪制圖形使用了 WebGL,為了利用 GPU 的并行能力,需要給著色器一次性提供盡可能多的頂點和顏色信息。iOz28資訊網——每日最新資訊28at.com

PixiJS 提供了一些基礎圖形,比如矩形。繪制時會根據圖形屬性信息進行三角化,最后將所有的信息組合起來,一次性提供給 WebGL。iOz28資訊網——每日最新資訊28at.com

這篇文章其實斷斷續續寫了好久,PixiJS 里的彎彎道道挺多的,經常調試了半天就是找不著北了,一度擱置。最后還是硬著頭皮不斷地調試和思考,總算把這篇文章結束掉了。iOz28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-12747-0.htmlPixiJS 源碼解讀:繪制矩形的渲染過程講解

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Java 集合框架超詳細!

下一篇: Springboot整合Hutool自定義注解實現數據脫敏

標簽:
  • 熱門焦點
  • 盧偉冰長文解析K60至尊版 對Redmi有著里程碑式的意義

    在今天的Redmi后性能時代戰略發布會結束之后,Redmi總經理盧偉冰又帶來了一篇長文,詳解了為什么 Redmi 要開啟后性能時代?為什么選擇和 MediaTek、Pixelworks 深度合作?以及后性
  • Golang 中的 io 包詳解:組合接口

    io.ReadWriter// ReadWriter is the interface that groups the basic Read and Write methods.type ReadWriter interface { Reader Writer}是對Reader和Writer接口的組合,
  • 讓我們一起聊聊文件的操作

    文件【1】文件是什么?文件是保存數據的地方,是數據源的一種,比如大家經常使用的word文檔、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存數據,它既可以保
  • Python異步IO編程的進程/線程通信實現

    這篇文章再講3種方式,同時講4中進程間通信的方式一、 Python 中線程間通信的實現方式共享變量共享變量是多個線程可以共同訪問的變量。在Python中,可以使用threading模塊中的L
  • 為什么你不應該使用Div作為可點擊元素

    按鈕是為任何網絡應用程序提供交互性的最常見方式。但我們經常傾向于使用其他HTML元素,如 div span 等作為 clickable 元素。但通過這樣做,我們錯過了許多內置瀏覽器的功能。
  • “又被陳思誠騙了”

    作者|張思齊 出品|眾面(ID:ZhongMian_ZM)如今的國產懸疑電影,成了陳思誠的天下。最近大爆電影《消失的她》票房突破30億斷層奪魁暑期檔,陳思誠再度風頭無兩。你可以說陳思誠的
  • 聯想YOGA 16s 2022筆記本將要推出,屏幕支持觸控功能

    聯想此前宣布,將于11月2日19:30召開聯想秋季輕薄新品發布會,推出聯想 YOGA 16s 2022 筆記本等新品。官方稱,YOGA 16s 2022 筆記本將搭載 16 英寸屏幕,并且是一
  • Windows 11發布,微軟一改往常對老機型開放的態度

    距離 Windows 11 發布已經過去一周,在過去一周里,很多數碼愛好者圍繞其對 Android 應用的支持、對老機型的升級問題展開了激烈討論。與以往不同的是,在這次大
  • 聯想小新Pad Pro 12.6將要推出,搭載高通驍龍 870 處理器

    聯想小新Pad Pro 12.6將于秋季新品會上推出,官方按照慣例直接在發布會前給出了機型的所有參數。聯想小新 Pad Pro 12.6 將搭載高通驍龍 870 處理器,重量為 5
Top 主站蜘蛛池模板: 宁化县| 嘉善县| 和硕县| 康马县| 民乐县| 华蓥市| 介休市| 绿春县| 武山县| 新宁县| 鹤岗市| 永仁县| 瓦房店市| 东安县| 上虞市| 松滋市| 巴塘县| 扶余县| 双牌县| 安仁县| 景宁| 平顺县| 寿阳县| 高雄县| 马公市| 阿瓦提县| 沁源县| 和田县| 巴塘县| 武宁县| 丰顺县| 乌兰察布市| 南郑县| 信宜市| 巴彦淖尔市| 长兴县| 金沙县| 昌邑市| 两当县| 砀山县| 麟游县|