Unity中Shader法线贴图(下)实现篇

文章目录

  • 前言
  • 一、回顾一下上一篇中公式
  • 二、在Shader中实现
    • 1.appdata中定义NORMAL与TANGENT语义.
    • 2.v2f中声明三个变量用于组成成切线空间下的旋转矩阵.
    • 3.在顶点着色器中执行:
    • 4.在片断着色器中计算出世界空间下的法线,然后再拿去进行需要的计算:
  • 三、最终效果


前言

我们在这篇文章中,实现法线贴图的正确采样

  • Unity中Shader法线贴图(下)理论篇

一、回顾一下上一篇中公式

在这里插入图片描述


二、在Shader中实现

1.appdata中定义NORMAL与TANGENT语义.

half3 normal : NORMAL;
float4 tangent : TANGENT;

2.v2f中声明三个变量用于组成成切线空间下的旋转矩阵.

float3 tSpace0:TEXCOORD4;
float3 tSpace1:TEXCOORD5;
float3 tSpace2:TEXCOORD6;

3.在顶点着色器中执行:

  • 切线从本地空间转化到世界空间

half3 worldTangent = UnityObjectToWorldDir(v.tangent);
//v.tangent.w:DCC软件中顶点UV值中的V值翻转情况.
//unity_WorldTransformParams.w:模型缩放是否有奇数负值.
half tangentSign = v.tangent.w * unity_WorldTransformParams.w;

- 由叉积计算出副切线

half3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;

  • 得到 MT

o.tSpace0 = float3(worldTangent.x,worldBinormal.x,worldNormal.x);
o.tSpace1 = float3(worldTangent.y,worldBinormal.y,worldNormal.y);
o.tSpace2 = float3(worldTangent.z,worldBinormal.z,worldNormal.z);

4.在片断着色器中计算出世界空间下的法线,然后再拿去进行需要的计算:

  • 利用点积操作,得出世界空间下的法线(法线纹理)

half3 normalTex = UnpackNormalWithScale(tex2D(_NormalTex,i.uv),scale);
half3 worldNormal = half3(dot(i.tSpace0,normalTex),dot(i.tSpace1,normalTex),dot(i.tSpace2,normalTex));


三、最终效果

请添加图片描述

最终代码:

//纹理的多级渐远 Mipmap
//纹理的环绕方式
//法线贴图
Shader "MyShader/P2_1_8"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        
        [KeywordEnum (Repeat,Clamp)]_WrapMode("WrapMode",int) = 0
        [IntRange]_Mipmap ("Mipmap",Range(0,10)) = 0
        
        //法线贴图
        [Normal]_NormalTex("NormalTex",2D) = "bump" {}
        //在属性面板定义立方体纹理
        _CubeMap("CubeMap",Cube) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma shader_feature _WRAPMODE_REPEAT _WRAPMODE_CLAMP
            #include "UnityCG.cginc"
            
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                
                half3 normal : NORMAL;
                float4 tangent : TANGENT;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 localPos : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                half3 worldNormal : TEXCOORD3;

                float3 tSpace0:TEXCOORD4;
                float3 tSpace1:TEXCOORD5;
                float3 tSpace2:TEXCOORD6;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _Mipmap;
            samplerCUBE _CubeMap;
            sampler2D _NormalTex;
            v2f vert (appdata v)
            {
                v2f o;
                
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.localPos = v.vertex.xyz;
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);

                half3 worldTangent = UnityObjectToWorldDir(v.tangent);
                //v.tangent.w:DCC软件中顶点UV值中的V值翻转情况.
                //unity_WorldTransformParams.w:模型缩放是否有奇数负值. 
                half tangentSign = v.tangent.w * unity_WorldTransformParams.w;

                half3 worldBinormal = cross(o.worldNormal, worldTangent) * tangentSign;


                o.tSpace0 = float3(worldTangent.x,worldBinormal.x,o.worldNormal.x);
                o.tSpace1 = float3(worldTangent.y,worldBinormal.y,o.worldNormal.y);
                o.tSpace2 = float3(worldTangent.z,worldBinormal.z,o.worldNormal.z);
                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //WrapMode
                #if _WRAPMODE_REPEAT
                i.uv = frac(i.uv);
                #elif _WRAPMODE_CLAMP
                    //法一:
                    //i.uv = clamp(i.uv,0,1);
                    //法二:
                    i.uv = saturate(i.uv);
                #endif
                float4 uvMipmap = fixed4(i.uv,0,_Mipmap);
                fixed4 col = tex2Dlod(_MainTex, uvMipmap);

                //法线纹理
                fixed3 normalTex = UnpackNormal(tex2D(_NormalTex,i.uv));
                
                
                //max(0,dot(N,L))
                fixed3 N1 = normalize(normalTex);
                fixed3 L = _WorldSpaceLightPos0.xyz;

                //return fixed4(normalTex,1);
                //计算出世界空间下的法线
                half3 worldNormal = half3(dot(i.tSpace0,normalTex),dot(i.tSpace1,normalTex),dot(i.tSpace2,normalTex));
                return max(0,dot(worldNormal,L));

                //CubeMap
                fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
                //V,N,R
                fixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);
                fixed3 N = normalize(i.worldNormal);
                fixed3 R = reflect(V,N);
                cubemap = texCUBE(_CubeMap,R);
                
                return cubemap;
                
                return col;
            }
            ENDCG
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NLP | SimKGC论文详解及项目实现

本文主要讲解了论文SimKGC:基于预训练语言模型的简单对比KGC的论文总结以及项目实现。 论文题目:2022_SimKGC: Simple Contrastive Knowledge Graph Completion with Pre-trained Language Models 论文地址:2022.acl-long.295.pdf (aclanthol…

开源集群管理系统对比分析:Kubernetes 与 Apache Mesos

集群管理系统是关键的软件解决方案,可以在互连机器网络中有效分配和利用计算资源。毫无疑问,它们通过确保可扩展性、高可用性和有效的资源管理在现代计算中发挥着至关重要的作用,这使得它们对于运行复杂的应用程序、管理数据中心以及进一步增…

java 实现发送邮箱,复制即用,包含邮箱设置第三方登录授权码获取方法

application.yml spring:profiles:active: dev # active: test#邮件附件上传文件大小限制servlet:multipart:max-file-size: 50MB #单个文件大小限制max-request-size: 100MB #总文件大小限制(允许存储文件的文件夹大小)mail:default-encoding: UTF…

Java集合大总结——Set的简单使用

Set的简单介绍 Set接口是Collection的子接口,Set接口相较于Collection接口没有提供额外的方法。Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。Set集合支持的遍历方式和Collection集合一样&am…

设计模式系列:三、责任链设计模式

一、概述 责任链模式是一种行为设计模式,它允许多个对象处理一个请求,从而避免了请求的发送者和接收者之间的耦合关系。 优点是把任务划分为一个一个的节点,然后按照节点之间的业务要求、顺序,把一个个节点串联起来,…

单链表相关面试题--4.输入一个链表,输出该链表中倒数第k个结点

/* 解题思路: 快慢指针法 fast, slow, 首先让fast先走k步,然后fast,slow同时走,fast走到末尾时,slow走到倒数第k个节点。 */ class Solution { public:ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {struct Lis…

AppLink定时调度操作

RestCloud AppLink定时调度操作 定时调度可以让我们更加快速了解到数据的变动以作出更好的决策,接下来通过AppLink平台配置定时调度的操作。 1.登录RestCloud AppLink 2.点击授权管理 3.点击应用认证菜单 4.新建拼多多授权认证 基础定时调度配置 1.拉取一个定时器…

Linux内核调试篇——获取内核函数地址的四种方法(一文解决)

在内核调试中,经常需要知道某个函数的地址,或者根据函数地址找到对应的函数,从而进行更深一步的debug。 下面介绍四种获取内核函数地址的方法: 1、System.map 在编译Linux内核时,会产生一个内核映像文件System.map&…

英飞凌TC3xx的LMU SRAM保护机制(一)

目录 1.基本概述 2.理解Master Tag ID 3.LMU memory保护使能 4.测试结果分析 5.小结 1.基本概述 在英飞凌TC3xx中,每个CPU除了有自己的DLMU外,在SRI总线还挂着几块SRAM,这几块SRAM由LMU(Local Memory Unit)进行权限控制。…

微服务学习|Gateway网关:网关作用、快速入门、路由断言工厂、路由过滤器配置、全局过滤器、过滤器执行顺序、跨域问题处理

为什么需要网关 网关功能: 1.身份认证和权限校验 2.服务路由、负载均衡 3.请求限流 网关的技术实现 在SpringCloud中网关的实现包括两种:gateway、zuul Zuul是基于Servlet的实现,属于阻塞式编程。而SprinaCloudGateway则是基于Spring5中提供的WebFlux&#xf…

RHCE之WEB服务器作业

目录 一、实验要求 1.1 网站需求: 1.2 要求: 二、实验步骤 2.1 下载mod_ssl模块,关闭firewall 2.2 链接本机IP与域名 2.3 创建网页目录 2.4 建立该网站 ​编辑 2.5 创建两位学生信息 2.6 实施数据加密 三、实验结果 一、实验要求…

Leetcode刷题详解——打家劫舍 II

1. 题目链接:213. 打家劫舍 II 2. 题目描述: 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻…

火电安全事故vr模拟仿真培训强交互更真实

VR消防,利用VR虚拟现实技术,将VR和消防教育融合在一起达到寓教于乐的效果, VR消防教育是对于家中、校园内、大型商场、公司办公室等情景产品研发的消防安全培训类VR系统软件,根据互动体验、互动、视角实际操作、视听觉系统多度自然…

什么是域欺骗?域欺骗的主要类型有哪些?

域欺骗是指网络犯罪分子假冒网站名称或电子邮件域来欺骗用户。域欺骗的目的是将恶意电子邮件或网络钓鱼网站伪装成合法电子邮件或网站,诱使用户与之交互。域欺骗就像骗子一样,向人们展示伪造的凭据以获得信任,然后再利用其获得好处。 域欺骗…

photoshop插件开发入门(java,android,ios)

photoshop给我们提供了一个服务,让我们可以通过java或者c#等语言发送JavaScript等脚本给photoshop,让photoshop自动帮我们处理图片。这里的资料主要是如何连接photoshop,如果开发和调试JavaScript脚本。 photoshop 学习资料和sdk&#xff08…

网络工程师网络配置经典例题(一)附有详细注释

一、配置管理IP和Telnet 配置设备管理IP地址后&#xff0c;可以通过管理IP远程登录设备。 &#xff08;1&#xff09;配置管理IP地址 <HUAWEI> system-view [HUAWEI] vlan 5 //创建交换机管理VLAN 5 [HUAWEI-VLAN5] management-vlan [HUAWEI-VLAN5…

一篇博客读懂双向链表

目录 一、双向带头循环链表的格式 二、链表的初始化和销毁 2.1链表的初始化 2.2链表的销毁 三、链表的检查与准备 3.1链表的打印 3.2创建新结点 四、链表增删查改 4.1尾插 4.2尾删 4.3头插 4.4头删 4.5查找 4.6任意位置前插入 4.7删除任意位置 一、双向带…

emq Neuron工业协议采集使用

emq Neuron工业协议采集使用 Neuron 简介 EMQ X Neuron 是运行在各类物联网边缘网关硬件上的工业协议商业化网关软件&#xff0c;支持一站式接入和解析数十种工业协议&#xff0c;并转换成 MQTT 协议接入工业物联网平台。用户可以通过基于 Web 的管理控制台可以实现在线的网关…

leetcode刷题日记:202. Happy Number( 快乐数)和203. Remove Linked List Elements(移除链表元素)

202. Happy Number( 快乐数) 这一题的解决与之前的循环链表比较类似&#xff0c;因为如果不是快乐数的话&#xff0c;在数字变化的过程中必然遇到了数字变换的循环&#xff0c;所以我们需要在变换的过程中判断是否遇到了循环&#xff0c;判断是否在一个序列中存在循环&#xf…