<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>风牛菜籽 &#187; shader</title>
	<atom:link href="http://www.caiyanpei.com/category/network-technology/shader/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.caiyanpei.com</link>
	<description>拖延症重症患者</description>
	<lastBuildDate>Tue, 25 Mar 2025 01:51:19 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6.1</generator>
		<item>
		<title>Unity Shader：从“五彩斑斓的黑”到丝滑渲染的调试探索</title>
		<link>http://www.caiyanpei.com/unity_shader_debug_check/</link>
		<comments>http://www.caiyanpei.com/unity_shader_debug_check/#comments</comments>
		<pubDate>Sun, 23 Apr 2023 12:46:26 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[shader]]></category>
		<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[调优]]></category>
		<category><![CDATA[unity]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=653</guid>
		<description><![CDATA[在Unity中编写Shader时，常常会遇到一些令人抓狂的问题：颜色显示异常、光 &#8230; <a href="http://www.caiyanpei.com/unity_shader_debug_check/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity中编写Shader时，常常会遇到一些令人抓狂的问题：颜色显示异常、光照计算错误、性能突然暴跌，甚至直接导致屏幕“五彩斑斓”或完全黑屏。由于Shader代码在GPU上执行，无法像C#一样逐行调试，这让问题定位变得异常困难。本文探讨几个实用调试技巧，一起尝试下驯服“暴躁”的Shader代码。</p>
<hr />
<h1>​<strong>一、基础调试工具：你的Shader显微镜</strong></h1>
<h2>1. ​<strong>假色输出法（False Color Debugging）​</strong></h2>
<p>当计算结果超出预期范围时，将中间值映射为可视颜色是最直接的调试方式。</p>
<p><strong>示例：​</strong></p>
<pre><code>// 将法线向量可视化（范围[-1,1] → [0,1]）
fixed4 frag (v2f i) : SV_Target {
    float3 normal = i.worldNormal * 0.5 + 0.5; // 映射到颜色范围
    return fixed4(normal, 1.0);
}</code></pre>
<p>通过逐步替换输出值，可以快速定位哪一步计算出现了异常。</p>
<h2>2. ​<strong>分阶段注释法</strong></h2>
<p>将复杂的Shader拆分成多个阶段，逐步启用/禁用代码块：</p>
<ul>
<li>注释掉光照计算，仅输出基础颜色</li>
<li>逐步启用法线贴图、高光、阴影等模块</li>
<li>使用宏定义快速切换（如 <code>#define ENABLE_SPECULAR 0</code>）</li>
</ul>
<h2>3. ​<strong>Unity帧调试器（Frame Debugger）​</strong></h2>
<ul>
<li>​<strong>路径：Window &gt; Analysis &gt; Frame Debugger</strong></li>
<li>逐帧查看Draw Call的执行顺序</li>
<li>检查渲染目标（Render Texture）的中间结果</li>
<li>验证Uniform变量（如矩阵、光照参数）是否正确传递</li>
</ul>
<hr />
<h1>​<strong>二、高级武器库</strong></h1>
<h2>1. ​<strong>RenderDoc：GPU级别的侦探工具</strong></h2>
<ul>
<li>​<strong>适用场景</strong>：深度分析渲染管线、纹理采样、缓冲区内容</li>
<li>​<strong>操作步骤</strong>：
<ol>
<li>在Unity中启动游戏并触发问题</li>
<li>使用RenderDoc捕获一帧</li>
<li>检查Shader输入/输出、纹理坐标、顶点数据</li>
</ol>
</li>
<li>​<strong>关键功能</strong>：
<ul>
<li>查看每个像素的历史记录（Pixel History）</li>
<li>动态修改Shader变量并实时预览</li>
</ul>
</li>
</ul>
<h2>2. ​<strong>Shader Variant剥离（Preprocessor魔法）​</strong></h2>
<p>通过自定义预处理指令，快速定位多平台兼容性问题：</p>
<pre><code>#pragma shader_feature _USE_NORMAL_MAP
// ...
#if _USE_NORMAL_MAP
    // 法线贴图相关代码
#endif</code></pre>
<p>在材质面板中切换<code>_USE_NORMAL_MAP</code>开关，观察表现差异。</p>
<h2>3. ​<strong>GPU Instancing的“陷阱”​</strong></h2>
<p>当使用<code>UNITY_INSTANCING_BUFFER_START</code>时，若出现数据错乱：</p>
<ul>
<li>检查<code>unity_WorldTransformParams</code>是否正确处理</li>
<li>在Vertex Shader中输出实例ID，验证数据索引：
<pre><code>float instanceID = (float)unity_InstanceID;
return fixed4(instanceID, 0, 0, 1);</code></pre>
</li>
</ul>
<hr />
<h1>​<strong>三、常见问题急救手册</strong></h1>
<h2>​<strong>1. 颜色全黑/全白？先检查这些！​</strong></h2>
<ul>
<li>​<strong>UV坐标错误</strong>：输出UV为颜色，观察是否超出[0,1]范围</li>
<li>​<strong>法线方向错误</strong>：在片段着色器中返回<code>fixed4(i.normal * 0.5 + 0.5, 1)</code></li>
<li>​<strong>光照向量计算错误</strong>：手动硬编码光照方向测试</li>
<li>​<strong>Alpha通道问题</strong>：检查混合模式（Blend）和深度写入（ZWrite）</li>
</ul>
<h2>​<strong>2. 性能断崖下跌？GPU在“燃烧”什么？</strong></h2>
<ul>
<li>​<strong>过度分支</strong>：避免在片段着色器中使用<code>if</code>语句，改用<code>step()</code>或<code>lerp()</code></li>
<li>​<strong>采样次数爆炸</strong>：合并纹理采样（如使用RGBA通道存储不同数据）</li>
<li>​<strong>精度问题</strong>：将不必要的<code>float</code>改为<code>half</code>或<code>fixed</code></li>
<li>​<strong>隐藏的循环</strong>：检查<code>for</code>循环是否在片段着色器中意外执行多次</li>
</ul>
<h2>​<strong>3. 平台差异：为什么Android和PC表现不同？</strong></h2>
<ul>
<li>​<strong>精度差异</strong>：移动端GPU的<code>half</code>可能只有10位精度</li>
<li>​<strong>纹理压缩格式</strong>：检查ASTC/RGBA32等格式的兼容性</li>
<li>​<strong>ES3.0限制</strong>：避免使用<code>tex2Dlod</code>等需要Shader Model 3.0以上特性的函数</li>
</ul>
<hr />
<h1>​<strong>四、防御性编码</strong></h1>
<h2>1. ​<strong>数学计算的“安全网”​</strong></h2>
<ul>
<li>使用<code>saturate()</code>函数限制数值范围：
<pre><code>float specular = saturate(dot(N, L)); // 避免负数导致意外结果</code></pre>
</li>
<li>除法保护：<code>(a + 1e-5) / (b + 1e-5)</code></li>
</ul>
<h2>2. ​<strong>Debug宏的妙用</strong></h2>
<p>自定义调试宏，快速切换调试模式：</p>
<pre><code>#define DEBUG_NORMAL 1

fixed4 frag (v2f i) : SV_Target {
    #if DEBUG_NORMAL
        return fixed4(i.normal * 0.5 + 0.5, 1);
    #else
        // 正式代码
    #endif
}</code></pre>
<h2>3. ​<strong>版本兼容性声明</strong></h2>
<p>在Shader开头明确声明目标级别：</p>
<pre><code>#pragma target 3.5
#pragma require tessellation</code></pre>
<hr />
<h1>​<strong>五、调试思维</strong></h1>
<ol>
<li>​<strong>最小化复现</strong>：将Shader简化到仅保留问题的最小代码块</li>
<li>​<strong>对比法</strong>：与官方Standard Shader或已知正常Shader对比输入输出</li>
<li>​<strong>边界值测试</strong>：测试UV(0,0)、(1,1)、法线(0,0,1)等极端情况</li>
<li>​<strong>物理合理性检查</strong>：高光是否能量守恒？光照衰减是否符合预期？</li>
</ol>
<hr />
<p>可能用到的工具清单</p>
<ul>
<li><a title="VSCode Shaderlab插件" href="https://marketplace.visualstudio.com/items?itemName=amlovey.shaderlabvscodefree" target="_blank">VSCode Shaderlab</a>插件：支持语法高亮和自动补全</li>
<li><a title="Unity Graphics Test Framework" href="https://docs.unity3d.com/Packages/com.unity.test-framework@1.1/manual/reference-attribute-unitytest.html" target="_blank">Unity Graphics Test Framework</a>：自动化测试Shader表现</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/unity_shader_debug_check/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
