Unity3d Shader篇(七)— 纹理采样

文章目录

  • 前言
  • 一、什么是纹理采样?
    • 1. 纹理采样的工作原理
    • 2. 纹理采样的优缺点
      • 优点
      • 缺点
  • 二、使用步骤
    • 1. Shader 属性定义
    • 2. SubShader 设置
    • 3. 渲染 Pass
    • 4. 定义结构体和顶点着色器函数
    • 5. 片元着色器函数
  • 三、效果
  • 四、总结
    • 使用场景


前言

纹理采样是一种常用的图形学技术,它可以让我们在渲染物体表面时,使用一张图片来提供颜色信息,从而增强物体的细节和真实感。在本文中,我们将介绍纹理采样的基本概念,原理和实现方法,以及在 Unity Shader 中如何使用纹理采样来实现一个简单的高光反射着色器。


一、什么是纹理采样?

1. 纹理采样的工作原理

纹理采样,就是通过 uv 获取贴图对应位置的颜色。uv 是一种二维坐标系,它的取值范围是 [0,1],表示了贴图上的相对位置。例如,uv 值是 (0.5,0.5),此时采样到的就是贴图中心点的颜色值。

在 Unity Shader 中,我们可以使用 tex2D 函数来进行纹理采样,它的参数有两个,一个是纹理对象,一个是 uv 坐标,它的返回值是一个 fixed4 类型的颜色值,表示了纹理上的纹素(texel)的颜色。例如:

fixed4 col = tex2D (_MainTex, i.uv);

这段代码表示,从 _MainTex 这个纹理对象中,采样 i.uv 这个坐标处的颜色,赋值给 col 变量。

2. 纹理采样的优缺点

优点

可以大大提高物体表面的细节和真实感,使物体看起来更加美观和逼真。
可以减少顶点数据的传输和处理,提高渲染效率和性能。
可以灵活地调整和修改物体表面的颜色和效果,不需要重新编译着色器或者修改代码。

缺点

需要占用额外的内存空间和带宽,增加资源的加载和管理的开销。
需要考虑纹理的分辨率和质量,以及纹理坐标的映射和过滤,避免出现失真和锯齿的现象。
需要考虑纹理的环绕和过滤模式,以及纹理的压缩和优化,以适应不同的渲染需求和设备。

二、使用步骤

1. Shader 属性定义

// 定义属性
Properties
{_MainTex("MainTex",2D)="white"{}_Diffuse("Diffuse",Color)=(1,1,1,1) // 漫反射颜色属性,默认白色_Specular("Specular",Color)=(1,1,1,1) // 高光颜色属性,默认白色_Gloss("Gloss",Range(1,256))=5 // 高光反射系数
}

这段代码定义了Shader的属性,其中:
_MainTex: 表示图片属性,它的默认值是白色,表示如果没有指定贴图,就使用白色填充。
_Diffuse: 表示漫反射颜色属性,使用RGBA格式表示颜色,默认为白色 (1, 1, 1, 1)。
_Specular: 表示高光颜色属性,同样使用RGBA格式表示颜色,默认为白色 (1, 1, 1, 1)。
_Gloss: 表示高光反射系数属性,使用Range声明范围为1到256,默认值为5。

2. SubShader 设置

SubShader
{Tags{"RenderType" = "Opaque" // 渲染类型为不透明}LOD 100 // 细节级别
}

SubShader 定义了一组渲染设置,包括标签和细节级别。在这里,我们将渲染类型标签设置为 “Opaque”,表示物体是不透明的。

3. 渲染 Pass

Pass
{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"
}

这里开始了渲染 Pass 部分。在这里,我们使用了 CGPROGRAM 指令来声明顶点着色器和片元着色器函数。#pragma vertex vert 和 #pragma fragment frag 分别指定了顶点着色器函数和片元着色器函数的名称。

然后,我们包含了 UnityCG.cginc 和 Lighting.cginc,它们提供了许多有用的函数和宏,用于简化编写 Shader。

4. 定义结构体和顶点着色器函数

// 定义结构体:从顶点到片元的数据传递
struct v2f
{float4 vertex:SV_POSITION; // 顶点位置fixed3 worldNormal:TEXCOORD0; // 世界空间法线fixed3 worldPos:TEXCOORD1;// 世界空间位置float2 uv:TEXCOORD2;
};// 顶点着色器函数
v2f vert(appdata_base v)
{v2f o;o.vertex = UnityObjectToClipPos(v.vertex); // 顶点位置变换到裁剪空间fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); // 世界空间法线o.worldNormal = worldNormal;//让外面的属性可以影响到uv//o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;//uv计算简化函数o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);o.worldPos=mul(unity_ObjectToWorld,v.vertex);return o;
}

顶点着色器的输入是一个结构体 appdata_base ,它包含了顶点的位置和法线信息等。顶点着色器的输出是一个结构体 v2f ,它包含了顶点的裁剪空间位置和世界空间法线和位置信息等。

顶点着色器的主要逻辑是:

  1. 使用 UnityObjectToClipPos 函数,将顶点的位置从对象空间变换到裁剪空间,这是渲染管线的必要步骤。

  2. 使用 UnityObjectToWorldNormal 函数,将顶点的法线从对象空间变换到世界空间,这是为了计算光照效果所需的方向向量。

  3. 使用 TRANSFORM_TEX 函数,将顶点的贴图坐标根据 _MainTex_ST 的值进行缩放和偏移,这是为了让贴图的属性可以影响到贴图的显示。

  4. 使用 unity_ObjectToWorld 矩阵,将顶点的位置从对象空间变换到世界空间,这是为了计算光照效果所需的坐标系。

5. 片元着色器函数

// 片元着色器函数
fixed4 frag(v2f i) : SV_Target
{//获取环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//纹理采样fixed3 albedo = tex2D(_MainTex, i.uv).rgb;//漫反射fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * max(0, dot(worldLightDir, i.worldNormal) * 0.5 + 0.5);// 高光反射// 计算视角方向fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));// 计算半向量fixed3 halfDir = normalize(worldLightDir + viewDir);// 计算高光颜色   fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(i.worldNormal, halfDir)), _Gloss);// 组合最终颜色fixed3 color = diffuse + ambient + specular;return fixed4(color, 1); // 输出颜色
}

片元着色器的输入是一个结构体 v2f ,它包含了顶点的裁剪空间位置和世界空间法线和位置信息。片元着色器的输出是一个 fixed4 类型的颜色值,它表示了片元的颜色。

片元着色器的主要逻辑是:

  1. 使用 UNITY_LIGHTMODEL_AMBIENT 宏,获取环境光的颜色,这是 Phong 光照模型的第一个分量。

  2. 使用 tex2D 函数,对 _MainTex 进行纹理采样,根据 i 的 uv 值获取对应的像素颜色,它是物体的表面颜色。

  3. 使用 UnityWorldSpaceLightDir 函数,获取光源的方向向量,这是为了计算漫反射和高光效果所需的角度。

  4. 使用 _LightColor0 和 _Diffuse 变量,获取光源的颜色和物体的漫反射颜色,然后使用 max 和 dot 函数,计算光源和法线的夹角的余弦值,然后乘以 0.5 并加上 0.5,这是为了将 [-1, 1] 的范围映射到 [0, 1] 的范围,这是 Phong 光照模型的第二个分量

  5. 使用 UnityWorldSpaceViewDir 函数,根据 i 的 worldPos 值获取视线的方向向量,这是为了计算高光效果所需的角度。

  6. 使用 normalize 函数,计算视线方向和光源方向的半向量,这是为了简化高光效果的计算。

  7. 使用 _LightColor0 和 _Specular 变量,获取光源的颜色和物体的高光颜色,然后使用 max 和 dot 函数,计算法线和半向量的夹角的余弦值,然后使用 pow 函数,根据 _Gloss 的值计算高光的强度,这是 Phong 光照模型的第三个分量。

  8. 将环境光、漫反射和高光的颜色相加,得到最终的光照颜色,作为片元着色器的输出。

三、效果

在这里插入图片描述

四、总结

纹理采样是从一张纹理图片中获取颜色值的过程,它需要指定一个纹理坐标(uv)和一个采样器(sampler)。采样器定义了纹理的过滤方式(filter)和寻址模式(wrap)。过滤方式决定了当纹理坐标不是整数时,如何插值得到颜色值,常见的有邻近点(point)、线性(linear)和各向异性(anisotropic)三种。寻址模式决定了当纹理坐标超出[0,1]范围时,如何处理边界情况,常见的有重复(repeat)、钳位(clamp)、边框(border)和镜像(mirror)四种。

使用场景

纹理采样的应用场景非常广泛,几乎所有的图形渲染都会用到纹理采样。例如:
基础颜色:我们可以使用一张彩色图片作为纹理,来为物体表面提供基础的颜色信息,从而使物体看起来更加丰富和多样。
法线贴图:我们可以使用一张法线图片作为纹理,来为物体表面提供法线信息,从而使物体看起来更加凹凸和立体。
高光贴图:我们可以使用一张灰度图片作为纹理,来为物体表面提供高光信息,从而使物体看起来更加光滑和反光。
遮罩贴图:我们可以使用一张黑白图片作为纹理,来为物体表面提供遮罩信息,从而使物体看起来更加复杂和多层次。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/694412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打造智能物品租赁平台:Java与SpringBoot的实践

✍✍计算机编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java实战 |…

力扣:869. 重新排序得到 2 的幂

枚举和回溯 1.先把int值转换成char数组,之后再用回溯来枚举出全部的排列顺序,在回溯排列过程中要防止同一个数据的重新使用,同时要计算排列中的数字总和,在进行判断这个数据是否是2的幂,使用递归的方式进行&#xff0…

SparkSQL学习01

目录 1.SparkSQL特点1.1易整合1.2统一的数据访问1.3兼容Hive1.4标准的数据连接 2 SparkSQL编程模型DataFrameDataSet2.1 SQL2.2 DataFrame是什么2.3 DataSet是什么2.4 RDD,DataSet,DataFrame 3 SparkSQL核心编程3.1 编程入口3.2 SparkSQL基本编程3.2.1编…

掌握web控件定位技巧,提升页面操作效率!

简介 在做 Web 自动化时,最根本的就是操作页面上的元素,首先要能找到这些元素,然后才能操作这些元素。工具或代码无法像测试人员一样用肉眼来分辨页面上的元素。那么要如何定位到这些元素,本章会介绍各种定位元素的方法。 web 控…

15. 三数之和 - 力扣(LeetCode)

题目描述 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组…

用Python编写计算字母或数字个数的程序

小编简单写了一个实现计算字母数字的程序 实例代码: str_n input("输入一段文本:") int_n 0 zimu_n 0 qita_n 0for i in str_n:if i.isdigit():int_n 1elif i.isalpha():zimu_n 1else:qita_n 1 # 其他字符(包括空格、标点…

人脸比对-欧氏距离

欧氏距离人脸比对 欧氏距离判断是否同一人脸 embedding_reshape np.array(face.embedding).reshape((1, -1)) face.embedding_normalize preprocessing.normalize(embedding_reshape) # 欧式距离 diffnp.subtract( self.fixed_face.embedding_normalize,face.embedding_nor…

P9063 [yLOI2023] 分解只因数

题目描述 给定一个正整数 n,对 n 分解质因数。 设 np1​p2​p3​⋯px​,其中 pi​ 均为质数。 如果 pi​ 均为奇数,则称 n 为『只因数』。 现在,给出若干个 n,请你判断 n 是不是『只因数』。 输入格式 本题单测试…

Ant Design Pro 快速入门

文章目录 为什么要学习 Ant Design Pro视频教程未来规划 为什么要学习 Ant Design Pro Ant Design Pro 作为阿里巴巴开源的前端优秀项目,开箱即用,从技术新颖程度和架构设计,都非常值得学习。 作为后端为主要技术栈的同学,越好上…

【前端】前端三要素之DOM

写在前面:本文仅包含DOM内容,JavaScript传送门在这里,BOM传送门在这里。 本文内容是假期中刷的黑马Pink老师视频(十分感谢Pink老师),原文保存在个人的GitLab中,如果需要写的网页内容信息等可以评…

ORA-600 kclchkblk_4和2662故障---惜分飞

有客户恢复请求:由于未知原因导致aix环境的rac两台主机同时重启之后数据库无法正常启动,初步判断是由于写丢失导致故障(ORA-00742 ORA-00353) Wed Feb 21 09:23:06 2024 ALTER DATABASE OPEN This instance was first to open Abort recovery for domain…

vue3 + ts + echart 实现柱形图表

首先封装Echart一个文件 代码如下 <script setup lang"ts"> import { ECharts, EChartsOption, init } from echarts; import { ref, watch, onMounted, onBeforeUnmount } from vue;// 定义props interface Props {width?: string;height?: string;optio…

pclpy 窗口可视化多个点云

pclpy 窗口可视化多个点云 一、算法原理二、代码三、结果1.可视化结果 四、相关数据五、问题与解决方案1.问题2.解决 一、算法原理 原理看一下代码写的很仔细的。。目前在同一个窗口最多可视化两个点云。。 二、代码 from pclpy import pcldef CloudShow(cloud1, cloud2):&q…

04 动力云客之登录后获取用户信息+JWT存进Redis+Filter验证Token + token续期

1. 登录后获取用户信息 非常好实现. 只要新建一个controller, 并调用SS提供的Authentication对象即可 package com.sunsplanter.controller;RestController public class UserController {GetMapping(value "api/login/info")public R loginInfo(Authentication a…

C++ 基础算法 双指针 数组元素的目标和

给定两个升序排序的有序数组 A 和 B &#xff0c;以及一个目标值 x 。 数组下标从 0 开始。 请你求出满足 A[i]B[j]x 的数对 (i,j) 。 数据保证有唯一解。 输入格式 第一行包含三个整数 n,m,x &#xff0c;分别表示 A 的长度&#xff0c;B 的长度以及目标值 x 。 第二行包…

使用静态CRLSP配置MPLS TE隧道

正文共&#xff1a;1591 字 13 图&#xff0c;预估阅读时间&#xff1a;4 分钟 静态CRLSP&#xff08;Constraint-based Routed Label Switched Paths&#xff0c;基于约束路由的LSP&#xff09;是指在报文经过的每一跳设备上&#xff08;包括Ingress、Transit和Egress&#xf…

C语言内存模型的深度剖析

一、C语言内存模型的详细构成 在计算机体系结构中&#xff0c;内存被抽象为一个线性的地址空间&#xff0c;C语言内存模型即建立在此基础之上。每个存储单元都有一个唯一的地址&#xff0c;这个地址空间从0开始递增&#xff0c;范围受限于处理器架构和操作系统提供的物理或虚拟…

Ubuntu18.4桌面版安装并配置apt update与远程访问

1、无脑直接一步步安装即可 2、安装完成后与服务器版不同的是 服务器版(参照系统安装博客)通过选项安装openssh,桌面版啊需要通过 apt install openssh-server 进行安装 ----小插曲--- 如果使用apt install openssh-server 时 报错 无法解析ip 那么是由于未配置DNS 配置为1…

使用alist连接百度网盘和阿里云盘挂载到本地磁盘

1、下载alist软件 alist软件下载地址&#xff1a;https://github.com/alist-org/alist 跳转后&#xff0c;找到对应的windows版本 2 、下载后解压&#xff0c;并启动服务 注意&#xff1a;alist的启动方式不是传统的双击启动&#xff0c;需要用命令提示符,启动服务 下载完成…

平时积累的FPGA知识点(9)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第9期&#xff1a; 31 ldpc的license是什么&#xff1f; 解释&#xff1a;Xilinx公司的Zynq UltraScale RFSoC系列芯片进行项目开发&#xff0c;在某些芯片型号中&#xff0c;自身带有SD-FEC硬核资源&#xff0c;具体查询方式&a…