庄懂着色器_L09_Fresnel/Matcap/Cubemap

2023-12-04 14:38

本文主要是介绍庄懂着色器_L09_Fresnel/Matcap/Cubemap,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

庄懂-BoyanTata的个人空间_哔哩哔哩_Bilibili

环境反射的做法有Matcap和Cubemap
菲涅尔现象
菲涅尔连连看部分
Fresnel = pow(1-ndotv,powVal) 下的法线 点乘 世界下的视线
现实中View Dir观察方向和light Dir光方向都是太阳照射到地面上的,但在引擎内View Dir观察方向和lDir光向量都是指向人眼方向的,也可以说是指向光源的
因此View Dir观察方向和lDir光向量在物理上和引擎内效果是相反的
Matcap效果
Matcap连连看部分
金属反射环境是没有中间与边缘的区分
Remap
相当于是一个映射,法线方向点乘光方向输出的值是-1到1之间,我们将-1到1之间的值映射到0到1之间
将点乘的值转换为Lambert输出的操作
菲涅尔 =  世界下的法线 dot 世界下的视向量
法线从切线空间(tangent space)变换到世界空间(world space)再变换到观察空间(view space)
一束光从屏幕的右边打过来,它的中间是黑色,右边的黑色不是0,而是负值,无论怎样旋转视角
为了验证它是一个负数,把它+1再*0.5,直接做一个Remap,它是一个(-1,1)的值,我们将其映射为(0,1)
法线朝左边,从左到右的一个渐变
通道的含义就是它这个表面,法线方向,它在平行于屏幕的轴向上,朝左它就是0.朝右就是1,这是Remap之后的结果
没有Remap之前,朝左就是-1,正对着你是0,朝右是1
绿通道的含义,就是左右的关系,将红通道平行于屏幕的关系变成垂直于屏幕的关系,就变成了一个上下关系,同样去做一个Remap,它也是无论怎样旋转模型或者旋转视角也好,它始终都是在屏幕上的一个上下关系
我们拿到这个 绿通道,做了Remap之后,它就是一个以朝下,法线取0值,法
线朝你取0.5,法线朝你取1
通道是法线朝左取0,法线朝你取0.5,法线朝右取1
把观察空间下View_Space的下的法线取出它的 红绿通道做Remap去采样纹理
通道从左到右依次取值为0,0.5,1
绿通道从下到上依次取值为0,0.5,1
Cubemap效果
简单理解就是一张全景图
Cubemap效果连连看部分
视方向ViewDir不是眼睛射出的光线,而是一个光线射向眼睛的方向
Reflect反射不是要拿视方向ViewDir,而是要拿视方向ViewDir在法线上反弹之后的方向去采样
不是直接去看Cubemap的结果,我们是把自己的视线方向ViewDir经过一面镜子的反弹,然后用那个方向去采样cubemap的结果
将视方向ViewDir先取了一个反, 然后跟法线Normal去做了一次反射Reflect,这样就拿到了一个视方向ViewDir的反弹方向,就可以去查询Cubemap反弹到哪个像素了
HDR的图片很多手机不支持,所以想办法要把HDR的信息编码成LDR的图,就是不超过1的图,有一些方法可以做一下编码,然后在去手机上做一个还原,而且还能保留一个高动态范围的信息,但是它的载体是低动态范围的,是常用手段之一
将SD内导出的HDR贴图(EXR.格式)导入PS,然后勾选 作为Alpha通道,将HDR贴图由长方形改为正方形,之后还是一个高动态范围的状态,在图像>>模式>>改为8位/通道(A),然后贴图整体就变暗了,因为它将原先最亮的地方变成1,最暗的地方变为0,也就是重新做了一下Remap映射,然后保存为TGA格式导出
Cubemap的映射方式Mapping选择为Latitude-Longitue Layout(Cylindrical)
Convolution Type 选择 Specular(Glossy Reflection) 可以生成 Mipmap
远处采样低精度的图,近处采样高精度的图,这也是Mipmap一个常规的用法
但是我们做Cubemap,是利用Mipmap这样一个特性,将不用级别的Mipmap视作不用粗糙度表面对环境的反射
Fixup Edge Seams 修正接缝
Mapcap效果代码部分
i.posWS =  mul(unity_objectToWorld,vertex);  //世界坐标
//世界空间下的视线方向 = 摄像机的位置 - 世界坐标的位置
float3 nDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz); 
Shader "AP01/L09/Matcap"
{Properties{_NormalMap  ("法线贴图", 2D) = "bump" {}_Matcap     ("Matcap", 2D) = "gray" {}_FresnelPow ("菲涅尔次幂", Range(0, 10)) = 1_EnvSpecInt ("环境镜面反射强度", Range(0, 5)) = 1}SubShader{Tags { "RenderType"="Opaque" }Pass{Name "FORWARD"Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma multi_compile_fwdbase_fullshadows#pragma target 3.0// 输入参数uniform sampler2D _NormalMap;uniform sampler2D _Matcap;uniform float _FresnelPow;uniform float _EnvSpecInt;// 输入结构struct VertexInput{float4 vertex   : POSITION;     // 顶点信息float2 uv0      : TEXCOORD0;    // uv信息float3 normal   : NORMAL;       // 法线信息float4 tangent  : TANGENT;      // 切线信息};// 输出结构struct VertexOutput{float4 pos : SV_POSITION;       // 屏幕顶点位置float2 uv0 : TEXCOORD0;         // uv信息float4 posWS : TEXCOORD1;       // 世界顶点位置float3 nDirWS : TEXCOORD2;      // 世界法线方向float3 tDirWS : TEXCOORD3;      // 世界切线方向float3 bDirWS : TEXCOORD4;      // 世界副切线方向};// 输入结构>>>顶点Shader>>>输出结构VertexOutput vert (VertexInput v){VertexOutput o = (VertexOutput)0;           // 新建一个输出结构o.pos = UnityObjectToClipPos( v.vertex );o.uv0 = v.uv0;                                  // 传递uv信息o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 顶点位置 OS>WSo.nDirWS = UnityObjectToWorldNormal(v.normal);  // 法线方向 OS>WSo.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 切线方向 OS>WSo.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);  // 根据nDir tDir求bDirreturn o;                                   // 将输出结构 输出}// 输出结构>>>像素float4 frag(VertexOutput i) : COLOR{// 准备向量float3 nDirTS = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb;float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);float3 nDirWS = normalize(mul(nDirTS, TBN));        // 计算nDirVS 计算Fresnelfloat3 nDirVS = mul(UNITY_MATRIX_V, nDirWS);        // 计算MatcapUVfloat3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz); // 计算Fresnel// 准备中间变量float vdotn = dot(vDirWS, nDirWS);float2 matcapUV = nDirVS.rg * 0.5 + 0.5;// 光照模型float3 matcap = tex2D(_Matcap, matcapUV);float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);float3 envSpecLighting = matcap * fresnel * _EnvSpecInt;// 返回值return float4(envSpecLighting, 1.0);}ENDCG}}FallBack "Diffuse"
}
Cubemap代码部分
采样Cubemap要用texCUBElod
采样的UV坐标必须是四维的,float4(vrDirWS,_CubemapMip)
Shader "AP01/L09/Cubemap"
{Properties{_Cubemap    ("环境球", Cube) = "_Skybox" {}_NormalMap  ("法线贴图", 2D) = "bump" {}_CubemapMip ("环境球Mip", Range(0, 7)) = 0_FresnelPow ("菲涅尔次幂", Range(0, 5)) = 1_EnvSpecInt ("环境镜面反射强度", Range(0, 5)) = 0.2}SubShader{Tags { "RenderType"="Opaque" }Pass{Name "FORWARD"Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma multi_compile_fwdbase_fullshadows#pragma target 3.0// 输入参数uniform samplerCUBE _Cubemap;uniform sampler2D _NormalMap;uniform float _CubemapMip;uniform float _FresnelPow;uniform float _EnvSpecInt;// 输入结构struct VertexInput{float4 vertex   : POSITION;     // 顶点信息float2 uv0      : TEXCOORD0;    // uv信息float3 normal   : NORMAL;       // 法线信息float4 tangent  : TANGENT;      // 切线信息};// 输出结构struct VertexOutput{float4 pos : SV_POSITION;       // 屏幕顶点位置float2 uv0 : TEXCOORD0;         // uv信息float4 posWS : TEXCOORD1;       // 世界顶点位置float3 nDirWS : TEXCOORD2;      // 世界法线方向float3 tDirWS : TEXCOORD3;      // 世界切线方向float3 bDirWS : TEXCOORD4;      // 世界副切线方向};// 输入结构>>>顶点Shader>>>输出结构VertexOutput vert (VertexInput v){VertexOutput o = (VertexOutput)0;           // 新建一个输出结构o.pos = UnityObjectToClipPos( v.vertex );o.uv0 = v.uv0;                                  // 传递uv信息o.posWS = mul(unity_ObjectToWorld, v.vertex);   // 顶点位置 OS>WSo.nDirWS = UnityObjectToWorldNormal(v.normal);  // 法线方向 OS>WSo.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 切线方向 OS>WSo.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);  // 根据nDir tDir求bDirreturn o;                                   // 将输出结构 输出}// 输出结构>>>像素float4 frag(VertexOutput i) : COLOR{// 准备向量float3 nDirTS = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb;float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);float3 nDirWS = normalize(mul(nDirTS, TBN));   // 计算Fresnel 计算vrDirWSfloat3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);  // 计算Fresnelfloat3 vrDirWS = reflect(-vDirWS, nDirWS);// 采样Cubemap// 准备中间变量float vdotn = dot(vDirWS, nDirWS);// 光照模型float3 var_Cubemap = texCUBElod(_Cubemap, float4(vrDirWS, _CubemapMip)).rgb;float fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow);float3 envSpecLighting = var_Cubemap * fresnel * _EnvSpecInt;// 返回值return float4(envSpecLighting, 1.0);}ENDCG}}FallBack "Diffuse"
}
World Reflection

这篇关于庄懂着色器_L09_Fresnel/Matcap/Cubemap的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/453825

相关文章

OpenGL——着色器画一个点

一、 绘制 在窗口中间画一个像素点: #include <GL/glew.h>#include <GLFW/glfw3.h>#include <iostream>using namespace std;#define numVAOs 1GLuint renderingProgram;GLuint vao[numVAOs];GLuintcreateShaderProgram (){c

学习使用RenderDoc查看着色器代码

0. 准备 首先,我想要一个相对简单的程序来学习。因此,我选择了 DX11官方范例(包含在DirectX11官方SDK中)里的【Tutorial 07: Texture Mapping and Constant 】 需要安装工程,编译出exe,然后将着色器文件(Tutorial07.fx)和贴图文件(seafloor.dds)放到exe的同级目录。随后应该可以打开exe: 1. 截一帧

图形API学习工程(24):D3D11读取非DDS格式的CubeMap

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 在《图形API学习工程(21):使用CubeMap纹理》中,由于DirectX读取CubeMap的教程范例都是DDS格式的纹理,因此我也首先实现了DDS的版本,期望之后做处理。 上一篇使D3D12可以用非DDS格式的CubeMap了,本篇目标将是D3D11。 分析当前的流程 当前使用D

glsl着色器学习(九)屏幕像素空间和设置颜色

在上一篇文章中,使用的是裁剪空间进行绘制,这篇文章使用屏幕像素空间的坐标进行绘制。 上一篇的顶点着色器大概是这样子的 回归一下顶点着色的主要任务:  通常情况下,顶点着色器会进行一系列的矩阵变换操作,将输入的顶点坐标从模型空间依次经过世界空间,视图空间,最终转换到裁剪空间。 将顶点着色器改成下面这样: <script id="vertex-shader-2d" type="x-sh

glsl着色器学习(十)缩放

对二维图形进行缩放,需要用到顶点着色器,顶点着色器经过矩阵变换,会将模型空间最终转换成裁剪空间。下面就来操作矩阵 这里需要用到一个库glMatrix。 首先修改顶点着色器 <script id="vertex-shader-2d" type="x-shader/x-vertex">attribute vec4 a_position;uniform mat4 u_matrix;void m

glsl着色器学习(六点五)顶点和片元的处理顺序

在WebGL中,顶点和片元的处理顺序遵循着图形渲染管线的流程。 顶点处理阶段 顶点处理阶段是图形渲染管线的起点,在这一阶段,所有与顶点相关的操作都会被执行。 顶点着色器(Vertex Shader) 顶点着色器接收每个顶点的数据,例如顶点坐标,法线,纹理坐标等。将顶点数据上传到图形硬件的缓冲区。在顶点着色器中,对这些顶点数据进行变换和运算,例如将顶点从模型空间转换到世界空间、视图空间和

three.js 编辑器,动画,着色器, cesium 热力图,聚合点位,大量点线面, 图层,主题,文字

对于大多数的开发者来言,看了很多文档可能遇见不到什么有用的,就算有用从文档上看,把代码复制到自己的本地大多数也是不能用的,非常浪费时间和学习成本, 尤其是three.js , cesium.js 这种难度较高, 想要实现一个功能可能会查阅很多博客 ,进行很多错误尝试,费时费力。 所以,话不多说为了给各位造福利,我搭建了在线查看代码且可的调试系统,所有案例可直接访问,让你欣赏 什么叫做 - 优雅永

Vulkan教程 - 08 着色器及编译SPIR-V

着色器模块 不像是之前的API,Vulkan着色器代码一定要用字节码格式,而不是人类可读的语法如GLSL和HLSL。这个字节码就是SPIR-V,设计用于Vulkan和OpenCL。这是一个可以用于编写图形和计算着色器的格式,但是我们主要关注的是Vulkan的图形管线。使用字节码格式的优点之一是GPU厂商写的编译器将着色器代码转化为原生代码会非常简单。过去的经验表明,人类易读的语法如GLSL,某些

[OpenGL ES 3.0编程指南]4 着色器和程序

介绍创建着色器,编译它们并链接到一个程序对象。 4.1 着色器和程序 源代码提供给着色器对象,然后着色器对象被编译为一个目标文件,编译后可以连接到一个程序对象。程序对象可以连接多个着色器对象。在OpenGL ES中,每个程序对象必须连接一个顶点着色器和一个片段着色器。一般包含6个步骤: 1.创建一个顶点着色器和一个片段着色器对象 2.将源代码连接到每个着色器对象 3.编译着色器对象 4.创建一

【Cesium学习】着色器详解【待进一步总结】

在Cesium中,drawCommand 和 CustomShader 是与渲染管线和自定义渲染效果相关的两个重要概念,但它们各自有不同的作用和应用场景。下面我将分别详解这两个概念。 drawCommand drawCommand 是 Cesium 渲染引擎内部使用的一个概念,它代表了单个渲染命令,通常包含了一组需要被WebGL API绘制的顶点和相应的渲染状态(如着色器程序、材质属性等)。在