UnityShader学习笔记——高级纹理

——内容源自唐老狮的shader课程


目录

1.立方体纹理

1.1.概念

1.2.用处

1.3.如何采样

1.4.优缺点

2.天空盒

2.1.概念

2.2.优点

2.3.设置

3.动态生成立方体纹理

3.1.原因

3.2.实现

 3.3.代码运行中生成

4.反射

4.1.原理

4.2.补充知识

5.折射

5.1.原理

5.2.菲涅耳定律

5.3.补充知识

6.菲涅耳反射

6.1.是什么

6.2.原理

7.渲染纹理

7.1.概念

7.2.常用的获取方法

8.镜面效果

9.玻璃效果

9.1.基本原理

9.2.补充知识

9.3.让玻璃效果对象滞后渲染

9.3.1.原因

9.3.2.实现

9.4.自定义折射效果

9.5.利用切线空间法线来计算折射偏移

10.程序纹理

10.1.概念

10.2.优点

10.3.补充知识

10.4.方法

11.程序纹理

12.如有疏漏,还请指出


1.立方体纹理

1.1.概念

        是一种特殊的纹理类型,其包括六个二维纹理,分别对应一个立方体的六个面。右为+X,左为-X;上为+Y,下为-Y;前为+Z,后为-Z。也就是说它的轴向与unity的世界坐标轴向相同。

1.2.用处

        1.环境映射:用于模拟反射环境的效果,用立方体纹理存储周围环境的图像。应用到反射表面时,可以让物体看起来像是在反射周围环境

        2.天空盒:将立方体纹理的六个面映射道一个立方体内表面,从而模拟天空,云朵,远处的山脉等环境

        3.全景图:用于展示全息图像,视频以及通过立方体纹理来存储全景图片,视频的六个部分等

1.3.如何采样

        提供一个三维的纹理坐标,该坐标会提供一个方向,从立方体纹理的中心出发,使其与六个面之一相交,采样结果就是基于该相交点计算而来。

1.4.优缺点

        优:

        1.用途多:可以有效地模拟环境反射和全景效果

        2.无缝衔接:立方体纹理设计为无缝衔接者的六个面,减少了瑕疵

        3.兼容性好

        缺:

        1.内存开销大:存了六张2d纹理,内存占用较高,尤其是在高分辨率下

        2.采样复杂:采样方式比起传统2d纹理更加复杂,计算更多

        3.透视变形:6个平面来近似模拟球形环境,有时会出现透视变形的问题


2.天空盒

2.1.概念

        常用于模拟背景的一种方式,通常由一个立方体构成,不止可以模拟天空,也可以模拟室内环境之类的。而在使用天空盒时,世界就被包括在一个立方体中,这个立方体的每个面使用的就是 立方体纹理技术

2.2.优点

        1.可以创建逼真的背景,因为它可以展示复杂和详细的背景

        2.可以提高性能,毕竟只需要贴图而不需要实际渲染

        3.全景视图,天空盒六个面共同构成一个完整的环境,无论哪个视角都是一个连贯的图像

        4.易于实现,只需六个方向的纹理图像即可

2.3.设置

        1.需要将图片纹理的Wrap Mode设置为Clamp

        2.全局天空盒:在Light面板设置。

           单独天空盒:为摄像机添加SkyBox组件并关联材质球


3.动态生成立方体纹理

3.1.原因

        为了实现更好更真实的表现效果(反射,折射),对于场景中不同位置的物体。我们应该为他们在不同位置生成不同的立方体纹理

3.2.实现

        在unity菜单中加入一个专门用于生成立方体纹理地渲染即可

using UnityEditor;
using UnityEngine;public class Lesson52_RenderToCubeMap : EditorWindow
{private GameObject obj;private Cubemap cubeMap;[MenuItem("立方体纹理动态生成/打开生成窗口")]static void OpenWindow(){Lesson52_RenderToCubeMap window = EditorWindow.GetWindow<Lesson52_RenderToCubeMap>("立方体纹理生成窗口");window.Show();}private void OnGUI(){GUILayout.Label("关联对应位置对象");//第三个参数为是否只选择当前场景的对象obj = EditorGUILayout.ObjectField(obj, typeof(GameObject), true) as GameObject;GUILayout.Label("关联对应立方体纹理");cubeMap = EditorGUILayout.ObjectField(cubeMap, typeof(Cubemap), false) as Cubemap;if (GUILayout.Button("生成立方体纹理")){if (obj == null || cubeMap == null){EditorUtility.DisplayDialog("error", "先关联", "确认");}//动态生成GameObject tmpObj = new GameObject("临时对象");tmpObj.transform.position = obj.transform.position;Camera camera = tmpObj.AddComponent<Camera>();camera.RenderToCubemap(cubeMap);DestroyImmediate(tmpObj);return;}}
}
面板

 3.3.代码运行中生成

        让Camera的RenderToCubemap在Update,LateUpdate等方法中使用即可,但要注意性能消耗。并且RenderToCubemap有重载,可以一个面一个面的渲染。


4.反射

4.1.原理

        利用立方体纹理进行环境映射

        利用摄像机看向物体顶点的方向向量坐标入射光,结合顶点法线可以算出反射向量,然后用该反射向量在立方体纹理中进行采样,得到最终颜色。也可以定义个反射颜色以控制反射时候的颜色

4.2.补充知识

        texCUBE(立方体纹理,反射方向向量):用于立方体纹理采样,CG内置函数

        lerp(a,b,t):插值函数,内部计算公式为 结果 = a * (1 - t) + b * t,我们利用这个函数来决定反射效果的程度

Shader "Models_2/ReflectionWithDiffuse"
{Properties{_DiffuseColor("DiffuseColor", Color) = (1, 1, 1, 1)_ReflectionMap("ReflectionMap", Cube) = ""{}_ReflectionColor("ReflectionColor", Color) = (1, 1, 1, 1)_Reflectivity("_Reflectivity", Range(0, 1)) = 0}SubShader{Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbasefixed4 _DiffuseColor;fixed4 _ReflectionColor;samplerCUBE _ReflectionMap;float _Reflectivity;struct v2f{float4 pos : SV_POSITION;float3 wNormal : NORMAL;float3 wPos : TEXCOORD0;float3 wReflectionDir : TEXCOORD1;SHADOW_COORDS(2)};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.wPos = mul(unity_ObjectToWorld, v.vertex);data.wNormal = normalize(UnityObjectToWorldNormal(v.normal));float3 wViewDir = UnityWorldSpaceViewDir(data.wPos.xyz);data.wReflectionDir = reflect(-wViewDir, data.wNormal);TRANSFER_SHADOW(data);return data;}fixed4 frag(v2f f) : SV_TARGET{fixed3 texColor = texCUBE(_ReflectionMap, f.wReflectionDir).rgb * _ReflectionColor.rgb;float3 wLightDir = normalize(UnityWorldSpaceLightDir(f.wPos.xyz));fixed3 lambertColor = _LightColor0.rgb * _DiffuseColor.rgb * max(0, dot(f.wNormal, wLightDir));UNITY_LIGHT_ATTENUATION(atten, f, f.wPos.xyz);//利用 lerp 在漫反射颜色和反射颜色之间 进行插值 0和1就是极限状态,0 没有反射效果,1 只有反射效果//反射率就是t(插值因子)fixed3 finalColor = UNITY_LIGHTMODEL_AMBIENT + lerp(lambertColor, texColor, _Reflectivity) * atten;return fixed4(finalColor, 1.0);}ENDCG}}FallBack "Reflective/VertexLit"
}

        上述代码是在漫反射和反射之间变化,也可以不加漫反射,使用单纯的颜色来与反射结合。但漫反射会比单纯的颜色更亮一点。

左侧是漫反射,右侧是纯色,反射率都是1

5.折射

5.1.原理

        利用立方体纹理进行环境映射

        利用摄像机看向物体表面顶点的方向向量作为入射向量,结合顶点法线向量算出折射向量,然后利用折射方向向量在立方体纹理中进行采样,得到最终颜色

5.2.菲涅耳定律

        当光从介质1沿着表面法线夹角为θ1的方向斜射入介质2时,我们可以利用数学公式 n1sinθ1 = n2sinθ2 计算出折射光线和法线的夹角 θ2。(n1 和 n2 为两种介质的折射率)

        实际上折射是会多次发生的,但我们一般直接用第一次所得的折射方向去采样,虽然不符合物理规律,但其效果在视觉上可以接受。

5.3.补充知识

        refract(入射方向单位向量,顶点法线单位向量,入射介质折射率 / 射入介质折射率):可以通过该方法获取反射向量,其内部实现的就是菲涅耳定律。

Shader "Models_2/RefractWithDiffuse"
{Properties{_RefractCube("RefractCube", Cube) = ""{}_RefractiveIndexRatio("RefractiveIndexRadio", Range(-1, 5)) = 1_RefractAmount("RefractAmount", Range(0, 1)) = 1_RefractColor("RefractColor", Color) = (1, 1, 1, 1)//漫反射颜色_Color("Color", Color) = (1 ,1, 1, 1)}SubShader{Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbasesamplerCUBE _RefractCube;float _RefractiveIndexRatio;float _RefractAmount;fixed4 _RefractColor;fixed4 _Color;struct v2f{float4 pos : SV_POSITION;float3 wNormal : NORMAL;float4 wPos : TEXCOORD0;float3 wRefractDir : TEXCOORD1;SHADOW_COORDS(2)};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.wNormal = normalize(UnityObjectToWorldNormal(v.normal));data.wPos = mul(unity_ObjectToWorld, v.vertex);float3 wViewDir = UnityWorldSpaceViewDir(data.wPos);data.wRefractDir = refract(-wViewDir, data.wNormal, _RefractiveIndexRatio);TRANSFER_SHADOW(data);return data;}fixed4 frag(v2f f) : SV_TARGET{fixed4 refractTex = texCUBE(_RefractCube, f.wRefractDir) * _RefractColor;float3 wLightDir = normalize(UnityWorldSpaceLightDir(f.wPos));fixed3 lambertColor = _LightColor0.rgb * _Color.rgb * max(0, dot(f.wNormal, wLightDir));UNITY_LIGHT_ATTENUATION(atten, f, f.wPos);fixed3 finalColor = UNITY_LIGHTMODEL_AMBIENT + lerp(lambertColor, refractTex, _RefractAmount) * atten;return fixed4(finalColor, 1.0);}ENDCG}}FallBack "Reflective/VertexLit"
}

        上述代码依旧使用的是漫反射与折射之间的差值,会显得更亮一些。当然,使用纯色也行。

左边为漫反射,右边为纯色,折射率都为1

6.菲涅耳反射

6.1.是什么

        一种光学现象,当视线垂直于表面时,反射较弱。而当视线非垂直观察表面时,夹角越小,反射越明显。

        从物理角度看,世界上所有物体在光线照射下都会遵循菲涅耳反射原理

        而在unity中,它一般用来增强真实感,使物体表面在不同角度和光照条件下呈现出更加真实和自然的外观,增强视觉效果。如金属感,陶瓷感,玻璃感等。其效果基于反射,但比反射更加接近真实的效果

6.2.原理

        还是对立方体纹理进行采样,只是对反射率(插值因子)进行一些改变

        由于菲涅耳等式很复杂,所以采用Schlick菲涅耳近似等式来计算反射率:

R(θ) = R0 + (1 - R0)(1 - cos(θ))^5

即:R(θ) = R0 + (1 - R0)(1 - V · N)^5

        R(θ)是入射角为θ时的反射率,R0是垂直入射介质时的反射率,V是视角方向单位向量(入射角),N是顶点法线单位向量。V和N之间是点乘,即dot

Shader "Models_2/FresnelReflectionWithDiffuse"
{Properties{_ReflectCube("ReflectCube", Cube) = ""{}//垂直的反射率 _FresnelScale("FresnelScale", Float) = 1_Color("Color", Color) = (1, 1, 1, 1)}SubShader{Tags { "RenderType" = "Opaque" "Queue" = "Geometry"}Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbasesamplerCUBE _ReflectCube;fixed4 _Color;float _FresnelScale;struct v2f{float4 pos : SV_POSITION;float3 wNormal : NORMAL;float4 wPos : TEXCOORD;float3 wReflectDir : TEXCOORD1;float3 wViewDir: TEXCOORD2;SHADOW_COORDS(3)};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.wNormal = UnityObjectToWorldNormal(v.normal);data.wPos = mul(unity_ObjectToWorld, v.vertex);data.wViewDir = UnityWorldSpaceViewDir(data.wPos);data.wReflectDir = reflect(-data.wViewDir, data.wNormal);TRANSFER_SHADOW(data)return data;}fixed4 frag(v2f f) : SV_TARGET{fixed4 reflectTex = texCUBE(_ReflectCube, f.wReflectDir);float3 wLightDir = normalize(UnityWorldSpaceLightDir(f.wPos));fixed3 lambertColor = _LightColor0.rgb * _Color.rgb * max(0, dot(f.wNormal, wLightDir));float fresnelReflect = _FresnelScale + (1.0 - _FresnelScale) * pow((1.0 - dot(f.wViewDir, f.wNormal)), 5);UNITY_LIGHT_ATTENUATION(atten, f, f.wPos);fixed3 finalColor = UNITY_LIGHTMODEL_AMBIENT.rgb + lerp(lambertColor, reflectTex, fresnelReflect) * atten;return fixed4(finalColor, 1.0);}ENDCG}}FallBack "Reflective/VertexLit"
}

        上述代码仍是漫反射下的

左侧漫反射,右侧纯色

7.渲染纹理

7.1.概念

        渲染目标纹理(也叫渲染纹理)允许我们将摄像机的渲染结果直接写入到某一张纹理中,我们可以利用这个纹理来处理各种特殊效果,比如:镜子,玻璃,屏幕后处理,阴影映射等。

        其用处体现在我们可以不让摄像机将结果直接渲染到屏幕上,而是对其渲染结果进行二次处理或应用。

        简而言之,渲染纹理就是将渲染结果存储到一个纹理对象中,以便在后续的渲染步骤中使用。

7.2.常用的获取方法

        1.在面板创建:Project中右击选择Create->Custom Render Texture创建,然后我们只需要对该纹理进行相关的设置,然后关联到摄像机组件的Target Texture即可,这样对应摄像机渲染的内容就会直接写入到该纹理中。可以手动创建也可以代码创建并关联

        2.特殊渲染通道GrabPass:我们可以在Pass渲染通道外(SubShader中)使用 GrabPass 抓取指令,捕获当前屏幕内容并将其保存为纹理,以便后续使用。它保存的纹理需要我们将其声明出来,默认为_GrabTexture,可以在GrabPass中修改该变量名。

//这么写就能获取了
GrabPass { "自定义变量名(可写可不写)" }

        3.OnRenderImage:在继承了MonoBehaviour的脚本中,我们可以使用OnRenderImage来获取摄像机渲染完成的图像,该函数一般用于实现自定义图像后处理效果,相当于将摄像机渲染完成的图像进行二次处理


8.镜面效果

        将渲染纹理左右翻转即可。这里的渲染纹理直接在面板上创建,然后创建另一个摄像机,将其与该渲染纹理关联,然后把该摄像机放到一个合适的地方即可。

Shader "Models_3/Mirror"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{Pass{CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbasesampler2D _MainTex;float4 _MainTex_ST;struct v2f{float4 pos : SV_POSITION;float3 wNormal : NORMAL;float4 wPos : TEXCOORD0;float4 uv : TEXCOORD1;};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.wPos = mul(unity_ObjectToWorld, v.vertex);data.wNormal = UnityObjectToWorldNormal(v.normal);data.uv.xy = v.texcoord.xy * _MainTex_ST.xy +_MainTex_ST.zw;return data;}fixed4 frag(v2f f) : SV_TARGET{fixed4 mainTex = tex2D(_MainTex, float2(1.0 - f.uv.x, f.uv.y));return mainTex;}ENDCG}}FallBack "Diffuse"
}
摄像机前面是个单向面

9.玻璃效果

9.1.基本原理

        首先,制作效果更好的玻璃效果时,往往不会使用透明来制作。

        在渲染玻璃效果之前,先捕获当前屏幕内容并保存到一张渲染纹理中。在之后的Shader处理中利用该渲染纹理进行采样,将采样结果与主纹理颜色相乘,然后参与最终的颜色计算,实现各种玻璃效果

9.2.补充知识

        1.内置函数 ComputeGrabScreenPos:用于计算屏幕空间位置,传入的是顶点的裁剪空间位置。返回一个float4变量,其各个分量分别为:(屏幕空间x坐标,屏幕空间y坐标,屏幕空间深度值(一般表示顶点距离摄像机的相对深度),裁剪空间的w分量(通常用于透视除法,将xy的范围限制在0~1之间))。所以我们可以利用该函数得到顶点相对屏幕的坐标,然后对捕获的渲染纹理进行采样。

        2.模拟折射的自定义计算规则:不用之前的折射,而是自定义一些计算规则,来模拟折射效果。总体的设计思路,就是在对捕获纹理进行采样时,进行一些偏移计算

9.3.让玻璃效果对象滞后渲染

9.3.1.原因

        为了保证屏幕能够捕获玻璃对象之后的内容,我们必须保证玻璃对象能偶之后渲染。

9.3.2.实现

        将其渲染标签Queue(渲染队列)设置为 Transparent(透明的),保证它晚于大部分队列之后渲染。这样就可以通过GrabPass获取想对正确的内容了。

9.4.自定义折射效果

        我们可以自定义一些简单的偏移计算规则,让最终的采样位置发生偏移,以模拟折射效果

Shader "Models_3/Glass"
{Properties{_MainTex("MainTex", 2D) = ""{}_ReflectionMap("ReflectionMap", Cube) = ""{}//0表示完全不折射,即完全反射,1表示完全不反射,即透明_RefractAmount("RefractAmount", Range(0, 1)) = 0}SubShader{Tags { "RenderType" = "Opaque" "Queue" = "Transparent" }GrabPass {}Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#include "UnityCG.cginc"#include "Lighting.cginc"#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbasesampler2D _MainTex;float4 _MainTex_ST;samplerCUBE _ReflectionMap;float _RefractAmount;//GrabPass默认存储的纹理变量sampler2D _GrabTexture;struct v2f{float4 pos : SV_POSITION;float3 wNormal : NORMAL;float4 wPos : TEXCOORD0;float3 wReflectionDir : TEXCOORD1; //用于存储从屏幕图像中采样的坐标(顶点相对于屏幕的位置)float4 grabPos : TEXCOORD2;//用于在主纹理中采样的uv坐标float2 uv : TEXCOORD3;};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.wPos = mul(unity_ObjectToWorld, v.vertex);data.wNormal = UnityObjectToWorldNormal(v.normal);float3 wViewDir = _WorldSpaceCameraPos.xyz - data.wPos.xyz;float3 wReflectionDir = reflect(-wViewDir, data.wNormal);data.wReflectionDir = wReflectionDir;data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;//屏幕坐标转换相关的内容data.grabPos = ComputeGrabScreenPos(data.pos);return data;}fixed4 frag(v2f f) : SV_TARGET{//反射相关fixed4 mainTex = tex2D(_MainTex, f.uv);fixed4 reflectColor = texCUBE(_ReflectionMap, f.wReflectionDir) * mainTex;//想要有折射效果,可以在采样之前,进行xy屏幕坐标的偏移//1的时候偏移程度最小,0最大float2 Offest = 1 - _RefractAmount;f.grabPos.xy -= Offest / 10.0;//折射相关//齐次除法(透视除法)fixed2 screenUV = f.grabPos.xy / f.grabPos.w;//折射颜色fixed4 grabColor = tex2D(_GrabTexture, screenUV);//0表示完全不折射,即完全反射,1表示完全不反射,即透明fixed4 finalColor = reflectColor * (1.0 - _RefractAmount) + grabColor * _RefractAmount;return finalColor;}ENDCG}}
}
玻璃效果

9.5.利用切线空间法线来计算折射偏移

        1.声明一个_Distortion(名字随意),用以控制折射扭曲程度

        2.利用切线空间下法线来计算偏移值:

        第一行:float2 offset = tangentNormal.xy * _Distortion;

        第二行:屏幕空间.xy  = offset * 屏幕坐标.z + 屏幕空间.xy;

           第一行:代表光线经过法线方向扰动后的便宜成都,确定光线折射的方向和速度

           第二行:模拟真实的折射效果,深度值越大,折射效果越明显。这样可以实现近大远小的效果,使得物体在不同深度上的折射结果有所差异。

        3.用偏移后屏幕空间坐标进行透视除法后去对渲染纹理进行采样

        需要注意的是:法线贴图需要代替模型法线进行光照计算

基于切线空间法线

 


10.程序纹理

10.1.概念

        通过程序代码生成的纹理。其可控性和自由度都远大于之前学习的其他纹理内容

10.2.优点

        1.由于是动态生成,故而不需要存储大文件,可以在运行时生成任意分辨率的纹理

        2.可以根据需求调整自定义参数,实时的更改纹理外观

        3.通过适当的函数设计,可以生成无缝平铺的纹理

10.3.补充知识

        floor(x):向下取整函数

10.4.方法

        1.通过c#脚本生成纹理后传递给Shader(不做过多解释)

using UnityEngine;//1.利用Unity中Texture2D类生成纹理对象
//2.利用Renderer类设置材质球纹理
//3.利用Unity编辑器拓展知识自定义Inspector窗口public class Lesson59_Generate : MonoBehaviour
{public int textureWidth = 256;public int textureHeight = 256;public int tileCount = 8;public Color color0 = Color.white;public Color color1 = Color.black;// Start is called before the first frame updatevoid Start(){UpdateTexture();}// Update is called once per framevoid Update(){}public void UpdateTexture(){Texture2D tex = new Texture2D(textureWidth, textureHeight);float tileWidth = textureWidth / tileCount;float tileHeight = textureHeight / tileCount;int xIndex, yIndex;for (int y = 0; y < textureHeight; y++){for (int x = 0; x < textureWidth; x++){xIndex = (int)(x / tileWidth);yIndex = (int)(y / tileHeight);//同奇同偶if (xIndex % 2 == yIndex % 2){tex.SetPixel(x, y, color0);}else{tex.SetPixel(x, y, color1);}}}//应用像素tex.Apply();Renderer ren = this.GetComponent<Renderer>();if (ren != null){//得到渲染器中的材质球并修改ren.sharedMaterial.mainTexture = tex;}}
}
//用于直接在面板上更新,而不用播放using UnityEditor;
using UnityEngine;[CustomEditor(typeof(Lesson59_Generate))]
public class Lesson59_Editor : Editor
{public override void OnInspectorGUI(){//会绘制默认参数DrawDefaultInspector();//获取目标脚本Lesson59_Generate scriptObj = (Lesson59_Generate)target;if (GUILayout.Button("更新程序纹理")){scriptObj.UpdateTexture();}}
}

 

        2.直接在Shader代码中自定义逻辑生成纹理(不做过多解释)

Shader "Models_3/GenerateTexturePT"
{Properties{_TileCount("TileCount", Float) = 8_Color1("Color1", Color) = (1, 1, 1, 1)_Color2("Color2", Color) = (0, 0, 0, 0)}SubShader{Tags {  }Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float _TileCount;float4 _Color1;float4 _Color2;struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert (appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.uv = v.texcoord.xy;return data;}fixed4 frag (v2f f) : SV_Target{//uv坐标缩放到0-_TimeCountfloat2 uv = f.uv * _TileCount;//获取对应索引float2 posIndex = floor(uv);//只会是0和1,同奇同偶结果都是偶,奇偶结果为奇float value = (posIndex.x + posIndex.y) % 2;//两个极端,value为0时,为color1;value为1时,为color2return lerp(_Color1, _Color2, value);}ENDCG}}
}

11.程序纹理

        是通过算法和数学函数生成的材质(主要在Shader代码中实现),他通常包含多个纹理属性和各种其他属性,用于计算模拟现实世界中的各种表面属性。

        常见的制作程序材质的工具有:Substance Designer,Blender,Houdini

        可以在unity的资源商店,Substance Share,GameTextures等地方获取程序材质


12.如有疏漏,还请指出

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

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

相关文章

IBM服务器刀箱Blade安装Hyper-V Server 2019 操作系统

案例:刀箱某一blade,例如 blade 5 安装 Hyper-V Server 2019 操作系统(安装进硬盘) 刀箱USB插入安装系统U盘,登录192.168... IBM BlandeCenter Restart Blande 5,如果Restart 没反应,那就 Power Off Blade 然后再 Power On 重启后进入BIOS界面设置usb存储为开机启动项 …

C++20新特性

作者&#xff1a;billy 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 前言 C20 是 C 标准中的一个重要版本&#xff0c;引入了许多新特性和改进&#xff0c;包括模块&#xff08;Modules&#xff09;、协程…

WPS如何接入DeepSeek(通过JS宏调用)

WPS如何接入DeepSeek 一、文本扩写二、校对三、翻译 本文介绍如何通过 WPS JS宏调用 DeepSeek 大模型&#xff0c;实现自动化文本扩写、校对和翻译等功能。 一、文本扩写 1、随便打开一个word文档&#xff0c;点击工具栏“工具”。 2、点击“开发工具”。 3、点击“查看代码”…

【SQL server】关于SQL server彻底的卸载删除。

1.未彻底卸载删除SQL Server会出现的问题 如果没有彻底删除之前的SQL server&#xff0c;就可能会出现这个 当要安装新的实例的时候因为之前安装过sql server没有删除干净而导致下图问题&#xff0c;说实例名已经存在。 2.首先要先关闭服务 “开始R”可以快速进入运行&#…

对话框补充以及事件处理机制 (2025.2.10)

作业 1> 将鼠标事件和键盘事件相关代码重新实现一遍 2> 将文本编辑器功能完善 主函数main.cpp #include "widget.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 头…

企业级Mysql实战

Mysql企业级sql编写实战 1 一对多&#xff0c;列表展示最新记录字段1.1 场景1.2 需求1.3 实现1.3.1 表及数据准备1.3.2 Sql编写 2 区间统计&#xff08;if/case when&#xff09;2.1 场景2.2 需求2.3 实现2.2.1 表及数据准备2.3.2 sql编写 3 多类别分组统计&#xff08;竖表转横…

C语言基础第04天:数据的输出和输出

C语言基础:04天笔记 内容提要 回顾C语言数据的输入输出 回顾 运算符 算术运算符 结果:数值 - * / % (正) -(负) -- i和i 相同点:i自身都会增1 不同点:他们运算的最终结果是不同的. i先使用 ,后加1; i先计算,后使用 赋值运算符 结果:赋值后的变量的值 赋值顺序:由右…

DeepSeek训练成本与技术揭秘

引言&#xff1a;在当今人工智能蓬勃发展的时代&#xff0c;DeepSeek 宛如一颗耀眼的新星&#xff0c;突然闯入大众视野&#xff0c;引发了全球范围内的热烈讨论。从其惊人的低成本训练模式&#xff0c;到高性能的模型表现&#xff0c;无一不让业界为之侧目。它打破了传统认知&…

数组与指针1

1. 数组名的理解 1.1 数组名是数组首元素的地址 int arr[10] {1,2,3,4,5,6,7,8,9,10};int *p &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址。如下&#xff1a; 1.2…

Axure原型图怎么通过链接共享

一、进入Axure 二、点击共享 三、弹出下面弹框&#xff0c;点击发布就可以了 发布成功后&#xff0c;会展示链接&#xff0c;复制即可共享给他人 四、发布失败可能的原因 Axure未更新&#xff0c;首页菜单栏点击帮助选择Axure更新&#xff0c;完成更新重复以上步骤即可

软件模拟I2C案例(寄存器实现)

引言 在经过前面对I2C基础知识的理解&#xff0c;对支持I2C通讯的EEPROM芯片M24C02的简单介绍以及涉及到的时序操作做了整理。接下来&#xff0c;我们就正式进入该案例的实现环节了。本次案例是基于寄存器开发方式通过软件模拟I2C通讯协议&#xff0c;然后去实现相关的需求。 阅…

脚手架开发【实战教程】prompts + fs-extra

创建项目 新建文件夹 mycli_demo 在文件夹 mycli_demo 内新建文件 package.json {"name": "mycli_demo","version": "1.0.0","bin": {"mycli": "index.js"},"author": "","l…

【大模型】DeepSeek-V3技术报告总结

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了学习DeepSeek相关知识的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于DeepSeek官方技术报告进行的&#xff0c;每个知识点的…

只需三步!5分钟本地部署deep seek——MAC环境

MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步&#xff1a;安装谷歌浏览器插件 第一步:下载Ollama 打开此网址&#xff1a;https://ollama.com/&#xff0c;点击下载即可&#xff0c;如果网络比较慢可使用文末百度网盘链接 注&#xff1a;Ollama是…

力扣hot100刷题第一天

哈希 1. 两数之和 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。你可以按任意…

Linux(CentOS)安装 Nginx

CentOS版本&#xff1a;CentOS 7 Nginx版本&#xff1a;1.24.0 两种安装方式&#xff1a; 一、通过 yum 安装&#xff0c;最简单&#xff0c;一键安装&#xff0c;全程无忧。 二、通过编译源码包安装&#xff0c;需具备配置相关操作。 最后附&#xff1a;设置 Nginx 服务开…

项目6:基于大数据校园一卡通数据分析和可视化

1、项目简介 本项目是基于大数据的清华校园卡数据分析系统&#xff0c;通过Hadoop&#xff0c;spark等技术处理校园卡交易、卡号和商户信息数据。系统实现消费类别、男女消费差异、学院消费排行和年级对比等分析&#xff0c;并通过Web后端和可视化前端展示结果。项目运行便捷&…

Django项目中创建app并快速上手(pycharm Windows)

1.打开终端 我选择的是第二个 2.运行命令 python manage.py startapp 名称 例如&#xff1a; python manage.py startapp app01 回车&#xff0c;等待一下&#xff0c;出现app01的文件夹说明创建成功 3.快速上手 1.app注册 增加一行 "app01.apps.App01Config"&#…

使用Docker + Ollama在Ubuntu中部署deepseek

1、安装docker 这里建议用docker来部署&#xff0c;方便简单 安装教程需要自己找详细的&#xff0c;会用到跳过 如果你没有安装 Docker&#xff0c;可以按照以下步骤安装&#xff1a; sudo apt update sudo apt install apt-transport-https ca-certificates curl software-p…

信创领域的PostgreSQL管理员认证

信创产业&#xff0c;全称为信息技术应用创新产业&#xff0c;是中国为应对国际技术竞争、保障信息安全、实现科技自立而重点发展的战略性新兴产业。其核心目标是通过自主研发和生态构建&#xff0c;逐步替代国外信息技术产品&#xff0c;形成自主可控的国产化信息技术体系。 发…