1. 程式人生 > >WebGL之旅(十一)透視投影

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.

WebGLcanvas、WebGL和shader簡介

一 canvas canvas(翻譯為畫布)是HTML5的一個標籤,canvas可以使用JavaScript在網頁上繪製圖像,例如下面的程式碼就使用canvas繪製一個簡單的矩形。 <!DOCTYPE html> <html lang=