unity 代码运行时间 和 反射的使用

本文展示了如何在Unity中使用System.Diagnostics.Stopwatch来测量代码执行时间,并结合反射进行方法调用。通过Stopwatch的Start、Stop方法记录代码运行的毫秒数,再转换为小时、分钟、秒等单位。同时,演示了如何利用反射遍历类的静态和实例方法,并执行特定开头的方法。
https://msdn.microsoft.com/zh-cn/library/vstudio/system.diagnostics.stopwatch(v=vs.100).aspx
 
 
 
 
 
using UnityEngine;
using System.Collections;
using System.Reflection;
using System;

public class ReflTestDemo : MonoBehaviour {

	// Use this for initialization
	void Start () {

		int start = System.Environment.TickCount; 
		fun ();
		int end = System.Environment.TickCount; 
		
		Debug.Log("strat - end :" + (end - start));//单位毫秒

		/*
		    Stopwatch 实例可以测量一个时间间隔的运行时间,也可以测量多个时间间隔的总运行时间。
		    在典型的 Stopwatch 方案中,先调用 Start 方法,然后调用 Stop 方法,最后使用 Elapsed 属性检查运行时间。
			Stopwatch 实例或者在运行,或者已停止;使用 IsRunning 可以确定 Stopwatch 的当前状态。
			使用 Start 可以开始测量运行时间;使用 Stop 可以停止测量运行时间。
			通过属性 Elapsed、ElapsedMilliseconds 或 ElapsedTicks 查询运行时间值。 
			当实例正在运行或已停止时,可以查询运行时间属性。
			运行时间属性在 Stopwatch 运行期间稳固递增;在该实例停止时保持不变。
			默认情况下,Stopwatch 实例的运行时间值相当于所有测量的时间间隔的总和。
			每次调用 Start 时开始累计运行时间计数;每次调用 Stop 时结束当前时间间隔测量,并冻结累计运行时间值。
			使用 Reset 方法可以清除现有 Stopwatch 实例中的累计运行时间。
		 */
		System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
		
		stopwatch.Start(); //  开始监视代码运行时间
		fun ();
		stopwatch.Stop(); //  停止监视



		/*
			Days	获取当前 TimeSpan 结构所表示的时间间隔的天数部分。
			Hours	获取当前 TimeSpan 结构所表示的时间间隔的小时数部分。
			Milliseconds	获取当前 TimeSpan 结构所表示的时间间隔的毫秒数部分。
			Minutes	获取当前 TimeSpan 结构所表示的时间间隔的分钟数部分。
			Seconds	获取当前 TimeSpan 结构所表示的时间间隔的秒数部分。
			Ticks	获取表示当前 TimeSpan 结构的值的刻度数。
			TotalDays	获取以整天数和天的小数部分表示的当前 TimeSpan 结构的值。
			TotalHours	获取以整小时数和小时的小数部分表示的当前 TimeSpan 结构的值。
			TotalMilliseconds	获取以整毫秒数和毫秒的小数部分表示的当前 TimeSpan 结构的值。
			TotalMinutes	获取以整分钟数和分钟的小数部分表示的当前 TimeSpan 结构的值。
			TotalSeconds	获取以整秒数和秒的小数部分表示的当前 TimeSpan 结构的值。
		 */
		System.TimeSpan timespan = stopwatch.Elapsed;

		double hours = timespan.TotalHours; // 总小时
		double minutes = timespan.TotalMinutes;  // 总分钟
		double seconds = timespan.TotalSeconds;  //  总秒数
		double milliseconds = timespan.TotalMilliseconds;  //  总毫秒数
		
		//打印代码执行时间
		Debug.Log("hours " + hours);
		Debug.Log("minutes " + minutes);
		Debug.Log("seconds " + seconds);
		Debug.Log("milliseconds " + milliseconds);

	}
	
	// Update is called once per frame
	void Update () {
	
	}

	void fun()
	{
		string strText = "zhaoguanghui";  
		
		BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | 
		                      BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);  
		
		Type t = typeof(ReflTest1);
		MethodInfo[] mi = t.GetMethods(flags);  
		System.Object obj = Activator.CreateInstance(t);  
		
		foreach (MethodInfo m in mi)  
		{  
			if (m.Name.StartsWith("Write"))
			{  
				m.Invoke(obj, new object[] { strText });  
			}  
		}  
		
		MethodInfo mMy = t.GetMethod("MyWrite");  
		if (mMy != null)  
		{  
			mMy.Invoke(obj, new object[] { strText });  
		}  
	}

	void fun2()
	{
		// Define two dates.
		DateTime date1 = new DateTime(2010, 1, 1, 8, 0, 15);
		DateTime date2 = new DateTime(2010, 8, 18, 13, 30, 30);

		TimeSpan interval = date2 - date1;

		Console.WriteLine("{0} - {1} = {2}", date2, date1, interval.ToString());
		Console.WriteLine("   {0,-35} {1,20}", "Value of Days Component:", interval.Days);
		Console.WriteLine("   {0,-35} {1,20}", "Total Number of Days:", interval.TotalDays);
		Console.WriteLine("   {0,-35} {1,20}", "Value of Hours Component:", interval.Hours);
		Console.WriteLine("   {0,-35} {1,20}", "Total Number of Hours:", interval.TotalHours);
		Console.WriteLine("   {0,-35} {1,20}", "Value of Minutes Component:", interval.Minutes);
		Console.WriteLine("   {0,-35} {1,20}", "Total Number of Minutes:", interval.TotalMinutes);
		Console.WriteLine("   {0,-35} {1,20:N0}", "Value of Seconds Component:", interval.Seconds);
		Console.WriteLine("   {0,-35} {1,20:N0}", "Total Number of Seconds:", interval.TotalSeconds);
		Console.WriteLine("   {0,-35} {1,20:N0}", "Value of Milliseconds Component:", interval.Milliseconds);
		Console.WriteLine("   {0,-35} {1,20:N0}", "Total Number of Milliseconds:", interval.TotalMilliseconds);
		Console.WriteLine("   {0,-35} {1,20:N0}", "Ticks:", interval.Ticks);
		//		the example displays the following output:

		//      8/18/2010 1:30:30 PM - 1/1/2010 8:00:15 AM = 229.05:30:15
		//      Value of Days Component:                             229
		//      Total Number of Days:                   229.229340277778
		//      Value of Hours Component:                              5
		//      Total Number of Hours:                  5501.50416666667
		//      Value of Minutes Component:                           30
		//      Total Number of Minutes:                       330090.25
		//      Value of Seconds Component:                           15
		//      Total Number of Seconds:                      19,805,415
		//      Value of Milliseconds Component:                       0
		//      Total Number of Milliseconds:             19,805,415,000
		//      Ticks:                               198,054,150,000,000
	}
}
Mirror-BumpSpec.shader 实时镜面反射shader 可以配合法线贴图一起用 适用于平面物体 Mirror-AlphaBumpSpec.shader 实时镜面发射、透明材质,可以同时反射透明效果,也可以配合法线贴图,适用于平面物体 Mirror-AlphaSpecSphere.shader 与上面材质相同,适用于球面物体,不能使用法线贴图 使用很简单,就几个参数,具体效果要慢慢调节,简单解说几个关键参数: Main Material Blend Level:主材质的混合浓度 Bump Rate:法线贴图强度 Reflection Rate 反射强度 Reflective Color 反射颜色 Reflective Distortion 反射图受法线影响强度 Transparency 同时透明、反射的材质,调节透明反射混合的比例 ,0是全反射 1是全透明 Distortion 反射、透明受法线影响的强度 另外每个shader都有个自动的贴图是不需要设置的,由脚本自动设置 Mirror脚本参数: Disable Pixel Lights 禁用Pixel Lights,对应unity摄像机的这个设置 Texture Size 反射贴图精度 缺省是256 如果觉得反射很模糊直接把这个加大就行了 即时生效 所以不要设太大了,1024足以应付绝大多数要求了。 Is Flat Mirror:如果是平面反射物体就勾上,球体点掉,材质也要选择相应的 Reflect Layer 反射的culling mask,可以屏蔽掉指定的层 shader脚本都是参考unity的water效果,脚本基本就是water包里反射脚本的简化版 由于只是模拟,并不是真正的光线跟踪效果,所以折射效果并不准确,但是基本能满足观感。 注意:目前只适用于forward 渲染,Deferred下会有贴图倒置、光线暗淡的问题 尽量避免反射物体互相反射,消耗巨大而且效果不准确 实时反射本身也开销极大,尽量不要滥用
<think>好的,我现在需要解决用户的问题:UnityShader中逐顶点漫反射代码运行结果为黑色的原因及解决方案。用户之前已经提过类似的问题,但这次特别强调逐顶点的情况,我需要结合之前的回答新的引用内容来调整。 首先,回顾之前的回答,用户的问题可能出在光照计算位置、法线处理、光源数据或编译指令上。但这次是逐顶点,所以重点可能不同。根据用户提供的引用[3],逐顶点计算可能在片元着色器中出现插值误差,导致黑色。但用户现在的问题是逐顶点本身的结果是黑色,可能需要检查顶点着色器中的计算是否正确。引用[2]提到逐顶点漫反射使用半兰伯特模型可以改善,但用户现在的结果是黑色,可能未正确处理法线或光源方向。引用[4]提到顶点着色器的输入结构是否正确,比如POSITIONNORMAL的语义是否正确。引用[5]指出光源方向是否正确获取,以及是否缺少平行光源。现在,我需要整理可能的原因:1.**法线转换错误**:顶点着色器中法线未正确转换到世界空间,或者未归一化。例如,在引用[3]中,法线可能在模型空间直接使用,而没有转换到世界空间,导致点积计算错误。 2. **光源方向获取错误**:在顶点着色器中是否正确获取了_WorldSpaceLightPos0,特别是在逐顶点的情况下,是否在顶点阶段正确计算了光的方向。3.**颜色输出问题**:顶点着色器中的颜色计算是否正确传递给片元着色器,可能颜色未被正确插值或输出。4.**缺少光照宏或头文件**:是否在Shader中正确包含了Lighting.cginc等必要的头文件,以及编译指令是否正确,如#pragmamulti_compile_fwdbase。5.**场景中没有有效光源**:用户可能未添加平行光,导致_LightColor0为空,颜色为黑色。 解决方案需要针对这些点逐一检查。例如,确保法线转换正确,使用mulunity_WorldToObject矩阵,并归一化。检查光源方向是否正确,场景中是否有平行光,以及Shader是否正确处理了这些数据。 此外,用户提供的引用[3]提到将光照计算移到片元着色器解决插值问题,但用户现在的问题是逐顶点,可能需要对比两种方法的差异,确认是否顶点计算导致的问题。最后,生成相关问题时需要考虑用户可能进一步的问题,比如如何调试顶点数据、逐顶点与逐像素的区别等。</think>### Unity Shader逐顶点漫反射出现黑色的原因及解决方案 --- #### 一、核心原因分析 1. **法线向量未正确转换** 逐顶点计算时未将法线从**模型空间**转换到**世界空间**,或未进行归一化处理。错误示例: ```glsl // 错误:直接使用模型空间法线 float3 normal = v.normal; ``` 修正方法: ```glsl // 正确转换到世界空间并归一化 float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); [^4] ``` 2. **光源方向计算错误** 未正确获取平行光方向`_WorldSpaceLightPos0.xyz`,或未处理点光源的特殊情况(平行光方向需归一化): ```glsl // 平行光方向直接取前三个分量 float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); [^5] ``` 3. **颜色输出未关联顶点数据** 逐顶点计算的光照结果未正确传递给片元着色器: ```glsl struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; // 必须通过COLOR语义传递 }; ``` 4. **缺少关键编译指令** 未启用光照宏导致无法获取光源参数: ```glsl #pragma multi_compile_fwdbase // 必须声明[^1] #include "Lighting.cginc" // 必须包含 ``` --- #### 二、修正代码示例 ```glsl Shader "Custom/VertexDiffuse" { Properties { _Color ("Main Color", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; // 模型空间法线[^4] }; struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; // 颜色输出通道 }; v2f vert (appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); // 法线转换到世界空间 float3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); // 光源方向计算 float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 漫反射计算 float diff = max(0, dot(worldNormal, lightDir)); o.color = _LightColor0 * _Color * diff; return o; } fixed4 frag (v2f i) : SV_Target { return i.color; // 直接输出插值后的颜色 } ENDCG } } } ``` --- #### 三、关键验证步骤 1. **法线方向可视化** 在片元着色器中输出法线向量: ```glsl return fixed4(worldNormal * 0.5 + 0.5, 1); // 检查是否为合理颜色[^3] ``` 2. **光源方向验证** 打印`_WorldSpaceLightPos0`值: ```glsl return fixed4(lightDir * 0.5 + 0.5, 1); // 应随光源旋转变化[^5] ``` 3. **数学公式验证** 漫反射强度计算公式: $$ I_{\text{diffuse}} = \max(0, \mathbf{n} \cdot \mathbf{l}) \cdot L_{\text{color}} \cdot M_{\text{color}} $$ 其中$\mathbf{n}$为法线向量,$\mathbf{l}$为光源方向向量[^2] --- #### 四、进阶优化 1. **半兰伯特修正** 将线性计算改为非线性映射: ```glsl float diff = dot(worldNormal, lightDir) * 0.5 + 0.5; // 消除纯黑区域[^2] ``` 2. **顶点颜色插值调试** 在片元着色器中检查颜色插值是否正确: ```glsl return fixed4(i.color.rgb, 1); // 应显示渐变效果 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值