WebGL之旅(十一)透視投影
與正射投影不同,透視投影會出近大遠小的效果,與人的視覺效果一直,遊戲中一般都是使用的透視投影。
示例:
/**
* 透視投影矩陣
* [email protected]
* */
var g_vs = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMat;
uniform mat4 u_ProjMat;
varying vec4 v_Color;
void main() {
gl_Position = u_ProjMat * u_ViewMat * a_Position;
v_Color = a_Color;
}`;
var g_fs = `
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}`;
function main() {
var gl = getGL();
var shaderProgram = initShader(gl);
var n = initVertexBuffers(gl, shaderProgram);
draw(gl, shaderProgram, n);
}
function getGL() {
var canvas = document.getElementById("container" );
return canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
}
function initShader(gl) {
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource( vs, g_vs);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource( fs, g_fs);
gl.compileShader(fs);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vs);
gl.attachShader(shaderProgram, fs);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
return shaderProgram;
}
function initVertexBuffers(gl, shaderProgram) {
var verticesColors = new Float32Array([
0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
0.25, -1.0, -4.0, 0.4, 1.0, 0.4,
1.25, -1.0, -4.0, 1.0, 0.4, 0.4,
0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
0.25, -1.0, -2.0, 1.0, 1.0, 0.4,
1.25, -1.0, -2.0, 1.0, 0.4, 0.4,
0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
0.25, -1.0, 0.0, 0.4, 0.4, 1.0,
1.25, -1.0, 0.0, 1.0, 0.4, 0.4,
-0.75, 1.0, -4.0, 0.4, 1.0, 0.4,
-1.25, -1.0, -4.0, 0.4, 1.0, 0.4,
-0.25, -1.0, -4.0, 1.0, 0.4, 0.4,
-0.75, 1.0, -2.0, 1.0, 1.0, 0.4,
-1.25, -1.0, -2.0, 1.0, 1.0, 0.4,
-0.25, -1.0, -2.0, 1.0, 0.4, 0.4,
-0.75, 1.0, 0.0, 0.4, 0.4, 1.0,
-1.25, -1.0, 0.0, 0.4, 0.4, 1.0,
-0.25, -1.0, 0.0, 1.0, 0.4, 0.4,
]);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
var vertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(shaderProgram, "a_Position");
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
gl.enableVertexAttribArray(a_Position);
var a_Color = gl.getAttribLocation(shaderProgram, "a_Color");
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
return verticesColors.length / 6;
}
function draw(gl, shaderProgram, n) {
var u_ProjMat = gl.getUniformLocation(shaderProgram, "u_ProjMat");
var projMat = getPerspectiveProjection(60, 1280/720, 1, 100);
gl.uniformMatrix4fv(u_ProjMat, false, projMat);
var u_ViewMat = gl.getUniformLocation(shaderProgram, "u_ViewMat");
var viewMat = lookAt(0, 0, 6, 0, 0, -100, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMat, false, viewMat);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);
}
function getPerspectiveProjection(fov, aspect, near, far) {
var fovy = Math.PI * fov / 180 / 2;
var s = Math.sin(fovy);
var rd = 1 / (far - near);
var ct = Math.cos(fovy) / s;
return new Float32Array([
ct / aspect, 0, 0, 0,
0, ct, 0, 0,
0, 0, -(far + near) * rd, -1,
0, 0, -2 * near * far * rd, 0,
]);
}
/**
* 以下程式碼為lookAt的實現
* */
/**
* 由平移向量獲取平移矩陣
* */
function getTranslationMatrix(x, y, z) {
return new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
x, y, z, 1.0,
]);
}
/**
* 由旋轉弧度和旋轉軸獲取旋轉矩陣
* */
function getRotationMatrix(rad, x, y, z) {
if (x > 0) {
// 繞x軸的旋轉矩陣
return new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, Math.cos(rad), -Math.sin(rad), 0.0,
0.0, Math.sin(rad), Math.cos(rad), 0.0,
0.0, 0.0, 0.0, 1.0,
]);
} else if (y > 0) {
// 繞y軸的旋轉矩陣
return new Float32Array([
Math.cos(rad), 0.0, -Math.sin(rad), 0.0,
0.0, 1.0, 0.0, 0.0,
Math.sin(rad), 0.0, Math.cos(rad), 0.0,
0.0, 0.0, 0.0, 1.0,
]);
} else if(z > 0) {
// 繞z軸的旋轉矩陣
return new Float32Array([
Math.cos(rad), Math.sin(rad), 0.0, 0.0,
-Math.sin(rad), Math.cos(rad), 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
} else {
// 沒有指定旋轉軸,報個錯,返回一個單位矩陣
console.error("error: no axis");
return new Float32Array([
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
}
}
/**
* 檢視矩陣
* */
function lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) {
var zAxis = subVector([centerX, centerY, centerZ], [eyeX, eyeY, eyeZ]);
var N = normalizeVector(zAxis);
var xAxis = crossMultiVector(N, [upX, upY, upZ]);
var U = normalizeVector(xAxis);
var V = crossMultiVector(U, N);
// 旋轉的逆矩陣
var r = new Float32Array([
U[0], V[0], -N[0], 0,
U[1], V[1], -N[1], 0,
U[2], V[2], -N[2], 0,
0, 0, 0, 1
]);
// 平移的逆矩陣
var t = getTranslationMatrix(-eyeX, -eyeY, -eyeZ);
return multiMatrix44(r, t);
}
/**
* 由縮放因子獲取縮放矩陣
* */
function getScaleMatrix(xScale, yScale, zScale) {
return new Float32Array([
xScale, 0.0, 0.0, 0.0,
0.0, yScale, 0.0, 0.0,
0.0, 0.0, zScale, 0.0,
0.0, 0.0, 0.0, 1.0,
]);
}
/**
* 向量點乘
* */
function dotMultiVector(v1, v2) {
var res = 0;
for (var i = 0; i < v1.length; i++) {
res += v1[i] * v2[i];
}
return res;
}
/**
* 向量叉乘
* */
function crossMultiVector(v1, v2) {
return [
v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]
];
}
/**
* 向量減法
* */
function subVector(v1, v2){
return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]];
}
/**
* 向量加法
* */
function addVector(v1, v2){
return [v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]];
}
/**
* 向量歸一化
* */
function normalizeVector(v) {
var len = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
return (len > 0.00001) ? [v[0]/len, v[1]/len, v[2]/len] : [0, 0, 0];
}
/**
* 4 x 4 矩陣的轉置
* */
function transposeMatrix(mat) {
var res = new Float32Array(16);
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
res[i * 4 + j] = mat[j * 4 + i];
}
}
return res;
}
/**
* 4 x 4 矩陣乘法
* */
function multiMatrix44(m1, m2) {
var mat1 = transposeMatrix(m1);
var mat2 = transposeMatrix(m2);
var res = new Float32Array(16);
for (var i = 0; i < 4; i++) {
var row = [mat1[i * 4], mat1[i * 4 + 1], mat1[i * 4 + 2], mat1[i * 4 + 3]];
for (var j = 0; j < 4; j++) {
var col = [mat2[j], mat2[j + 4], mat2[j + 8], mat2[j + 12]];
res[i * 4 + j] = dotMultiVector(row, col);
}
}
return transposeMatrix(res);
}
上列中,前後繪製了分三排繪製了9個三角形,可以看到,距離視點越遠的三角形越小,如圖:
從圖中可以看到,遮擋關係是不正確的,前面的物品被後面的遮擋住了,修改draw函式如下:
function draw(gl, shaderProgram, n) {
var u_ProjMat = gl.getUniformLocation(shaderProgram, "u_ProjMat");
var projMat = getPerspectiveProjection(60, 1280/720, 1, 100);
gl.uniformMatrix4fv(u_ProjMat, false, projMat);
var u_ViewMat = gl.getUniformLocation(shaderProgram, "u_ViewMat");
var viewMat = lookAt(0, 0, 6, 0, 0, -100, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMat, false, viewMat);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);// 開啟深度測試
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// 增加清空深度緩衝區
gl.drawArrays(gl.TRIANGLES, 0, n);
}
然後就正確了,如圖:
相關推薦
WebGL之旅(十一)透視投影
與正射投影不同,透視投影會出近大遠小的效果,與人的視覺效果一直,遊戲中一般都是使用的透視投影。 示例: /** * 透視投影矩陣 * [email protected] * */ var g_vs = ` attribute vec4
Python學習之旅(十一)
Python基礎知識(10):函式(Ⅱ) 一、全域性變數和區域性變數 區域性變數:在函式內定義的變數,在函式內使用 全域性變數:在函式外定義的變數,在程式任何地方都可以使用 1、全域性變數與區域性變數同名 這時函式內部只調用區域性變數,如果要呼叫全域性變數需要在函式內加一句“global 同名變數”
Spark學習之路 (十一)SparkCore的調優之Spark內存模型
精準 規模 memory 此外 結構定義 申請 管理方式 存儲 內部 摘抄自:https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-apache-spark-memory-management/index
Kubernetes學習之路(十一)之資源清單定義
map latest dem kubectl 服務發現 bject 均衡 ima limit 一、Kubernetes常用資源 以下列舉的內容都是 kubernetes 中的 Object,這些對象都可以在 yaml 文件中作為一種 API 類型來配置。 類別 名稱
《SpringBoot從入門到放棄》之第(十一)篇——使用@Scheduled建立定時任務,cron七子表示式的簡單使用
模擬場景:有時候,你需要每天某個點或者每週、每個月讓程式做一些事情,如呼叫介面獲取資料,比如生成資料的報表,或者統計一些資料之類,你除了可以在資料庫建立儲存過程,還可以寫Java定時任務。 O的K,接著上一篇的開發環境。《SpringBoot從入門到放棄》之第(十)篇 我們建立一個定時任
Python學習之旅(十二)
Python基礎知識(11):高階特性 一、分片(切片) 通過索引來獲取一定範圍內的元素 #字串 s="Alice" s[0:4:2] 結果: 'Ai' #列表 l=[1,2,3,4,5,6] l[0:2] 結果: [1, 2] #元組 t=(1,2,3,"a","b","c"
Python學習之旅(十七)
Python基礎知識(16):面向物件程式設計(Ⅰ) 類和例項 類是抽象的模板 例項是根據類創建出來的一個個具體的物件,每個物件都擁有相同的方法,但各自的資料可能不同。 類可以在建立例項的時候,把一些我們認為必須繫結的屬性強制填寫進去 方法就是與例項繫結的函式,和普通函式不同,方法可以直接訪問例項的
Python學習之旅(十八)
expand red function encode tabs reduce repl nbsp 試圖 Python基礎知識(17):面向對象編程(Ⅱ) 獲取對象信息 在不知道對象信息的情況下,我們想要去獲取對象信息,可以使用以下方法 1、type (1)判斷對象類型 &
Linux 學習之路(十一):壓縮歸檔以及RAID
壓縮、解壓縮命令 壓縮格式:gz,bz2,xz,zip,Z 壓縮演算法不同,壓縮比(壓縮後的大小-壓縮前的大小/壓縮前的大小)可能也會不同。 compress:FILENAME.Z uncompress 只能壓縮檔案,預設會刪除原檔案保留壓縮後文件: gzip
Linux 學習之路(十一):RAID和LVM
傳輸速度 Mb/8=MB 硬碟的介面: IDE(ATA):133Mbps 並行匯流排 SATA:300Mbps,600Mbps,6Gbps 序列匯流排 USB:USB3.0:480Mbps 序列匯流排 SCSI:Small Computer System Int
決戰Python之巔(十一)
前言 本篇將介紹遞迴以及函式的內建方法。 知識回顧 遞迴 之前我們已經講過,函式內部可以呼叫其他函式。如果一個函式在內部呼叫自身,這個函式就是遞迴函式: def func() print('遞迴函式') func() 這就是一個遞迴函式,如果你執行這段程式碼的話
unity官方demo學習之Stealth(十一)角色移動
十一,角色移動 為char_ethan新增指令碼DonePlayerMovement using UnityEngine; using System.Collections; public class DonePlayerMovement : MonoBehaviour
Redis深入之路(十一)
事件 Redis 基於 Reactor 模式開發了自己的網路時間處理器:檔案事件處理器(File Event Handler) 檔案事件處理器基於 I/O 多路複用(multiplexing)程式來同時監聽多個套接字(Socket),並根
Vue 進階之路(十一)
模板 解決 字符 如何解決 效果 height doctype 信息 自定義 之前的文章我們說了一下 vue 中組件的原生事件綁定,本章我們來所以下 vue 中的插槽使用。 1 <!DOCTYPE html> 2 <html lang="en"
Python 爬蟲從入門到進階之路(十一)
之前的文章我們介紹了一下 Xpath 模組,接下來我們就利用 Xpath 模組爬取《糗事百科》的糗事。 之前我們已經利用 re 模組爬取過一次糗百,我們只需要在其基礎上做一些修改就可以了,為了保證專案的完整性,我們重新再來一遍。 我們要爬取的網站連結是 https://www.qiushibai
Salesforce學習之路(十一)Aura元件屬性<aura:attribute />
1. <aura:attribute />語法 Aura元件屬性類似與Apex中類的成員變數(或者說Java中類的成員變數)。他們是元件在特定的例項上設定的型別化欄位,可以使用表示式語法從元件的標記內引用他們。 語法:<aura:attribute name="**" type=
Java 從入門到進階之路(十一)
之前的文章我們介紹了一下 Java 中的繼承,接下來我們繼續看一下 Java 中的繼承。 在有些時候,我們通過類繼承的方式可以獲取父類的方法,但是有些時候父類為我們提供的方法並不完全符合我們的需求,這時候我們就要對類方法進行重寫,如下: 1 public class HelloWorld { 2
十年風雨,一個普通程式設計師的成長之路(十一)再見,2019。你好,2020!
00 回顧2019 在過去的這一年裡,收穫最大的便是眼界了, 與高水平的同事們一起合作,讓人愉快。 與高水平的領導共事,則讓人受益匪淺。 2019年元旦前後那段時間,突然陷入了焦慮,買了一些極客時間的課程,加入了一些知識星球。也確實提升了自己不少關於職場、工作、生活的一些認知。 但是收貨最大的還是在工作之餘,
springboot原始碼解析-管中窺豹系列之BeanFactoryPostProcessor(十一)
# 一、前言 - Springboot原始碼解析是一件大工程,逐行逐句的去研究程式碼,會很枯燥,也不容易堅持下去。 - 我們不追求大而全,而是試著每次去研究一個小知識點,最終聚沙成塔,這就是我們的springboot原始碼管中窺豹系列。 ![ 簡介 ](https://zhangbin1989.gitee.
WebGL之旅(一)canvas、WebGL和shader簡介
一 canvas canvas(翻譯為畫布)是HTML5的一個標籤,canvas可以使用JavaScript在網頁上繪製圖像,例如下面的程式碼就使用canvas繪製一個簡單的矩形。 <!DOCTYPE html> <html lang=