webgl 系列 —— 變換矩陣和動畫

来源:https://www.cnblogs.com/pengjiali/archive/2023/03/09/17200893.html
-Advertisement-
Play Games

其他章節請看: webgl 系列 變換矩陣和動畫 動畫就是不停地將某個東西變換(transform)。例如將三角形不停地旋轉就是一個動畫 和 CSS transform 類似,變換有三種形式:平移、縮放和旋轉。 簡單的變換用普通表達式容易實現,如果事情複雜,比如旋轉後平移,這時就可以使用變換矩陣。 ...


其他章節請看:

webgl 系列

變換矩陣和動畫

動畫就是不停地將某個東西變換(transform)。例如將三角形不停地旋轉就是一個動畫

CSS transform 類似,變換有三種形式:平移縮放旋轉

簡單的變換用普通表達式容易實現,如果事情複雜,比如旋轉後平移,這時就可以使用變換矩陣

普通表達式

平移

比如要平移一個三角形,只需要將三個頂點移動相同的距離即可(這是一個逐頂點操作)

用二維向量表示,就像這樣:[x1, y1] + [tx1, ty2] = [x2, y2]

比如要實現如下效果:

前面我們已經講過三角形了,這裡不再冗餘,改動的核心代碼如下:

 const VSHADER_SOURCE = `
 attribute vec4 a_Position;
+uniform vec4 u_Translation;
 void main() {
-  gl_Position = a_Position;
+  gl_Position = a_Position + u_Translation;
   gl_PointSize = 10.0;
 }
 `
function main() {
     gl.clearColor(0, 0, 0, 1);
     gl.clear(gl.COLOR_BUFFER_BIT);

+    const u_Translation = gl.getUniformLocation(gl.program, 'u_Translation');
+    if (!u_Translation) {
+        return;
+    }
+    gl.uniform4f(u_Translation, 0.5, 0.5, 0, 0.0);
+

a_Position 和 u_Translation 都是 vec4 類型,使用 + 號,兩個矢量(也稱向量)對應的分量會被同時相加(矢量相加是著色器語言的特性之一)。就像這樣:

縮放

以一個點為例,比如要將 A 點縮放到 B 點,乘以一個繫數就好,繫數小於1表示縮小,繫數大於1表示放大:

用二維向量表示,就像這樣:k[x1, y1] = [x2, y2]

旋轉

比如要將 p 點旋轉 β,推導出來的公式如下:

變換矩陣

概念

變換矩陣(非常適合操作電腦圖形)是數學線性代數中的一個概念。請看下圖:

將點從 S 旋轉到 T,新坐標(m, n)可以用普通表達式表示,同樣可以用變換矩陣來表示(舊點 * 變換矩陣 = 新點

變換矩陣和向量相乘有一個規則,並會得到一個新的向量。

Tip:webgl 中的一個點,在坐標系中就相當於一個向量

在 webgl 中變換矩陣和向量相乘的規則如下:

:牢記公式:變換矩陣 * 向量 會生成一個新的向量;順序不同結果也不同,例如:向量 * 變換矩陣

旋轉

將旋轉的普通表達式轉為變換矩陣:

四維矩陣

為什麼要用四維矩陣

因為三維矩陣矩陣不夠用,比如將 (0,0,0) 移動到 (1, 0, 0),用三維矩陣是表示不出來的,而四維卻可以。請看下圖:

平移

將平移的普通表達式轉為變換矩陣:

縮放

將縮放的普通表達式轉為變換矩陣:

手動矩陣

為了更好的理解矩陣。我們先不使用矩陣庫,直接通過 js 來使用矩陣實現變換。

矩陣顛倒

js 中沒有矩陣數據類型,這裡用數組表示。

比如要表示如下一個平移矩陣:

1, 0, 0, Tx
0, 1, 0, Ty
0, 0, 1, Tz
0, 0, 0, 1

數組就是這樣:

const matrix = [
  1, 0, 0, Tx,
  0, 1, 0, Ty,
  0, 0, 1, Tz,
  0, 0, 0, 1,
]

而要表示如上這個變換矩陣,在 webgl 中就得將數組顛倒:行變成列。

所以最後就得這麼寫:

const matrix = [
  1, 0, 0, 0,
  0, 1, 0, 0,
  0, 0, 1, 0,
  Tx, Ty, Tz, 1,
]

Tip: 對於縮放,顛倒後和顛倒前是相同的。

平移

需求:將三角形向右上角偏移。

效果

前面我們已經學會畫三角形,筆者在此基礎上改動如下代碼:

 const VSHADER_SOURCE = `
+// mat4 是一種4維矩陣
+uniform mat4 u_xformMatrix;
 void main() {
-  gl_Position = a_Position ;
+  // 註:必須是 "變換矩陣 * 向量",不可是 "向量 * 變換矩陣"
+  gl_Position = u_xformMatrix * a_Position ;
   gl_PointSize = 10.0;
 }
 `
function main() {
     initVertexBuffers(gl, vertices)

+    變換(gl)

    gl.drawArrays(gl.TRIANGLES, 0, vertices.vertexNumber);
}

+function 變換(gl){
+    const u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
+    if (!u_xformMatrix) {
+        console.log('Failed to get the storage location of u_xformMatrix');
+        return;
+    }
+    // 四維矩陣
+    const [Tx, Ty, Tz] = [0.5, 0.5, 0];
+    // webgl 中矩陣的行和列是要顛倒的,比如要傳一個 A 矩陣,給 webgl 的A矩陣就得顛倒,也就是將 A 的第一行變為第一列,第二行變成第二列
+    const matrix = new Float32Array([
+        1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        Tx, Ty, Tz, 1,
+    ])
+    // 將矩陣分配給 u_xformMatrix
+    gl.uniformMatrix4fv(u_xformMatrix, false, matrix);
+}

代碼解析:

  • 前面已經說過,變換是一個逐頂點的操作,每個頂點都相同,所以不用 attribute 而用 uniform
  • mat4 表示4*4的矩陣
  • 向量(新點) = 變換矩陣 * 向量(舊點)
  • gl.uniformMatrix4fv(location, transpose, value) 為 uniform variables 指定矩陣值。webgl 中 transpose 必須為 false.

:如果改變變換矩陣 * 向量的順序,平移效果就不對了:

矩陣庫

自己手寫矩陣數組非常麻煩。

openGL 提供了一系列有用的函數幫助我們創建變換矩陣。例如通過 glTranslate 傳入在 x、y、z 上平移的距離,就可以創建一個平移矩陣。

既然 webgl 中未提供創建變換矩陣的函數,我們就使用庫來做這部分工作。

gl-matrix

筆者使用一個較流行的矩陣庫 gl-matrix —— 用於高性能WebGL應用程式的Javascript矩陣和矢量(又稱為向量)庫。

下載後,在 dist 目錄下看到 esm 文件夾和兩個 js 文件:

toji-gl-matrix-4480752/dist (master)
$ ll
drwxr-xr-x 1 Administrator 197121      0 Mar  6 15:26 esm/
-rw-r--r-- 1 Administrator 197121  52466 Jan 10 05:24 gl-matrix-min.js
-rw-r--r-- 1 Administrator 197121 206643 Jan 10 05:24 gl-matrix.js

其實也就是提供兩種使用的方法:

  • esm 通過 <script type="module" src="main.mjs"></script> 這種方式使用
  • 最常見的 <script src="animation.js"></script>

筆者選用第二種:在 html 中引入:<script src="./animation.js"></script>

這時在控制台就有一個 glMatrix 全局變數:

glMatrix
{glMatrix: {…}, mat2: {…}, mat2d: {…}, mat3: {…}, mat4: {…}, …}
    glMatrix: {EPSILON: 0.000001, ANGLE_ORDER: "zyx", RANDOM: ƒ, setMatrixArrayType: ƒ, …}
    mat2: {create: ƒ, clone: ƒ, copy: ƒ, identity: ƒ, fromValues: ƒ, …}
    mat2d: {create: ƒ, clone: ƒ, copy: ƒ, identity: ƒ, fromValues: ƒ, …}
    mat3: {create: ƒ, fromMat4: ƒ, clone: ƒ, copy: ƒ, fromValues: ƒ, …}
    mat4: {create: ƒ, clone: ƒ, copy: ƒ, fromValues: ƒ, set: ƒ, …}
    quat: {create: ƒ, identity: ƒ, setAxisAngle: ƒ, getAxisAngle: ƒ, getAngle: ƒ, …}
    quat2: {create: ƒ, clone: ƒ, fromValues: ƒ, fromRotationTranslationValues: ƒ, fromRotationTranslation: ƒ, …}
    vec2: {create: ƒ, clone: ƒ, fromValues: ƒ, copy: ƒ, set: ƒ, …}
    vec3: {create: ƒ, clone: ƒ, length: ƒ, fromValues: ƒ, copy: ƒ, …}
    vec4: {create: ƒ, clone: ƒ, fromValues: ƒ, copy: ƒ, set: ƒ, …}

官方文檔也是從這幾個模塊來介紹的:mat2, mat2d, mat3, mat4, quat, quat2, vec2, vec3, vec4。

  • mat[234]就是2維3維4維矩陣
  • vec[234]就是2維3維4維向量
四維矩陣

首先取得 mat4 模塊,然後調用 create() 就會創建一個四維矩陣:

// 四維矩陣模塊
const { mat4 } = glMatrix
// 創建一個4維單位矩陣
const matrix = mat4.create()
/*
Float32Array(16) [
    1, 0, 0, 0, 
    0, 1, 0, 0, 
    0, 0, 1, 0, 
    0, 0, 0, 1]
*/
console.log(matrix)

Tip: create() 創建的是一個單位矩陣,如同數的乘法中的1

平移矩陣

fromTranslation - 平移矩陣

語法如下:

(static) fromTranslation(out, v) → {mat4}

Creates a matrix from a vector translation This is equivalent to (but much faster than): mat4.identity(dest); mat4.translate(dest, dest, vec);

Parameters:
Name	Type	         Description
out	    mat4	         mat4 receiving operation result
v	    ReadonlyVec3	 Translation vector

Returns:
out

請看示例:

mat4.fromTranslation(matrix, [0.5, 0.5, 0])
/*
    Float32Array(16) [
        1,   0,   0,   0, 
        0,   1,   0,   0, 
        0,   0,   1,   0, 
        0.5, 0.5, 0,   1
    ]
*/
console.log(matrix)

matrix 是一個單位矩陣,通過該方法,即可得到一個向 x 和 y 各平移 0.5 的變換矩陣。

與之對應不修改原矩陣的方法是:translate(out, a, v)。語法如下:

(static) translate(out, a, v) → {mat4}

Translate a mat4 by the given vector

Parameters:
Name	Type	        Description
out	  mat4	        the receiving matrix
a	    ReadonlyMat4	the matrix to translate
v	    ReadonlyVec3	vector to translate by

Returns:
out

請看示例:

const matrix2 = mat4.create()
mat4.translate(matrix2, matrix, [0.5, 0.5, 0])
// Float32Array(16) [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
/*
    Float32Array(16) [
        1, 0, 0, 0, 
        0, 1, 0, 0, 
        0, 0, 1, 0, 
        0, 0, 0, 1
    ]
*/
console.log(matrix)
/*
    Float32Array(16) [
        1,   0,   0,   0, 
        0,   1,   0,   0, 
        0,   0,   1,   0, 
        0.5, 0.5, 0,   1
    ]
*/
console.log(matrix2)

matrix 沒有改變,最終變換矩陣輸出到 matrix2。

旋轉矩陣

fromRotation - 旋轉矩陣

創建一個旋轉矩陣。請看示例:

// fromRotation(out, rad, axis) - out 是要修改的矩陣、rad 旋轉角度、axis 圍繞哪個軸旋轉 [x, y, z]
const angle = 90
// 角度轉弧度
const rad = angle * Math.PI / 180;
const axis = [0, 0, 1];
// 等於 fromXRotation、fromYRotation、fromZRotation
mat4.fromRotation(matrix, rad, axis)
/*
Float32Array(16) [
    6.123234262925839e-17, 1, 0, 0, 
    -1, 6.123234262925839e-17, 0, 0, 
    0, 0, 1, 0, 
    0, 0, 0, 1
]
*/
console.log(matrix)

與之對應不修改原矩陣的方法是:rotate(out, a, rad, axis)。用法與平移中的類似。

toRadian

旋轉矩陣需要使用弧度,通過 toRadian() 可以將角度轉為弧度。用法如下:

glMatrix.glMatrix.toRadian(180) => 3.141592653589793
縮放矩陣

fromScaling - 縮放矩陣

創建一個縮放矩陣。請看示例:

mat4.fromScaling(matrix, [2, 2, 0])
/*
Float32Array(16) [
    2, 0, 0, 0, 
    0, 2, 0, 0, 
    0, 0, 0, 0, 
    0, 0, 0, 1
]
*/
console.log(matrix)

與之對應不修改原矩陣的方法是:scale(out, a, v)。用法與平移中的類似。

平移

現在使用這個庫來實現平移,只需要將手動矩陣替換如下即可:

-    const matrix = new Float32Array([
-        1, 0, 0, 0,
-        0, 1, 0, 0,
-        0, 0, 1, 0,
-        Tx, Ty, Tz, 1,
-    ])
+
+    const { mat4 } = glMatrix
+    const matrix = mat4.create()
+    mat4.fromTranslation(matrix, [Tx, Ty, 0])

旋轉、縮放也類似,不再展開。

組合變換矩陣

變換矩陣可以組合,比如希望將三角形旋轉平移,這裡需要註意:順序不同導致結果不同。請看下圖

核心代碼:

const VSHADER_SOURCE = `
attribute vec4 a_Position;
// 移動矩陣
uniform mat4 u_tformMatrix;
// 旋轉矩陣
uniform mat4 u_rformMatrix;
void main() {
  // 先旋轉後移動
  // gl_Position = u_tformMatrix * u_rformMatrix * a_Position;

  // 先移動後旋轉
  gl_Position = u_rformMatrix * u_tformMatrix * a_Position;
  gl_PointSize = 10.0;               
}
`

const u_rformMatrix = gl.getUniformLocation(gl.program, 'u_rformMatrix');
const u_tformMatrix = gl.getUniformLocation(gl.program, 'u_tformMatrix');

const { mat4 } = glMatrix
const tMatrix = mat4.create()
const rMatrix = mat4.create()

mat4.fromTranslation(tMatrix, [0.5, 0, 0])
// 設置移動矩陣
gl.uniformMatrix4fv(u_tformMatrix, false, tMatrix);

const rad = glMatrix.glMatrix.toRadian(90)
const axis = [0, 0, 1];
mat4.fromRotation(rMatrix, rad, axis)
// 設置旋轉矩陣
gl.uniformMatrix4fv(u_rformMatrix, false, rMatrix);

組合變換矩陣的順序和 css 類似,從右往左。比如:

  • u_rformMatrix * u_tformMatrix * a_Position 先移動後旋轉
  • u_tformMatrix * u_rformMatrix * a_Position 先旋轉後移動

Tip: 這裡的組合變換矩陣其實就是電腦圖形學中模型變換(M)。還有視圖變換(V)、投影變換(P),統稱為 MVP。

動畫

需求

需求:繪製一個旋轉動畫

效果如下:

實現

思路:

  • 首先繪製三角形
  • 通過變換矩陣進行旋轉
  • 不停的繪製(改變旋轉角度)。使用專門用於動畫的requestAnimationFrame(用法類似 setTimeout,但不需要指定回調時間,瀏覽器會在最恰當的時候回調)

完整代碼如下:

const VSHADER_SOURCE = `
attribute vec4 a_Position;
// 所有頂點移動位置都相同,所以不用 Attribute 而用 uniform
// mat4 是一種4維矩陣
uniform mat4 u_xformMatrix;
void main() {
  // 註:必須是 "變換矩陣 * 向量",不可是 "向量 * 變換矩陣"
  gl_Position = u_xformMatrix * a_Position ;
  gl_PointSize = 10.0;               
}
`
const FSHADER_SOURCE = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`

function main() {
    const canvas = document.getElementById('webgl');
    const gl = canvas.getContext("webgl");
    if (!gl) {
        console.log('Failed to get the rendering context for WebGL');
        return;
    }
    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
        console.log('Failed to intialize shaders.');
        return;
    }
    const vertices = {
        data: new Float32Array([
            0.0, 0.5,
            -0.5, -0.5,
            0.5, -0.5
        ]),
        vertexNumber: 3,
        count: 2,
    }
    initVertexBuffers(gl, vertices)
    tick(gl, vertices)
}

function initVertexBuffers(gl, { data, count }) {
    // 1. 創建緩衝區對象
    const vertexBuffer = gl.createBuffer();
    if (!vertexBuffer) {
        console.log('創建緩衝區對象失敗');
        return -1;
    }

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

    const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
    }

    gl.vertexAttribPointer(a_Position, count, gl.FLOAT, false, 0, 0);

    gl.enableVertexAttribArray(a_Position);
}


function 變換(gl, vertices) {
    const u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
    if (!u_xformMatrix) {
        console.log('Failed to get the storage location of u_xformMatrix');
        return;
    }

    const { mat4 } = glMatrix
    const matrix = mat4.create()
    const rad = glMatrix.glMatrix.toRadian(angle)
    const axis = [0, 0, 1];
    mat4.fromRotation(matrix, rad, axis)
    gl.uniformMatrix4fv(u_xformMatrix, false, matrix);

    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    gl.drawArrays(gl.TRIANGLES, 0, vertices.vertexNumber);
}

let angle = 0
// 每次改變的角度
const seed = 1

function tick(gl, vertices){
    變換(gl, vertices)
    // 改變角度
    angle += seed;
    // 動畫繪製
    requestAnimationFrame(() => tick(gl, vertices))
}

其他章節請看:

webgl 系列

作者:彭加李
出處:https://www.cnblogs.com/pengjiali/p/17200893.html
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 導讀 本文將介紹網易數帆在數據治理方面的一些總結和思考。文章將圍繞以下三點展開: 1. 數據治理解決了什麼問題 2. 數據治理體系 3. 淺談數據治理的實現 01數據治理解決了什麼問題 首先看一下數據治理解決了什麼問題,可以總結為六個方面: 1. 數據開發與數據治理脫節 在許多企業中存在這樣一個現象 ...
  • 1 mysql邏輯架構 mysql邏輯架構圖: Mysql伺服器、存儲引擎 是兩個獨立的組件,彼此通過api交互 第一層:連接處理、授權認證、安全管理 第二層:核心服務功能 查詢解析、分析、優化、緩存以及所有的內置函數(日期、時間、數學、加密函數等) 跨存儲引擎的功能:存儲過程、觸發器、視圖等。 第 ...
  • 數據治理是推動大型集團企業轉型升級、提升競爭優勢、實現高質量發展的重要引擎。通過全鏈數據結構化,實現業務對象、業務規則、業務流程數字化,推進全鏈業務深度數字化,夯實數據運營底座。 廈門國貿集團股份有限公司(簡稱“國貿股份”)是國有控股上市公司,同時也是首批全國供應鏈創新與應用示範企業,在“十四五”規 ...
  • 摘要:其實游戲客戶對資料庫的訴求是很明確的,資料庫應當“放心存放心用”。 本文分享自華為雲社區《華為雲GaussDB(for Redis)揭秘第27期:聊聊游戲業務怎麼用高斯Redis》,作者:高斯Redis官方博客。 華為雲資料庫團隊是比較重視技術洞察的,對客戶真實的業務場景也比較看重。年初出差了 ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 花家舍 文章來源:GreatSQL社區原創 前文回顧 實現一個簡單的Database系列 譯註:cstack在github維護了一個簡單的、類似 ...
  • 生活中存在同時使用兩個微信的情況,一個工作一個生活,這時希望同時在電腦上登錄兩個賬號。如何做到呢?步驟如下: 右鍵單擊“微信”圖標,選擇屬性,目標框內的路徑就是微信安裝路徑,複製目標框里的內容。 將如下命令複製到 TXT 文件保存,再將該文件重命名,主要是將尾碼名改成“.bat”文件。 @echo ...
  • 好家伙,本篇為做題思考 書接上文 題目如下: 1.請給出下列代碼的輸出結果,並配合"消息隊列"寫出相關解釋 async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } ...
  • 一般來說,項目由子模塊組成,拿到後端提供過來的介面,一般也是按照子模塊來分類提供的.請教一下各位,你們前端項目是如何管理api的? 希望各位貼點你們的優秀代碼段上來學習學習. 常見: 各個模塊的api存放到單獨的js文件里,返回一個請求實例promise對象 使用的時候根據需求引入相應的請求方法 / ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...