<?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>风牛菜籽</title>
	<atom:link href="http://www.caiyanpei.com/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>C++客户端使用RenderDoc和Visual Studio截帧工具调优</title>
		<link>http://www.caiyanpei.com/c_renderdoc_visual-studio_opt/</link>
		<comments>http://www.caiyanpei.com/c_renderdoc_visual-studio_opt/#comments</comments>
		<pubDate>Mon, 25 Dec 2023 13:44:09 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[调优]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能分析]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=651</guid>
		<description><![CDATA[在C++游戏客户端开发中，经常会碰到渲染性能优化各种头疼的问题。为了分析渲染问题 &#8230; <a href="http://www.caiyanpei.com/c_renderdoc_visual-studio_opt/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在C++游戏客户端开发中，经常会碰到渲染性能优化各种头疼的问题。为了分析渲染问题并找到性能瓶颈，可以借助截帧工具，如<strong>RenderDoc或</strong><strong>Visual Studio自带的截帧工具</strong>。本文探讨使用这两种工具进行调试和优化，尝试提升开发中客户端的渲染性能。</p>
<hr />
<h1>一、为什么需要截帧工具？</h1>
<p>在游戏开发中，渲染性能问题往往表现为帧率下降、卡顿或画面异常。通过截帧工具，我们可以：</p>
<ol>
<li>​<strong>分析每一帧的渲染过程</strong>：查看Draw Call、渲染状态、资源使用情况等。</li>
<li>​<strong>定位性能瓶颈</strong>：找到渲染性能问题的根源，如过多的Draw Call、高复杂度的Shader、不合理的资源使用等。</li>
<li>​<strong>验证优化效果</strong>：通过对比优化前后的截帧数据，验证优化策略的有效性。</li>
</ol>
<hr />
<h1>二、RenderDoc的使用</h1>
<p>RenderDoc是一款开源的图形调试工具，支持DirectX、OpenGL、Vulkan等多种图形API。以下是使用RenderDoc优化C++游戏客户端的步骤：</p>
<h2>1. ​<strong>安装与配置</strong></h2>
<ul>
<li>下载并安装RenderDoc：<a title="RenderDoc官网" href="https://renderdoc.org/" target="_blank">RenderDoc官网</a></li>
<li>启动RenderDoc，配置游戏客户端的可执行文件路径和启动参数。</li>
</ul>
<h2>2. ​<strong>捕获帧数据</strong></h2>
<ul>
<li>在RenderDoc中点击“Launch”启动游戏客户端。</li>
<li>在游戏中运行到需要调试的场景，按下<code>F12</code>（默认快捷键）捕获当前帧。</li>
<li>捕获完成后，RenderDoc会自动加载帧数据。</li>
</ul>
<h2>3. ​<strong>分析帧数据</strong></h2>
<ul>
<li>​<strong>Draw Call分析</strong>：查看每一帧的Draw Call数量，找出过多的Draw Call或重复的渲染操作。</li>
<li>​<strong>资源查看</strong>：检查纹理、缓冲区等资源的使用情况，确保资源加载和释放合理。</li>
<li>​<strong>Shader调试</strong>：查看Shader的输入输出，分析Shader的性能问题。</li>
<li>​<strong>渲染状态</strong>：检查深度测试、混合模式等渲染状态，确保设置正确。</li>
</ul>
<h2>4. ​<strong>优化建议</strong></h2>
<ul>
<li>​<strong>减少Draw Call</strong>：使用批处理（Batching）或实例化（Instancing）减少Draw Call数量。</li>
<li>​<strong>优化Shader</strong>：简化Shader计算，减少纹理采样次数。</li>
<li>​<strong>合理使用资源</strong>：压缩纹理格式，减少显存占用。</li>
</ul>
<hr />
<h1>三、Visual Studio截帧工具的使用指南</h1>
<p>Visual Studio自带的截帧工具（Graphics Debugger）是DirectX开发的强大调试工具，以下是使用步骤：</p>
<h2>1. ​<strong>启用Graphics Debugger</strong></h2>
<ul>
<li>在Visual Studio中打开游戏客户端项目。</li>
<li>点击“调试”菜单，选择“Graphics &gt; Start Graphics Debugging”。</li>
</ul>
<h2>2. ​<strong>捕获帧数据</strong></h2>
<ul>
<li>游戏启动后，运行到需要调试的场景。</li>
<li>在Visual Studio中点击“Graphics &gt; Capture Frame”捕获当前帧。</li>
</ul>
<h2>3. ​<strong>分析帧数据</strong></h2>
<ul>
<li>​<strong>事件列表</strong>：查看每一帧的渲染事件，分析Draw Call和渲染状态。</li>
<li>​<strong>资源查看</strong>：检查纹理、缓冲区等资源的使用情况。</li>
<li>​<strong>Pipeline状态</strong>：查看顶点着色器、像素着色器等阶段的输入输出。</li>
<li>​<strong>帧性能分析</strong>：使用“Frame Analysis”工具分析每一帧的性能瓶颈。</li>
</ul>
<h2>4. ​<strong>优化建议</strong></h2>
<ul>
<li>​<strong>减少渲染状态切换</strong>：合并相同渲染状态的Draw Call。</li>
<li>​<strong>优化资源使用</strong>：使用Mipmaps、压缩纹理格式。</li>
<li>​<strong>Shader优化</strong>：减少复杂计算，使用低精度数据类型。</li>
</ul>
<hr />
<h1>四、常见优化点</h1>
<h2>1：Draw Call过多</h2>
<ul>
<li>​<strong>问题描述</strong>：游戏帧率下降，RenderDoc显示Draw Call数量过多。</li>
<li>​<strong>可能解决方案</strong>：
<ol>
<li>使用批处理（Batching）合并相同材质的物体。</li>
<li>使用实例化（Instancing）渲染大量相同的物体。</li>
</ol>
</li>
<li>​<strong>验证效果</strong>：RenderDoc显示Draw Call数量显著减少，帧率提升。</li>
</ul>
<h2>2：Shader性能瓶颈</h2>
<ul>
<li>​<strong>问题描述</strong>：Visual Studio截帧工具显示像素着色器耗时较高。</li>
<li>​<strong>可能解决方案</strong>：
<ol>
<li>简化Shader计算，减少纹理采样次数。</li>
<li>使用低精度数据类型（如<code>half</code>代替<code>float</code>）。</li>
</ol>
</li>
<li>​<strong>验证效果</strong>：Visual Studio帧性能分析显示像素着色器耗时降低。</li>
</ul>
<h2>3：纹理资源过大</h2>
<ul>
<li>​<strong>问题描述</strong>：RenderDoc显示纹理资源占用显存过高。</li>
<li>​<strong>可能解决方案</strong>：
<ol>
<li>压缩纹理格式（如BC7、ASTC）。</li>
<li>使用Mipmaps优化远处纹理的渲染。</li>
</ol>
</li>
<li>​<strong>验证效果</strong>：RenderDoc显示显存占用显著减少。</li>
</ul>
<hr />
<h1>五、工具对比与选择</h1>
<div>
<table>
<thead>
<tr>
<th>工具</th>
<th>优点</th>
<th>缺点</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>​<strong>RenderDoc</strong></td>
<td>跨平台，支持多种图形API，功能强大</td>
<td>需要单独安装，学习曲线较陡</td>
<td>跨平台开发，深度调试</td>
</tr>
<tr>
<td>​<strong>Visual Studio</strong></td>
<td>集成开发环境，与C++项目无缝衔接</td>
<td>仅支持DirectX，功能相对有限</td>
<td>DirectX开发，快速调试</td>
</tr>
</tbody>
</table>
</div>
<p><strong>选择建议</strong>：</p>
<ul>
<li>如果需要跨平台支持或深度调试，选择RenderDoc。</li>
<li>如果是DirectX开发且追求快速调试，选择Visual Studio。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/c_renderdoc_visual-studio_opt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>几个轻量级离线AI大模型</title>
		<link>http://www.caiyanpei.com/%e5%87%a0%e4%b8%aa%e8%bd%bb%e9%87%8f%e7%ba%a7%e7%a6%bb%e7%ba%bfai%e5%a4%a7%e6%a8%a1%e5%9e%8b/</link>
		<comments>http://www.caiyanpei.com/%e5%87%a0%e4%b8%aa%e8%bd%bb%e9%87%8f%e7%ba%a7%e7%a6%bb%e7%ba%bfai%e5%a4%a7%e6%a8%a1%e5%9e%8b/#comments</comments>
		<pubDate>Sat, 27 May 2023 13:56:07 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[AI]]></category>
		<category><![CDATA[技术]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=610</guid>
		<description><![CDATA[对于适合手游的轻量级离线AI大模型，主要用于NPC的聊天系统，以下是一些可考虑的 &#8230; <a href="http://www.caiyanpei.com/%e5%87%a0%e4%b8%aa%e8%bd%bb%e9%87%8f%e7%ba%a7%e7%a6%bb%e7%ba%bfai%e5%a4%a7%e6%a8%a1%e5%9e%8b/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>对于适合手游的轻量级离线AI大模型，主要用于NPC的聊天系统，以下是一些可考虑的模型：</p>
<p>1. GPT-2：GPT-2是由OpenAI发布的一个基于Transformer的自然语言处理模型。它在生成文本方面表现出色，包含了大量的预训练参数。可以使用适当规模的GPT-2模型来构建NPC的聊天系统。虽然GPT-2较大，但可以使用一些技术来优化它，以适应手游环境。</p>
<p>2. MobileBERT： MobileBERT是Google发布的适用于移动设备的轻量级BERT模型。它是基于BERT的精简版本，旨在在保持较高性能的同时减小模型大小和计算复杂度。MobileBERT适用于NPC的聊天系统，并且可以在手游中进行本地离线计算。</p>
<p>3. ChatGPT： ChatGPT是OpenAI发布的面向对话任务的GPT模型。它专门用于生成自然语言的对话，适合用于NPC的聊天系统。类似于GPT-2，可以使用适当规模的ChatGPT模型来满足手游的性能需求。</p>
<p>4. MiniLM：MiniLM是一种轻量级的Transformer模型，是对BERT的改进版本。它具有较小的模型尺寸和计算复杂度，并且在自然语言处理任务中表现不错。MiniLM适合用于NPC的聊天系统，并可以在手游中进行本地离线计算。</p>
<p>5. TinyBERT：TinyBERT是对BERT进行压缩和优化的模型，以减小模型大小和计算资源的消耗。虽然比传统的BERT模型小得多，但TinyBERT仍然可以保持相对较高的准确性。它适合用于NPC的聊天系统，并且适用于在手游中进行本地离线计算。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/%e5%87%a0%e4%b8%aa%e8%bd%bb%e9%87%8f%e7%ba%a7%e7%a6%bb%e7%ba%bfai%e5%a4%a7%e6%a8%a1%e5%9e%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
		<item>
		<title>Unity Shader优化策略：提升性能与效果的关键</title>
		<link>http://www.caiyanpei.com/unity-shader-optimized/</link>
		<comments>http://www.caiyanpei.com/unity-shader-optimized/#comments</comments>
		<pubDate>Sat, 12 Nov 2022 13:25:40 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[shader]]></category>
		<category><![CDATA[unity]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=647</guid>
		<description><![CDATA[在Unity开发中，Shader是渲染效果的核心，但复杂的Shader往往会带来 &#8230; <a href="http://www.caiyanpei.com/unity-shader-optimized/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity开发中，Shader是渲染效果的核心，但复杂的Shader往往会带来性能问题。为了在保证视觉效果的同时提升性能，Shader优化成为了我们平常必须要理解应用的一环。本文主要探讨Unity中Shader优化的策略。</p>
<hr />
<h1>一、Shader优化的重要性</h1>
<p>Shader是GPU执行的程序，负责计算每个像素的颜色和光照效果。复杂的Shader会导致以下问题：</p>
<ul>
<li>​<strong>GPU负载过高</strong>：帧率下降，游戏卡顿。</li>
<li>​<strong>发热和耗电</strong>：移动设备性能瓶颈。</li>
<li>​<strong>渲染效率低</strong>：影响整体游戏体验。</li>
</ul>
<p>因此，Shader优化不仅是提升性能的关键，也是保证游戏流畅运行的必要手段。</p>
<hr />
<h1>二、Shader优化的核心策略</h1>
<h2>1. ​<strong>减少计算复杂度</strong></h2>
<ul>
<li>​<strong>避免不必要的计算</strong>：在Shader中只计算真正需要的值。例如，如果不需要法线贴图，就不要计算法线相关的值。</li>
<li>​<strong>简化数学运算</strong>：使用低精度的数据类型（如<code>half</code>代替<code>float</code>），减少复杂的数学运算（如<code>pow</code>、<code>sin</code>、<code>cos</code>等）。</li>
<li>​<strong>分支优化</strong>：尽量避免在Shader中使用<code>if</code>语句，因为GPU对分支处理效率较低。可以使用<code>step</code>或<code>lerp</code>等函数替代。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>// 不推荐
if (value &gt; 0.5) {
    color = red;
} else {
    color = blue;
}

// 推荐
color = lerp(blue, red, step(0.5, value));</code></pre>
<h2>2. ​<strong>优化纹理采样</strong></h2>
<ul>
<li>​<strong>减少纹理采样次数</strong>：每次纹理采样都会消耗性能，尽量减少采样次数。例如，将多个纹理合并为一张纹理（纹理图集）。</li>
<li>​<strong>使用Mipmaps</strong>：启用Mipmaps可以减少远处纹理的采样复杂度，提升性能。</li>
<li>​<strong>优化纹理格式</strong>：根据需求选择合适的纹理格式（如ETC2、ASTC），减少显存占用。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>// 不推荐
float4 color1 = tex2D(_MainTex, uv1);
float4 color2 = tex2D(_DetailTex, uv2);

// 推荐
float4 color = tex2D(_CombinedTex, uv);</code></pre>
<h2>3. ​<strong>优化光照计算</strong></h2>
<ul>
<li>​<strong>使用简化光照模型</strong>：在移动设备上，可以使用Lambert或Blinn-Phong等简化光照模型，而不是复杂的PBR模型。</li>
<li>​<strong>烘焙光照</strong>：将静态物体的光照信息烘焙到光照贴图中，减少实时计算。</li>
<li>​<strong>减少实时光源</strong>：尽量减少场景中的实时光源数量，使用点光源或聚光灯替代平行光。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>// 不推荐（复杂PBR）
float3 brdf = CalculateBRDF(normal, viewDir, lightDir);

// 推荐（简化Blinn-Phong）
float3 diffuse = max(dot(normal, lightDir), 0.0) * _LightColor;
float3 specular = pow(max(dot(reflectDir, viewDir), 0.0), _Gloss) * _SpecularColor;</code></pre>
<h2>4. ​<strong>减少顶点着色器计算</strong></h2>
<ul>
<li>​<strong>将计算移到片段着色器</strong>：如果某些计算在顶点着色器和片段着色器中重复，可以将它们移到片段着色器中，减少顶点着色器的负载。</li>
<li>​<strong>优化顶点数据</strong>：减少顶点数据的数量，例如使用压缩的顶点格式。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>// 不推荐（在顶点着色器中计算光照）
v2f vert(appdata v) {
    v2f o;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    o.normal = UnityObjectToWorldNormal(v.normal);
    o.lightDir = normalize(_WorldSpaceLightPos0.xyz - o.worldPos);
    return o;
}

// 推荐（在片段着色器中计算光照）
v2f vert(appdata v) {
    v2f o;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    o.normal = UnityObjectToWorldNormal(v.normal);
    return o;
}</code></pre>
<h2>5. ​<strong>使用Shader变体</strong></h2>
<ul>
<li>​<strong>减少变体数量</strong>：使用<code>#pragma multi_compile</code>或<code>#pragma shader_feature</code>生成多个Shader变体，避免不必要的功能启用。</li>
<li>​<strong>剔除无用变体</strong>：在Shader中根据平台或功能需求，剔除无用的变体。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>#pragma multi_compile _ _USE_DETAIL
#ifdef _USE_DETAIL
    float4 detailColor = tex2D(_DetailTex, uv);
    color *= detailColor;
#endif</code></pre>
<h2>6. ​<strong>使用GPU Instancing</strong></h2>
<ul>
<li>​<strong>减少Draw Call</strong>：对于大量相同的物体，使用GPU Instancing可以减少Draw Call，提升性能。</li>
<li>​<strong>优化材质设置</strong>：启用<code>Enable GPU Instancing</code>选项，确保材质支持实例化。</li>
</ul>
<p>​<strong>示例：​</strong></p>
<pre><code>#pragma multi_compile_instancing
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_INSTANCING_BUFFER_END(Props)</code></pre>
<hr />
<h1>三、工具与调试</h1>
<h2>1. ​<strong>Frame Debugger</strong></h2>
<ul>
<li>使用Unity的Frame Debugger分析每一帧的渲染过程，找出性能瓶颈。</li>
</ul>
<h2>2. ​<strong>Shader性能分析</strong></h2>
<ul>
<li>使用工具（如RenderDoc、Xcode GPU Frame Capture）分析Shader的性能。</li>
</ul>
<h2>3. ​<strong>Profiler</strong></h2>
<ul>
<li>使用Unity Profiler监控GPU和CPU的负载，定位性能问题。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/unity-shader-optimized/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用 ETC2、ASTC、PVRTC三种纹理压缩技术的区别</title>
		<link>http://www.caiyanpei.com/%e4%bd%bf%e7%94%a8-etc2%e3%80%81astc%e3%80%81pvrtc%e4%b8%89%e7%a7%8d%e7%ba%b9%e7%90%86%e5%8e%8b%e7%bc%a9%e6%8a%80%e6%9c%af%e7%9a%84%e5%8c%ba%e5%88%ab/</link>
		<comments>http://www.caiyanpei.com/%e4%bd%bf%e7%94%a8-etc2%e3%80%81astc%e3%80%81pvrtc%e4%b8%89%e7%a7%8d%e7%ba%b9%e7%90%86%e5%8e%8b%e7%bc%a9%e6%8a%80%e6%9c%af%e7%9a%84%e5%8c%ba%e5%88%ab/#comments</comments>
		<pubDate>Sat, 16 May 2020 13:51:22 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[日志]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=592</guid>
		<description><![CDATA[ETC2、ASTC 和 PVRTC 三种不同的纹理压缩技术，主要用在移动设备和游 &#8230; <a href="http://www.caiyanpei.com/%e4%bd%bf%e7%94%a8-etc2%e3%80%81astc%e3%80%81pvrtc%e4%b8%89%e7%a7%8d%e7%ba%b9%e7%90%86%e5%8e%8b%e7%bc%a9%e6%8a%80%e6%9c%af%e7%9a%84%e5%8c%ba%e5%88%ab/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>ETC2、ASTC 和 PVRTC 三种不同的纹理压缩技术，主要用在移动设备和游戏平台上减少纹理的内存占用和提高性能。</p>
<p>1. ETC2（Ericsson Texture Compression 2）：<br />
ETC2 是一种由 Ericsson 开发的纹理压缩格式，适用于大多数 Android 设备。<br />
它支持不同的压缩质量，包括 ETC2_RGBA8、ETC2_RGB8、ETC2_RGBA1 以及 ETC2_RGB8A1 等。<br />
ETC2 压缩质量较高，可以提供相对较好的画质。</p>
<p>2. ASTC（Adaptive Scalable Texture Compression）：<br />
ASTC 是一种由 ARM 开发的高级纹理压缩格式，支持广泛的质量和压缩率。<br />
ASTC 适用于支持 OpenGL ES 3.0 及更高版本的设备，以及支持 Metal API 的 iOS 设备。<br />
ASTC 提供了更高的灵活性，可以在不同纹理上获得更好的压缩比例和画质。</p>
<p>3. PVRTC（PowerVR Texture Compression）：<br />
PVRTC 是由 Imagination Technologies 开发的纹理压缩格式，主要用于设备采用 PowerVR GPU 的 iOS 设备。<br />
PVRTC 分为 PVRTC1 和 PVRTC2，PVRTC2 在画质和压缩率上都有提升。<br />
PVRTC 对于图像的细节较少的情况下，可以实现较好的压缩效果。但在某些情况下可能会出现一些失真。</p>
<p>区别总结：<br />
ETC2 适用于大多数 Android 设备，提供较高的画质和压缩率。<br />
ASTC 支持广泛的质量和压缩率，适用于 OpenGL ES 3.0 及更高版本的设备，以及支持 Metal API 的 iOS 设备。<br />
PVRTC 主要用于 PowerVR GPU 的 iOS 设备，可以在细节较少的情况下获得较好的压缩效果。</p>
<p>在选择纹理压缩技术时，需要考虑目标平台的支持和性能要求，以及画质需求。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/%e4%bd%bf%e7%94%a8-etc2%e3%80%81astc%e3%80%81pvrtc%e4%b8%89%e7%a7%8d%e7%ba%b9%e7%90%86%e5%8e%8b%e7%bc%a9%e6%8a%80%e6%9c%af%e7%9a%84%e5%8c%ba%e5%88%ab/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unity中的C#委托与事件</title>
		<link>http://www.caiyanpei.com/unity_delegate_event/</link>
		<comments>http://www.caiyanpei.com/unity_delegate_event/#comments</comments>
		<pubDate>Tue, 21 Apr 2020 12:55:28 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[日志]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=633</guid>
		<description><![CDATA[在Unity开发中，C#的委托（Delegate）​和事件（Event）​就像一 &#8230; <a href="http://www.caiyanpei.com/unity_delegate_event/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity开发中，C#的<strong>委托（Delegate）​</strong>和<strong>事件（Event）​</strong>就像一对双胞胎兄弟，曾困惑于它们的本质区别。本文将通过实战案例揭开这对&#8221;孪生兄弟&#8221;的神秘面纱，了解它们的正确使用姿势。</p>
<h1>一、委托：灵活的函数指针</h1>
<h2>1.1 委托的本质</h2>
<p>委托本质上是一个类型安全的函数指针容器，可以存储多个方法引用。我们可以通过+=运算符实现多播委托：</p>
<pre class="brush: cpp; title: ; notranslate">
public delegate void HealthHandler(float health);

public class Player {
    public HealthHandler OnHealthChanged;

    public void TakeDamage(float damage) {
        currentHealth -= damage;
        OnHealthChanged?.Invoke(currentHealth);
    }
}
</pre>
<h2>1.2 委托的妙用场景</h2>
<ul>
<li>实现回调系统（如成就解锁）</li>
<li>跨脚本通信（非MonoBehaviour类间通信）</li>
<li>异步操作处理（如资源加载完成回调）</li>
</ul>
<h1>二、事件：安全的委托封装器</h1>
<h2>2.1 事件的核心特征</h2>
<p>事件在委托基础上添加了访问控制层，使用<code>event</code>关键字声明：</p>
<pre class="brush: cpp; title: ; notranslate">
public class Achievements {
    public event Action OnAchievementUnlocked;

    private void Unlock(string achievementName) {
        OnAchievementUnlocked?.Invoke(achievementName);
    }
}
</pre>
<h2>2.2 事件的安全机制</h2>
<ul>
<li>封装性：外部类只能订阅/取消订阅（+=/-=）</li>
<li>访问控制：仅声明类可触发事件</li>
<li>线程安全：编译器自动生成线程同步代码</li>
</ul>
<h1>三、关键差异对比表</h1>
<div>
<table>
<thead>
<tr>
<th>特性</th>
<th>委托</th>
<th>事件</th>
</tr>
</thead>
<tbody>
<tr>
<td>访问权限</td>
<td>公共可调用</td>
<td>仅声明类可触发</td>
</tr>
<tr>
<td>赋值操作</td>
<td>支持=赋值</td>
<td>仅支持+=/-=</td>
</tr>
<tr>
<td>多播能力</td>
<td>原生支持</td>
<td>通过委托机制支持</td>
</tr>
<tr>
<td>空引用检查</td>
<td>需手动检查</td>
<td>自动生成空检查代码</td>
</tr>
<tr>
<td>设计目的</td>
<td>通用回调机制</td>
<td>观察者模式实现</td>
</tr>
<tr>
<td>典型应用场景</td>
<td>函数参数、回调列表</td>
<td>UI交互、游戏事件通知</td>
</tr>
</tbody>
</table>
</div>
<h1>四、Unity实战案例解析</h1>
<h2>4.1 委托实现技能冷却系统</h2>
<pre class="brush: cpp; title: ; notranslate">
public class SkillSystem {
    public delegate void CooldownCallback(int skillID);
    public CooldownCallback OnCooldownStart;

    public void CastSkill(int skillID) {
        // 释放技能逻辑
        OnCooldownStart?.Invoke(skillID);
    }
}

// 使用端
skillSystem.OnCooldownStart += id =&gt; Debug.Log($&quot;技能{id}开始冷却&quot;);
</pre>
<h2>4.2 事件实现成就系统</h2>
<pre class="brush: cpp; title: ; notranslate">
public class AchievementSystem {
    public event Action&lt;string&gt; OnAchievementCompleted;

    public void CompleteAchievement(string name) {
        OnAchievementCompleted?.Invoke(name);
    }
}

// 订阅端
achievementSystem.OnAchievementCompleted += name =&gt; {
    PlayEffect(name);
    UpdateUI(name);
};
</pre>
<h1>五、设计选择指南</h1>
<p>✅ ​<strong>使用委托当：​</strong></p>
<ul>
<li>需要函数作为参数传递时</li>
<li>实现回调函数列表时</li>
<li>需要直接控制调用时</li>
</ul>
<p>✅ ​<strong>使用事件当：​</strong></p>
<ul>
<li>构建发布-订阅系统时</li>
<li>需要保护触发权限时</li>
<li>处理UI交互事件时</li>
<li>实现系统解耦时</li>
</ul>
<h1>六、性能优化贴士</h1>
<ol>
<li>避免每帧触发高频事件（如Update中的物理检测）</li>
<li>及时取消订阅防止内存泄漏</li>
<li>对高频事件使用EventManager集中管理</li>
<li>值类型参数优先使用ref传递</li>
<li>使用对象池重用事件参数</li>
</ol>
<h1>结语</h1>
<p>理解委托和事件的区别就像掌握魔法世界中的两种咒语：委托是灵活的基础咒语，而事件则是施加了保护咒的强化版本。在Unity开发中，建议80%的场景使用事件，仅在需要完全控制调用时使用原始委托。记住：​<strong>事件不是委托的替代品，而是其安全封装形态</strong>。合理运用这对黄金组合，可以让游戏代码既优雅又高效！</p>
<div data-conv-index="1" data-speech-index="0"></div>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/unity_delegate_event/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unity中的Shader魔法</title>
		<link>http://www.caiyanpei.com/unity_shader_magic/</link>
		<comments>http://www.caiyanpei.com/unity_shader_magic/#comments</comments>
		<pubDate>Thu, 21 Nov 2019 12:52:13 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[shader]]></category>
		<category><![CDATA[unity]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=644</guid>
		<description><![CDATA[在Unity的世界里，Shader就像是给游戏对象施法的魔杖，它能让平凡的3D模 &#8230; <a href="http://www.caiyanpei.com/unity_shader_magic/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity的世界里，Shader就像是给游戏对象施法的魔杖，它能让平凡的3D模型焕发出惊人的视觉效果。本文探讨Unity中Shader的奥秘，从基础概念到应用，了解下这门强大的图形编程艺术。</p>
<h1>一、揭开神秘面纱</h1>
<h2>1.1 什么是Shader？</h2>
<p>Shader是运行在GPU上的小程序，专门处理图形渲染的各个阶段。它决定了物体如何被绘制到屏幕上，控制着颜色、光照、纹理等视觉效果。</p>
<h2>1.2 Shader的类型</h2>
<ul>
<li>​<strong>表面着色器（Surface Shader）​</strong>：Unity的高层抽象，适合初学者</li>
<li>​<strong>顶点/片段着色器（Vertex/Fragment Shader）​</strong>：更底层的控制</li>
<li>​<strong>固定函数着色器（Fixed Function Shader）​</strong>：旧式硬件兼容</li>
<li>​<strong>计算着色器（Compute Shader）​</strong>：用于通用计算任务</li>
</ul>
<h1>二、创建第一个Shader</h1>
<h2>2.1 使用Shader Graph</h2>
<p>Unity的Shader Graph是可视化Shader编程工具，适合美术和程序员协作：</p>
<ol>
<li>创建Shader Graph资源</li>
<li>添加主纹理节点</li>
<li>连接颜色输出</li>
<li>调整光照模型</li>
<li>生成最终Shader</li>
</ol>
<h2>2.2 手撸Shader代码</h2>
<p>对于更高级的控制，可以直接编写Shader代码：</p>
<pre><code>Shader "Custom/SimpleDiffuse" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
        }
        ENDCG
    }
    FallBack "Diffuse"
}</code></pre>
<h1>三、Shader进一步</h1>
<h2>3.1 实现卡通渲染（Toon Shading）</h2>
<ul>
<li>使用法线贴图增强细节</li>
<li>实现边缘检测（Edge Detection）</li>
<li>创建颜色分级（Color Ramp）</li>
</ul>
<pre><code>Shader "Toon/Basic" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _Ramp ("Ramp Texture", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Toon

        // 实现Toon光照模型
        // 使用Ramp纹理进行颜色分级
        ENDCG
    }
    FallBack "Diffuse"
}</code></pre>
<h2>3.2 创建水效果Shader</h2>
<ul>
<li>使用法线贴图模拟水面波纹</li>
<li>实现折射和反射效果</li>
<li>添加深度效果（Depth Fade）</li>
</ul>
<pre><code>Shader "Water/Basic" {
    Properties {
        _MainTex ("Wave Texture", 2D) = "white" {}
        _BumpMap ("Normal Map", 2D) = "bump" {}
        _ReflectionTex ("Reflection", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Transparent" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Water

        // 实现水特效
        // 处理折射、反射
        // 添加动画效果
        ENDCG
    }
    FallBack "Transparent/Diffuse"
}</code></pre>
<h1>四、Shader优化策略</h1>
<ol>
<li>​<strong>减少纹理采样</strong>：合并纹理或使用纹理图集</li>
<li>​<strong>优化数学运算</strong>：使用低精度数据类型</li>
<li>​<strong>减少分支语句</strong>：尽量避免if-else语句</li>
<li>​<strong>利用GPU并行性</strong>：设计适合并行计算的结构</li>
<li>​<strong>使用Shader变体</strong>：针对不同情况生成优化版本</li>
</ol>
<h1>五、Shader调试</h1>
<ol>
<li>​<strong>使用Frame Debugger</strong>：逐步分析渲染过程</li>
<li>​<strong>添加调试输出</strong>：返回特定颜色值检查中间结果</li>
<li>​<strong>使用Profiler</strong>：分析Shader性能瓶颈</li>
<li>​<strong>Shader错误日志</strong>：检查编译错误和警告</li>
<li>​<strong>可视化工具</strong>：如AMD GPU PerfStudio</li>
</ol>
<h1>六、现代渲染管线</h1>
<h2>6.1 通用渲染管线（URP）</h2>
<ul>
<li>轻量级、高性能</li>
<li>适合移动平台和VR</li>
<li>支持Shader Graph</li>
</ul>
<h2>6.2 高清渲染管线（HDRP）</h2>
<ul>
<li>高质量、高保真</li>
<li>适合PC和主机平台</li>
<li>先进的物理效果</li>
</ul>
<h1>七、实现昼夜循环Shader</h1>
<ol>
<li>创建天空盒材质</li>
<li>编写Shader控制太阳位置</li>
<li>实现光照渐变</li>
<li>添加星星和月亮效果</li>
<li>控制云层运动</li>
</ol>
<pre><code>Shader "Skybox/Procedural" {
    Properties {
        _SunColor ("Sun Color", Color) = (1,1,1,1)
        _HorizonColor ("Horizon Color", Color) = (0.5,0.5,0.5,1)
        // 其他属性...
    }
    SubShader {
        Tags { "Queue"="Background" "RenderType"="Background" }
        LOD 100

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // 实现昼夜循环逻辑
            ENDCG
        }
    }
}</code></pre>
<h1>结语</h1>
<p>Shader编程是Unity开发中很有创造性和挑战性的领域之一。通过掌握Shader技术，以为游戏带来令人惊叹的视觉效果。优秀的Shader不仅需要技术功底，更需要艺术眼光和创造力。从简单的漫反射到复杂的水面效果，每一步都是对图形编程艺术的探索。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/unity_shader_magic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个根据胜率匹配玩家的算法</title>
		<link>http://www.caiyanpei.com/%e4%b8%80%e4%b8%aa%e6%a0%b9%e6%8d%ae%e8%83%9c%e7%8e%87%e5%8c%b9%e9%85%8d%e7%8e%a9%e5%ae%b6%e7%9a%84%e7%ae%97%e6%b3%95/</link>
		<comments>http://www.caiyanpei.com/%e4%b8%80%e4%b8%aa%e6%a0%b9%e6%8d%ae%e8%83%9c%e7%8e%87%e5%8c%b9%e9%85%8d%e7%8e%a9%e5%ae%b6%e7%9a%84%e7%ae%97%e6%b3%95/#comments</comments>
		<pubDate>Tue, 17 Sep 2019 12:49:15 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[日志]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=607</guid>
		<description><![CDATA[根据胜率积分来匹配双方玩家的算法可以使用 &#8220;Elo rating&# &#8230; <a href="http://www.caiyanpei.com/%e4%b8%80%e4%b8%aa%e6%a0%b9%e6%8d%ae%e8%83%9c%e7%8e%87%e5%8c%b9%e9%85%8d%e7%8e%a9%e5%ae%b6%e7%9a%84%e7%ae%97%e6%b3%95/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>根据胜率积分来匹配双方玩家的算法可以使用 &#8220;Elo rating&#8221;（也称为 Elo 算法）。Elo 算法最初是用于计算棋手之间的等级差异，但它同样适用于其他竞技类游戏，包括电子竞技和体育运动。</p>
<p>以下是基于 Elo 算法的胜率积分匹配算法的步骤：</p>
<p>1. 确定初始积分：为每个玩家设置一个初始积分。通常新玩家初始积分为一个固定值（例如 1000 分）。</p>
<p>2. 预测胜率：对于两个玩家 A 和 B，使用以下公式计算他们之间的预测胜率（通常用 S 表示）：</p>
<pre class="brush: cpp; title: ; notranslate">
S = 1 / (1 + 10^((Rb - Ra) / 400))
</pre>
<p>其中，Ra 是玩家 A 的当前积分，Rb 是玩家 B 的当前积分。</p>
<p>3. 计算积分变化：假设玩家 A 赢得比赛，则他的积分变化（通常用 K 表示）可以根据以下公式计算：</p>
<pre class="brush: cpp; title: ; notranslate">
K = K_factor * (1 - S)
</pre>
<p>其中，K_factor 是一个常数，用于控制积分的波动幅度。通常情况下，新玩家的 K_factor 较大，以使其积分更快地调整。</p>
<p>4. 更新积分：根据比赛结果，更新玩家 A 和 B 的积分。如果玩家 A 赢得比赛，则他的新积分为：</p>
<pre class="brush: cpp; title: ; notranslate">
Ra_new = Ra + K
Rb_new = Rb - K
</pre>
<p>如果玩家 B 赢得比赛，则互换 A 和 B 的公式。</p>
<p>5. 重复过程：根据新的积分，再次预测下一次比赛的胜率，并重复上述步骤。</p>
<p>需要注意的是，K_factor 的值和初始积分是需要根据具体的游戏或竞技体育的情况进行调整的。K_factor 值过大会导致积分波动过大，而过小则调整速度较慢。</p>
<p>使用 Elo 算法进行胜率积分匹配可以使玩家之间的积分更加公平地反映他们的真实水平，并且在比赛胜负时调整积分。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/%e4%b8%80%e4%b8%aa%e6%a0%b9%e6%8d%ae%e8%83%9c%e7%8e%87%e5%8c%b9%e9%85%8d%e7%8e%a9%e5%ae%b6%e7%9a%84%e7%ae%97%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>unity帧率优化</title>
		<link>http://www.caiyanpei.com/unity%e5%b8%a7%e7%8e%87%e4%bc%98%e5%8c%96/</link>
		<comments>http://www.caiyanpei.com/unity%e5%b8%a7%e7%8e%87%e4%bc%98%e5%8c%96/#comments</comments>
		<pubDate>Tue, 06 Jun 2017 12:41:13 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[日志]]></category>
		<category><![CDATA[unity]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://www.caiyanpei.com/?p=586</guid>
		<description><![CDATA[在Unity中，帧率（Frame Rate）是指每秒钟渲染的帧数，常用单位为FP &#8230; <a href="http://www.caiyanpei.com/unity%e5%b8%a7%e7%8e%87%e4%bc%98%e5%8c%96/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity中，帧率（Frame Rate）是指每秒钟渲染的帧数，常用单位为FPS（Frames Per Second）。游戏开发过程中，如果帧率低了，可能就是受到以下因素的影响：</p>
<p>1. 渲染时间：每帧的渲染时间取决于场景中的物体数量、复杂度以及使用的特效和着色器等。渲染时间过长会导致帧率下降。</p>
<p>2. CPU性能：CPU负责执行游戏逻辑、物理模拟、AI计算等任务。如果CPU性能不足，可能无法在每帧的时间限制内完成必要的计算，导致帧率下降。</p>
<p>3. GPU性能：GPU负责处理图形渲染任务。如果GPU性能不足，无法及时处理渲染指令，导致帧率下降。</p>
<p>4. 游戏逻辑复杂度：复杂的游戏逻辑、AI计算、碰撞检测等任务会消耗CPU的计算资源，影响帧率。</p>
<p>帧率对游戏的运行流畅度有重要影响。较高的帧率能够提供更流畅的动画和交互体验，而较低的帧率可能导致卡顿、延迟响应和不流畅的动画效果。</p>
<p>几个可考优化方案：</p>
<p>1. 减少渲染开销：通过减少复杂的特效、减少细节或使用合理的LOD系统来减少渲染负载，从而提高帧率。</p>
<p>2. 优化代码性能：通过优化游戏逻辑、减少资源加载和销毁、使用对象池等技术来减少CPU计算开销。</p>
<p>3. 使用批处理技术：通过合并渲染操作，减少Draw Call的数量，从而提高GPU性能。</p>
<p>4. 适当使用线程：将耗时的计算任务放在单独的线程中执行，避免阻塞主线程，提高CPU利用率。</p>
<p>5. 使用合理的资源管理：合理使用纹理压缩、资源压缩和内存优化技术，减少内存占用和加载时间。</p>
<p>6. 避免过度渲染：根据场景需要，避免无意义的渲染操作，如遮挡物体、避免渲染在屏幕外的物体等。</p>
<p>7. 使用性能分析工具：利用Unity提供的性能分析工具，如Profiler，可以定位性能瓶颈并进行针对性的优化。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/unity%e5%b8%a7%e7%8e%87%e4%bc%98%e5%8c%96/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>u3d的drawcall几个注意的地方</title>
		<link>http://www.caiyanpei.com/u3d%e7%9a%84drawcall%e5%87%a0%e4%b8%aa%e6%b3%a8%e6%84%8f%e7%9a%84%e5%9c%b0%e6%96%b9/</link>
		<comments>http://www.caiyanpei.com/u3d%e7%9a%84drawcall%e5%87%a0%e4%b8%aa%e6%b3%a8%e6%84%8f%e7%9a%84%e5%9c%b0%e6%96%b9/#comments</comments>
		<pubDate>Fri, 19 May 2017 12:33:50 +0000</pubDate>
		<dc:creator>tsai</dc:creator>
				<category><![CDATA[Unity]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[日志]]></category>
		<category><![CDATA[drawcall]]></category>
		<category><![CDATA[unity]]></category>

		<guid isPermaLink="false">http://www.xiuchezu.com/?p=570</guid>
		<description><![CDATA[在Unity中，Draw Call是指渲染器在绘制场景中的每个独立物体或图元时发 &#8230; <a href="http://www.caiyanpei.com/u3d%e7%9a%84drawcall%e5%87%a0%e4%b8%aa%e6%b3%a8%e6%84%8f%e7%9a%84%e5%9c%b0%e6%96%b9/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>在Unity中，Draw Call是指渲染器在绘制场景中的每个独立物体或图元时发出的绘制命令。Draw Call的生成大致由以下因素决定的：</p>
<p>1. 独立物体：每个独立的物体（GameObject）通常需要一个单独的Draw Call来进行渲染。例如，如果场景中有100个不同的物体，则会生成100个Draw Call。</p>
<p>2. 材质（Material）：每个材质都会产生一个Draw Call。如果多个物体使用相同的材质，则它们可以合并为一个Draw Call。</p>
<p>3. 纹理（Texture）：每个使用不同纹理的物体也会产生额外的Draw Call。如果多个物体使用相同纹理，则它们可以合并为一个Draw Call。</p>
<p>Draw Call数量的增加会对游戏的运行流畅度产生影响，因为每个Draw Call都需要CPU和GPU的处理，过多的Draw Call会增加渲染的开销。较高的Draw Call数量可能导致以下问题：</p>
<p>1. CPU开销：每个Draw Call都需要一定的CPU开销，包括物体和材质的设置、状态切换等。当Draw Call数量过多时，CPU将花费更多的时间来处理渲染命令，可能降低游戏的帧率。</p>
<p>2. GPU开销：在GPU端，每个Draw Call都需要进行渲染资源切换和状态设置。大量的Draw Call会增加GPU的负载，可能导致性能瓶颈，如卡顿和低帧率。</p>
<p>为了优化Draw Call，常见的有以下几个优化方案：</p>
<p>1. 合批（Batching）：尽量减少独立物体和材质的数量，以减少Draw Call的生成。使用相同材质的物体可以合并为一个Draw Call，可以使用静态批处理（Static Batching）或动态批处理（Dynamic Batching）来实现。</p>
<p>2. 材质合并（Material Merging）：如果多个物体使用相似的材质，可以将它们合并为一个材质，以减少Draw Call的数量。</p>
<p>3. 纹理图集（Texture Atlas）：将多个小纹理合并为一个大纹理图集，可以减少纹理切换和Draw Call的数量。</p>
<p>4. GPU Instancing：对于使用相同网格和材质的大量物体，可以使用GPU Instancing来减少Draw Call的数量。GPU Instancing允许多个物体同时渲染，只产生一个Draw Call。</p>
<p>5. 动态LOD（Level of Detail）：根据物体的距离和屏幕尺寸，使用不同级别的细节模型（LOD）来减少多余的绘制。通过动态LOD，可以减少不必要的Draw Call。</p>
<p>6. 静态合并（Static Mesh Combining）：将多个静态网格合并为一个网格，以减少Draw Call的数量。适用于静态不可变的场景元素。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiyanpei.com/u3d%e7%9a%84drawcall%e5%87%a0%e4%b8%aa%e6%b3%a8%e6%84%8f%e7%9a%84%e5%9c%b0%e6%96%b9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
