LearnOpenGL-筆記-其十一

Normal Mapping

又到了介紹法線貼圖的地方,我感覺我已經寫了很多遍了...

法線貼圖用最簡單的話來介紹的話,就是通過修改貼圖對應物體表面的法線來修改光照效果,從而在不修改物體實際幾何形狀的前提下實現不同于物體幾何形狀的視覺效果。

因此對于法線貼圖來說,最重要的內容就是去修改法線貼圖對于物體表面的法線。

  vec3 normal = texture(normalMap, TexCoords).rgb;normal = normalize(normal * 2.0 - 1.0);normal = normalize(TBN * normal);

這是我們在物體的片元著色器實現的內容,就是根據法線貼圖的內容更換法線。

在這里我們不妨回顧一下法線貼圖的原理:

法線貼圖的“藍色”就代表“正對表面外”,紅色/綠色代表“沿U/V方向偏轉”,整個流程無非就是:法線貼圖以RGB值來記錄對法線方向的干擾,這個干擾是在切線空間中進行的,我們還需要TBN矩陣——這個工具來將變換后的法線映射回世界坐標系中。

效果如圖:

看起來確實有凹凸不平的質感——但其實,這只是薄薄的一個平面生成的效果。

Parallax Mapping

視差貼圖和法線貼圖類似也是也是不改變物體實際幾何形狀的前提下去修改視覺效果,可是和法線貼圖直接去修改法線方向不同,視差貼圖通過動態偏移紋理坐標實現高度不同的視覺效果。

vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{ float height =  texture(depthMap, texCoords).r;     return texCoords - viewDir.xy * (height * heightScale);        
}void main()
{           // offset texture coordinates with Parallax Mappingvec3 viewDir = normalize(fs_in.TangentViewPos - fs_in.TangentFragPos);vec2 texCoords = fs_in.TexCoords;texCoords = ParallaxMapping(fs_in.TexCoords,  viewDir);       if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)discard;// obtain normal from normal mapvec3 normal = texture(normalMap, texCoords).rgb;normal = normalize(normal * 2.0 - 1.0);   // get diffuse colorvec3 color = texture(diffuseMap, texCoords).rgb;// ambientvec3 ambient = 0.1 * color;// diffusevec3 lightDir = normalize(fs_in.TangentLightPos - fs_in.TangentFragPos);float diff = max(dot(lightDir, normal), 0.0);vec3 diffuse = diff * color;// specular    vec3 reflectDir = reflect(-lightDir, normal);vec3 halfwayDir = normalize(lightDir + viewDir);  float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);vec3 specular = vec3(0.2) * spec;FragColor = vec4(ambient + diffuse + specular, 1.0);
}

可以看到我們的視差貼圖會根據深度貼圖的R值來修改原來紋理坐標,在片元著色器的執行流程中,我們的紋理會根據視線方向來動態地調整根據深度貼圖的R值修改過的紋理坐標,從而達到視覺落差的效果。

說起來當然很簡單,但是其背后的工作原理呢?

移花接木,貍貓換太子,臥槽這個視差貼圖怎么這么壞啊。?用比較簡單的話來說就是:首先我們的視線看向這個片元時,視線真正與物體表面的交點在A點,但是我們在A點的著色渲染成B點的顏色的話,不就實現了紋理坐標的偏移,從而實現視覺落差的效果了。這個B點是怎么得到的呢?就是根據我們的視差貼圖修改該片元的高度值后與視線相交得到的。

陡峭視差映射(Steep Parallax Mapping)是視差映射的擴展,原則是一樣的,但不是使用一個樣本而是多個樣本來確定向量。即使在陡峭的高度變化的情況下,它也能得到更好的結果,原因在于該技術通過增加采樣的數量提高了精確性。

陡峭視差映射的基本思想是將總深度范圍劃分為同一個深度/高度的多個層。從每個層中我們沿著向量方向移動采樣紋理坐標,直到我們找到一個采樣低于當前層的深度值。

其實就是我們多很多個深度層,然后將視線和這些深度層的交點與深度貼圖的深度值一一比較,找到第一個符合深度貼圖的深度大于交點深度值的深度層,把這個深度層與視線的交點對于的深度值作為我們的紋理顏色渲染對象即可。

代碼上這樣改動:

vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{ // number of depth layersconst float minLayers = 8;const float maxLayers = 32;float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));  // calculate the size of each layerfloat layerDepth = 1.0 / numLayers;// depth of current layerfloat currentLayerDepth = 0.0;// the amount to shift the texture coordinates per layer (from vector P)vec2 P = viewDir.xy / viewDir.z * heightScale; vec2 deltaTexCoords = P / numLayers;// get initial valuesvec2  currentTexCoords     = texCoords;float currentDepthMapValue = texture(depthMap, currentTexCoords).r;while(currentLayerDepth < currentDepthMapValue){// shift texture coordinates along direction of PcurrentTexCoords -= deltaTexCoords;// get depthmap value at current texture coordinatescurrentDepthMapValue = texture(depthMap, currentTexCoords).r;  // get depth of next layercurrentLayerDepth += layerDepth;  }return currentTexCoords;
}

效果如圖:

在這個基礎上可以實現效果更好的視差遮蔽映射(Parallax Occlusion Mapping),只需要多加一個線性插值的操作即可。

vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{ // number of depth layersconst float minLayers = 8;const float maxLayers = 32;float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));  // calculate the size of each layerfloat layerDepth = 1.0 / numLayers;// depth of current layerfloat currentLayerDepth = 0.0;// the amount to shift the texture coordinates per layer (from vector P)vec2 P = viewDir.xy / viewDir.z * heightScale; vec2 deltaTexCoords = P / numLayers;// get initial valuesvec2  currentTexCoords     = texCoords;float currentDepthMapValue = texture(depthMap, currentTexCoords).r;while(currentLayerDepth < currentDepthMapValue){// shift texture coordinates along direction of PcurrentTexCoords -= deltaTexCoords;// get depthmap value at current texture coordinatescurrentDepthMapValue = texture(depthMap, currentTexCoords).r;  // get depth of next layercurrentLayerDepth += layerDepth;  }// get texture coordinates before collision (reverse operations)vec2 prevTexCoords = currentTexCoords + deltaTexCoords;// get depth after and before collision for linear interpolationfloat afterDepth  = currentDepthMapValue - currentLayerDepth;float beforeDepth = texture(depthMap, prevTexCoords).r - currentLayerDepth + layerDepth;// interpolation of texture coordinatesfloat weight = afterDepth / (afterDepth - beforeDepth);vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);return finalTexCoords;
}

效果如圖:

HDR

上來都是一些介紹HDR高動態范圍概念的文字,我覺得這個翻譯實在廢話有點多,說白了HDR就是解決攝像設備里人為設置的亮度范圍導致的過亮或者過暗時丟失的細節的機制:它允許你短暫地突破這個亮度范圍,在捕獲到細節后再將這些帶有細節的圖像融合在一起之后調整亮度到范圍內。

很好,明白原理之后讓我們深入細節。

首先我們需要一個浮點數類型的幀緩沖:

// 創建浮點幀緩沖
unsigned int hdrFBO;
glGenFramebuffers(1, &hdrFBO);

然后我們還涉及到色調映射(Tonemapping)和曝光調整(Exposure)。

// 2. now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range
hdrShader.use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffer);
hdrShader.setInt("hdr", hdr);
hdrShader.setFloat("exposure", exposure);
renderQuad();
#version 330 core
out vec4 FragColor;in vec2 TexCoords;uniform sampler2D hdrBuffer; // HDR幀緩沖的顏色紋理
uniform bool hdr;            // 是否啟用HDR色調映射
uniform float exposure;      // 曝光度void main()
{             const float gamma = 2.2;vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb; // 采樣HDR顏色if(hdr){// Reinhard色調映射(被注釋掉了)// vec3 result = hdrColor / (hdrColor + vec3(1.0));// 曝光色調映射vec3 result = vec3(1.0) - exp(-hdrColor * exposure);// Gamma校正result = pow(result, vec3(1.0 / gamma));FragColor = vec4(result, 1.0);}else{// 只做Gamma校正,不做色調映射vec3 result = pow(hdrColor, vec3(1.0 / gamma));FragColor = vec4(result, 1.0);}
}

效果如圖:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82105.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82105.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82105.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot 讀取.env文件獲取配置

Spring Boot 讀取.env文件獲取配置 在Resouce 目錄下創建.env文件 # DEEP SEEK TOKEN DEEP_SEEK_TOKENyour_deep_seek_key # 阿里云百煉 TOKEN ALI_BAILIAN_TOKENyour_ali_bailian_keyyml引入.env文件 spring:config:import: optional:classpath:.env[.properties]使用.env文…

【C++高級主題】命令空間(三):未命名的命名空間

目錄 一、未命名的命名空間的基本概念 1.1 定義與特點 1.2 基本語法 1.3 訪問方式 1.4 未命名的命名空間的作用 二、未命名的命名空間與靜態聲明的比較 2.1 靜態聲明的作用 2.2 未命名的命名空間的優勢 2.3 示例代碼比較 2.4. 未命名的命名空間的作用域和鏈接屬性 三…

【Unity】AudioSource超過MaxDistance還是能聽見

unity版本&#xff1a;2022.3.51f1c1 將SpatialBlend拉到1即可 或者這里改到0 Hearing audio outside max distance - #11 by wderstine - Questions & Answers - Unity Discussions

多個vue2工程共享node_modules

手頭有多個vue2項目&#xff0c;它們每個都需要一個node_modules&#xff0c;拷貝起來超級麻煩。于是想到能否共享一個node_modules呢&#xff1f;&#xff1f; 方法其實挺多&#xff0c;我選擇了一個較簡單的&#xff1a;符號連接法(win11平臺) 創建方法很簡單&#xff1a;比…

C語言-10.字符串

10.1字符串 10.1-1字符串 字符數組 char word[] = {‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; word[0]Hword[1]eword[2]lword[3]lword[4]oword[5]!這不是C語言的字符串,因為不能用字符串的方式做計算 字符串 char word[] = {‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; word[0]Hwo…

Python訓練營打卡Day41(2025.5.31)

知識回顧 數據增強卷積神經網絡定義的寫法batch歸一化&#xff1a;調整一個批次的分布&#xff0c;常用與圖像數據特征圖&#xff1a;只有卷積操作輸出的才叫特征圖調度器&#xff1a;直接修改基礎學習率 卷積操作常見流程如下&#xff1a; 1. 輸入 → 卷積層 → Batch歸一化層…

樂觀鎖:高效并發無鎖方案

4.樂觀鎖 這一章主要介紹樂觀鎖。前面的管程部分講了悲觀鎖&#xff0c;現在做一些總結&#xff1a; 悲觀鎖&#xff08;Pessimistic Lock&#xff09;&#xff1a;悲觀鎖認為數據在多線程或多進程環境下總是容易發生沖突/沖突的概率高&#xff0c;所以在數據操作前&#xff…

山海鯨輕 3D 渲染技術深度解析:預渲染如何突破多終端性能瓶頸

在前期課程中&#xff0c;我們已系統講解了山海鯨兩大核心渲染模式——云渲染與端渲染的技術特性及配置方法。為滿足復雜場景下的差異化需求&#xff0c;山海鯨創新推出輕3D渲染功能&#xff0c;本文將深度解析該技術的實現原理與操作實踐。 一、輕3D功能研發背景 針對多終端協…

【合集】Linux——31個普通信號

Linux普通信號總表&#xff08;1-31&#xff09;?? ?編號??信號名??觸發原因??默認動作?1SIGHUP終端連接斷開&#xff08;如SSH會話終止&#xff09;或守護進程重載配置&#xff08;如nginx -s reload&#xff09;終止進程2SIGINT用戶輸入CtrlC中斷前臺進程終止進程…

小程序使用npm包的方法

有用的鏈接 npm init -y 這個命令很重要, 會初始化 package.json 再重新打開微信小程序開發工具 選擇工具中npm構建 在程序中引用時在main.js中直接使用包名的方式引用即可 如安裝的是generator包&#xff0c;npm構建后就會生成 const myPackage require(***-generato…

騰訊云推出云開發AI Toolkit,國內首個面向智能編程的后端服務

5月28日&#xff0c;騰訊云開發 CloudBase 宣布推出 AI Toolkit&#xff08;CloudBase AI Toolkit&#xff09;&#xff0c;這是國內首個面向智能編程的后端服務&#xff0c;適配 Cursor 等主流 AI 編程工具。 云開發 AI Toolkit旨在解決 AI 輔助編程的“最后一公里”問題&…

系統是win11+兩個ubuntu,ubuntu20.04和ubuntu22.04,想刪除ubuntu20.04且不用保留數據

在 Ubuntu 22.04 的終端里運行這些命令: 重啟電腦&#xff0c;選擇啟動 Ubuntu 22.04&#xff1b;打開終端&#xff1b;從 lsblk 開始操作。 如果你不確定當前啟動的是哪個系統&#xff0c;可以在終端輸入&#xff1a; lsb_release -a它會輸出&#xff1a; Distributor ID: …

大模型應用開發第三講:大模型是Agent的“大腦”,提供通用推理能力(如GPT-4、Claude 3)

大模型應用開發第三講&#xff1a;大模型是Agent的“大腦”&#xff0c;提供通用推理能力&#xff08;如GPT-4、Claude 3&#xff09; 資料取自《大模型應用開發&#xff1a;動手做AI Agent 》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的…

第十四篇:MySQL 運維中的故障場景還原與排查實戰技巧

本篇通過典型故障場景的還原與分析&#xff0c;幫助你掌握高效、系統的 MySQL 故障排查與應急處理方法&#xff0c;構建穩定可靠的數據庫運維體系。 一、故障排查的基本思路 快速定位問題入口&#xff1a; 錯誤日志、連接報錯、監控告警&#xff1b; 確認影響范圍&#xff1a…

MySQL 分頁查詢優化

目錄 前言1. LIMIT offset, count 的性能陷阱&#xff1a;為什么它慢&#xff1f;&#x1f629;2. 優化策略一&#xff1a;基于排序字段的“跳躍式”查詢 (Seek Method) &#x1f680;3. 優化策略二&#xff1a;利用子查詢優化 OFFSET 掃描 (ID Subquery)4. 基礎優化&#xff1…

使用curlconverter網站快速生成requests請求包

在python寫requests請求的時候&#xff0c;抓包后需要復制粘貼包的內容&#xff0c;然后手動修改和寫代碼。 最近發現一個好的網站 https://curlconverter.com/python/ 可以復制curl(bash)數據后&#xff0c;直接生成數據包&#xff0c;非常便捷。 舉例說明&#xff1a; 選…

python打卡day41

簡單CNN 知識回顧 數據增強 卷積神經網絡定義的寫法 batch歸一化&#xff1a;調整一個批次的分布&#xff0c;常用與圖像數據 特征圖&#xff1a;只有卷積操作輸出的才叫特征圖 調度器&#xff1a;直接修改基礎學習率 卷積操作常見流程如下&#xff1a; 1. 輸入 → 卷積層 →…

系統思考:化繁為簡的藝術

系統思考&#xff0c;其實是一門化繁為簡的藝術。當我們能夠把復雜的問題拆解成清晰的核心以及更加簡單&#xff0c;從而提升團隊的思考品質和行動品質&#xff0c;發揮最大的合力。 每個公司都想在某方面成為最優秀的&#xff0c;但是實際上具有穿透性的洞察力和擺脫虛榮心的清…

2025.05.28【Parallel】Parallel繪圖:擬時序分析專用圖

Improve general appearance Add title, use a theme, change color palette, control variable orders and more Highlight a group Highlight a group of interest to help people understand your story 文章目錄 Improve general appearanceHighlight a group探索Paralle…

Elasticsearch父子關系解析

引言 在復雜業務場景中&#xff0c;數據關聯查詢是搜索與分析的核心需求。以電商訂單、文章評論、客戶關系等場景為例&#xff0c;傳統關系型數據庫通過外鍵實現的多表關聯&#xff0c;在分布式搜索場景下面臨性能與擴展性挑戰。Elasticsearch通過父子關系&#xff08;Parent-…