我的shader学习之二

本篇文章实际上是一个类似阅读笔记的东西。

这里主要讲一个反射shader,就是反射场景到一个物体表面。那么等于光线照到物体上计算的颜色要去周围环境去采样。

按道理这个东西是怎么实现的呢,我认为是光线照到场景反射到物体表面,然后再反射到摄像机内的,那么在物体表面的点应该显示场景什么内容,那就是要从摄像机方向发射一束光线到这个点然后反射到场景纹理上,然后获取场景纹理上的这个点。

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 10/Reflection" {
	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_ReflectColor ("Reflection Color", Color) = (1, 1, 1, 1)		//反射颜色
		_ReflectAmount ("Reflect Amount", Range(0, 1)) = 1		//反射程度,如果是0就是一个白茶壶
		_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}	//天空盒
	}
	SubShader {
		Tags { "RenderType"="Opaque" "Queue"="Geometry"}
		
		Pass { 
			Tags { "LightMode"="ForwardBase" }
			
			CGPROGRAM
			
			#pragma multi_compile_fwdbase
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			
			fixed4 _Color;
			fixed4 _ReflectColor;
			fixed _ReflectAmount;
			samplerCUBE _Cubemap;				//立方体纹理
			
			struct a2v {
				float4 vertex : POSITION;		//模型空间pos
				float3 normal : NORMAL;			//法线
			};	
			
			struct v2f {
				float4 pos : SV_POSITION;		//裁剪空间法线
				float3 worldPos : TEXCOORD0;		//世界空间坐标
				fixed3 worldNormal : TEXCOORD1;		//世界空间内法线
				fixed3 worldViewDir : TEXCOORD2;	//世界空间内视角方向向量
				fixed3 worldRefl : TEXCOORD3;		//
				SHADOW_COORDS(4)			//阴影及衰减效果计算1,在片元着色器的输入结构体中加
			};
			
			v2f vert(a2v v) {
				v2f o;
				
				o.pos = UnityObjectToClipPos(v.vertex);		//这里注意,这个函数toClipPos是直接replace掉了UNITY_MATRIX_MVP矩阵,即从模型空间到世界空间到视角空间到裁剪空间的
				
				o.worldNormal = UnityObjectToWorldNormal(v.normal);	//这个函数是unityshader封装的把法线转换到世界坐标(模型空间转换世界空间)
				
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;	//这个是乘一个模型到世界空间的矩阵
				
				o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);		//emmm这个函数是获取世界上某个点到摄像机的向量
				
				// Compute the reflect dir in world space
				o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);		//这是reflect函数,这个函数是计算反射方向的函数,需求的是光线射入方向和法线,这里要计算的是从这个点上反射入我们眼睛的光线,那么就是视角向量在这个点的反射
				//我们知道worldViewDir是从这个点到摄像机的向量,那么这里就是求的光线从摄像机射过去的反射向量,
				
				//TRANSFER_SHADOW(o);		阴影及衰减效果计算2,在顶点着色器里这个实际上我关了也没有任何影响
				
				return o;
			}
			//真正计算颜色
			fixed4 frag(v2f i) : SV_Target {
				fixed3 worldNormal = normalize(i.worldNormal);			//法线标准化
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));			//获取该点的标准化光方向,从该点射向光源		
				fixed3 worldViewDir = normalize(i.worldViewDir);		//视角方向的标准化	
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;		//环境光	
				
				fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir));		//Color是材质的漫反射颜色  这个_LightColor0.rgb是第一个直射光的颜色		这里实际只是算了一个漫反射
				
				// Use the reflect dir in world space to access the cubemap
				fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;		//正方形纹理采样
				//采样位置是用worldRefl这个是世界坐标下的反射函数的返回值,可以理解为从A点发一束光线反射后进入viewDir,那么这个反射方向
				//就是从view发射一束光线的反射方向的反方向
				
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);	//unity内置函数,在片元着色器里,需求结构体和世界坐标,然后atten就是一个衰减和阴影结果的综合
				
				// Mix the diffuse color with the reflected color
				fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;
				//fixed3 color = ambient + diffuse;		//不加反射光就是一个单纯的白茶壶
				return fixed4(color, 1.0);
			}
			
			ENDCG
		}
	}
	FallBack "Reflective/VertexLit"
}

这里的核心就是根据视角方向和法线方向求出实际射入这个点的光线的反方向,然后根据这个反方向可以通过texCUBE中获取到

_Cubemap的对应位置的纹理,这里_Cubemap是一个sampleCUBE变量。

此外这里的fragment shader里的UNITY_LIGHT_ATTENUATION实际是一个内置函数,用于计算衰减和阴影的因子,实际上注释掉然后设置atten等于1你会发现没什么差距的。

fragment shader里计算出纹理,然后用RefectAmount在diffuse和reflection里插个值,就可以根据RefectAmount来进行(1-x)*a + x*b这种操作,获得一个相加后的颜色

这个是一个类似的效果

Shader(着色器)是用于在图形渲染过程中处理和操作像素数据的一种程序。学习Shader需要一定的编程基础,特别是对C++、OpenGL或DirectX等图形编程框架的熟悉。以下是一个关于学习Shader的计划: 1. 学习基本概念: - 了解计算机图形学的基本概念,如顶点、纹理、光照等。 - 学习Shader的基本组成部分,包括顶点着色器(Vertex Shader)、片段着色器(Fragment Shader)和几何着色器(Geometry Shader)。 2. 选择合适的编程语言和图形编程框架: - 根据个人喜好和项目需求,选择C++、C#或HLSL(High Level Shading Language)作为编写Shader的编程语言。 - 学习所选编程语言的基本语法和图形编程框架的使用方法。 3. 学习Shader语言: - 熟悉所选编程语言的Shader库,了解常用的Shader函数和结构。 - 学习编写基本的顶点着色器和片段着色器,掌握如何描述图形渲染的过程。 4. 学习高级Shader技术: - 学习纹理贴图、光照模型、阴影技术等高级Shader技术。 - 掌握如何使用多个着色器(如几何着色器和光栅化着色器)组合在一起实现复杂的渲染效果。 5. 实践项目: - 参与开源项目或自己创建项目,将所学的Shader知识应用到实际项目中。 - 通过不断地实践和优化,提高自己的Shader编程能力。 6. 深入学习: - 阅读相关书籍和教程,了解更多关于Shader的高级技术和实现方法。 - 参加线上或线下的技术社区,与其他开发者交流学习经验,共同进步。 总之,学习Shader需要时间和耐心,通过不断地学习和实践,你将能够掌握这一技能并在图形渲染领域取得突破。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值