百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Unity Shaders学习笔记--SurfaceShader(九)Cubemap

csdh11 2024-12-12 11:18 21 浏览

【Unity Shaders】学习笔记——SurfaceShader(九)Cubemap

  1. 如果你想从零开始学习Unity Shader,那么你可以看看本系列的文章入门,你只需要稍微有点编程的概念就可以。

  2. 水平有限,难免有谬误之处,望指出。

上一节中讲述了制作Cubemap的方法。这一节讲讲怎么使用它。

Simple Cubemap

先来看一下最简单的Cubemap。

Shader "Custom/SimpleReflection" 
{
    Properties 
    {
        _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Cubemap ("CubeMap", CUBE) = ""{}
        _ReflAmount ("Reflection Amount", Range(0.01, 1)) = 0.5
    }
    
    SubShader 
    {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        samplerCUBE _Cubemap;
        float4 _MainTint;
        float _ReflAmount;

        struct Input 
        {
 float2 uv_MainTex;
 float3 worldRefl;
        };

        void surf (Input IN, inout SurfaceOutput o) 
        {
 half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
 o.Emission = texCUBE(_Cubemap, IN.worldRefl).rgb * _ReflAmount;
 o.Albedo = c.rgb;
 o.Alpha = c.a;
        }
        ENDCG
    } 
    FallBack "Diffuse"
}

其实就是用texCUBE函数来对Cubemap采样。

第二个参数应该传入UV坐标,但实际传入的是世界反射向量。这是Unity替我们计算了UV坐标。

Cubemap是由六张贴图构成的,组成了一个类似天空盒的六面体,那这六张贴图是如何映射到小球上的呢,使小球看起来像倒映着周围的环境一样?

将Cubemap想象成一个立方体,包裹着小球,从小球的中心点发射一条射线,穿过小球表面和立方体表面,射线与小球和立方体会各有一个交点,小球上的这个点对应的就是立方体上的这个点的纹理。那要怎样计算各个点对应的UV坐标呢?从小球中心点发射的一条条射线其实就是法线,有个很明显的事实就是,法线朝向法线坐标分量最大的坐标轴指向的立方体的面。也就是坐标(1,1,3)的法线朝向的是Z轴指向的立方体的面。这样就由法线找到了点对应的面。那么UV坐标又该如何计算呢?法线另外两个较小的坐标值和UV坐标是有关系的。举个特殊点的例子,小球最顶点的法线的坐标应该是(0,0,1),对应的应该是立方体的顶面的中点,UV坐标应该是(0.5,0.5)。计算UV坐标的方法是(x/z×0.5+0.5,y/z×0.5+0.5),将特殊点代进去,答案是正确的。原理有点难说明,相当于把X、Y坐标投影到了对应的面上。乘0.5加0.5是为了让法线坐标的区间从[-1,1]变为[0,1]。

在Unity里,我们不必自己计算,可以直接使用内置变量worldRefl来检索Cubemap。

Normal Cubemap

Shader "Custom/NormalMappedReflection" 
{
    Properties 
    {
        _MainTint ("Diffuse Tint", Color) = (1,1,1,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _NormalMap ("Normal Map", 2D) = "bump" {}
        _Cubemap ("Cubemap", CUBE) = ""{}
        _ReflAmount ("Reflection Amount", Range(0,1)) = 0.5
    }
    
    SubShader
     {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        CGPROGRAM
        #pragma surface surf Lambert

        samplerCUBE _Cubemap;
        sampler2D _MainTex;
        sampler2D _NormalMap;
        float4 _MainTint;
        float _ReflAmount;

        struct Input 
        {
 float2 uv_MainTex;
 float2 uv_NormalMap;
 float3 worldRefl;
 INTERNAL_DATA
        };

        void surf (Input IN, inout SurfaceOutput o) 
        {
 half4 c = tex2D (_MainTex, IN.uv_MainTex);
 
 float3 normals = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap)).rgb;
 o.Normal = normals;
 
 o.Emission = texCUBE (_Cubemap, WorldReflectionVector (IN, o.Normal)).rgb * _ReflAmount;
 o.Albedo = c.rgb * _MainTint;
 o.Alpha = c.a;
        }
        ENDCG
    } 
    FallBack "Diffuse"
}

就只是增加了法线贴图而已。 因为法线信息的改变,所以要重新计算传入texCUBE函数的世界反射向量。float3 worldRefl;INTERNAL_DATA变量用于原本的法线信息不使用时,比如使用了法线贴图,原来的法线信息就不使用了。要根据新的法线信息计算世界反射向量使用WorldReflectionVector函数。

动态立方图系统

有时候游戏里的物体从一个环境走到另一个环境,需要更换Cubemap,这样显示的反射效果才真实。

有两种方法更换Cubemap,一种是实时更换Cubemap,这样的效果最真实,但是要牺牲性能;第二种是当物体走到另一个环境的时候更换Cubemap,这就是我要讲的方法。

方法很简单,就是在C#里用SetTexture的方法动态更换Cubemap。

[ExecuteInEditMode]
public class SwapCubemaps : MonoBehaviour 
{
    public Cubemap cubeA;
    public Cubemap cubeB;
    
    public Transform posA;
    public Transform posB;
    
    private Material curMat;
    private Cubemap curCube;
    

    // Use this for initialization
    void Start  
    {
    
    }
    
    // Update is called once per frame
    void Update  
    {
        curMat = renderer.sharedMaterial;
        if(curMat)
        {
 curCube = CheckProbeDistance;
 curMat.SetTexture("_Cubemap", curCube);
 
        }
    }
    
    private Cubemap CheckProbeDistance
    {
        float distA = Vector3.Distance(transform.position, posA.position);
        float distB = Vector3.Distance(transform.position, posB.position);
        
        if(distA < distB)
        {
 return cubeA;
        }
        else if(distB < distA)
        {
 return cubeB;
        }
        else
        {
 return cubeA;
        }
        
    }
        
    
    void OnDrawGizmos
    {
        Gizmos.color = Color.green;
        
        if(posA)
        {
 Gizmos.DrawWireSphere(posA.position, 0.5f);
        }
        
        if(posB)
        {
 Gizmos.DrawWireSphere(posB.position, 0.5f);
        }
    }
}
  1. [ExecuteInEditMode]是为了让脚本在编辑器状态的时候也能执行,这样就不必点击Play调试,比较方便。

  2. OnDrawGizmos是在Scene里画一些可视化的东西方便调试。

  3. CheckProbeDistance里用Distance判断物体和A点、B点的距离,根据距离决定返回哪种Cubemap。

  4. 在Update设置材质的Cubemap。

Cubemap效果

Cubemap

我有加个金属的纹理。效果是这样的。

NormalCubemap

这是加了法线贴图的。

相关推荐

IDEA界面太丑??尝试一下这几个插件

前言IntelliJIDEA主要用于支持Java、Scala、Groovy等语言的开发工具,同时具备支持目前主流的技术和框架,擅长于企业应用、移动应用和Web应用的开发。IntelliJi...

小巧 Vue 页面滚动进度条组件ScrollProgress

今天给大家分享一个轻量级Vue.js全屏滚动进度条组件VueScrollProgress。vue-scroll-progress一款基于vue.js构建的页面滚动进度条组件,...

基于vue实现可视化拖拽编辑器,页面生成工具,提升前端开发效率

项目介绍基于vue实现的可视化拖拽编辑器,实现页面生成工具,提升前端开发效率。可以基层到移动端项目作为自定义json直接生成UI页面。项目特点功能特点...

优秀 vue+heyui 后端管理系统HeyUI-Admin

今天再给小伙伴们推荐一款成熟的企业中后台管理系统HEYUI-Admin。heyui-admin基于vue.js和heyui组件库构建的后台管理系统。包含基础表单/表格功能,拓展组件(图表、富文本编辑...

响应式 Vue.js 前端组件化框架Xvue-UI

今天给小伙伴们推荐一款超不错的Vue轻量级组件框架XVueUI。xvue-ui基于vue2.x构建的响应式前端组件化框架。轻量级、易于上手,提供...

《基于SpringBoot+Vue的在线视频系统设计与实现》开题报告

【计算机毕业设计案例】基于SpringBoot+Vue的在线视频系统设计与实现_哔哩哔哩_bilibili...

超好用 Vue.js 图片裁切组件Vue-ImgCutter

今天给小伙伴们分享一个超棒的Vue图片任意裁剪插件VueImgCutter。vue-img-cutter基于vue2.x构建的轻量级剪切图片组件。支持移动图像、放大缩小图片、任意移动图片、固定比...

Vue 3 进阶用法:异步组件(vue 异步组件原理)

一、代码分割一个大型前端应用,如果所有代码都放在单一文件,体积会特别大,下载时间长,白屏时间久,用户体验差。...

源码补丁神器—patch-package(源码助手怎么用)

作者:张浩一、背景vue项目中使用vue-pdf第三方插件预览pdf,书写业务代码完美运行,pdf文件内容正常预览无问题。后期需求有变,业务需求增加电子签章功能。这个时候pdf文件的内容可以显示出...

经验分享:Vue2 项目升级 Vue3 + Element Plus,借助Deepseek手动升级

Vue3出来好久了,我开发的项目还在使用Vue2框架,一般情况下不考虑升级,但是最近需要接入工作流程引擎之类的,看了下Vue2生态下操作空间不是很好,那索性尝试升级Vue3吧。一番操作下来,升级成功,...

34K Star!史上最全JavaScript资源库 awesome-javascript

34KStar!史上最全JavaScript资源宝库大揭秘引言在GitHub上,有一个备受瞩目的JavaScript资源仓库,以其全面的内容和精心的分类,成为了众多开发者的必备参考。这个拥有超过...

基于 Vue.js 磁片栅格布局组件VueGridLayout

#头条创作挑战赛#今天给大家分享一个超优秀的vue.js拖拽栅格布局插件VueGridLayout。...

6款高颜值 Vue3 PC端UI组件库(vue3开发组件库)

马上到国庆了,还没学习或者想学习vue3的小伙伴们有安排上没?这次推荐几个比较流行的VUE3UI组件库,合理利用,又或者学习借鉴都是不错的选择。1、element-pluselement-plus...

高性能 vue.js+ztree 树形组件Vue-GiantTree

今天给大家分享一款超棒的Vue海量数据渲染树形组件VueGiantTree。vue-giant-tree基于ztree封装的Vue树形组件。轻松实现大数据高性能渲染,适合海量数据渲染场景。zTr...

【推荐】2024年推荐的6款开源免费 Vue 后台管理系统模板,建议收藏

前言在现今的软件开发领域,...