Unity体积云开源项目实战:从导入到优化的全流程问题解决指南

发布时间:2026/7/19 5:14:10

Unity体积云开源项目实战:从导入到优化的全流程问题解决指南
1. 项目概述当Unity体积云遇上“拦路虎”在Unity里实现一套真实、动态的体积云效果是很多技术美术和图形程序员的“心头好”。开源项目“Volumetric Clouds in Unity”提供了一个绝佳的起点它基于Ray Marching光线步进和噪声纹理构建了一个从天空到地面的完整云层渲染方案。然而和所有优秀的开源项目一样当你兴冲冲地把它导入自己的项目准备大展拳脚时往往会发现理想很丰满现实却很骨感。编译错误、材质丢失、性能卡顿、效果失真……这些问题就像游戏里的“精英怪”不解决它们你的体积云就永远只能停留在Demo阶段。我自己在多个项目中复用和改造这个开源方案时几乎把能踩的坑都踩了一遍。从Shader编译报错到移动端适配从性能优化到美术效果调参每一个环节都可能让你卡上半天。这篇文章我就把这些年积累下来的、针对这个特定开源项目的常见问题及其解决方案系统地梳理一遍。无论你是刚接触图形学的新手还是正在为项目寻找云方案的老手希望这些“血泪经验”能帮你绕过弯路更快地让那片美丽的云海在你的项目中飘起来。2. 核心问题拆解与通用解决思路在深入具体问题之前我们需要建立一个宏观的认知这个开源项目本质上是一个复杂的、由多个部分耦合而成的渲染系统。它通常包含以下几个核心模块用于生成云体形状的3D噪声纹理如Worley, Perlin噪声、基于物理的大气散射模型、负责光线步进计算的Shader、以及一套控制云层分布、密度、光照的脚本和材质参数面板。问题往往就出现在这些模块的衔接处或者是对运行环境的假设上。2.1 问题根源分类根据我的经验所有问题可以归结为四大类环境与依赖问题项目对Unity版本、渲染管线、第三方插件版本有特定要求不匹配就会导致编译错误或功能缺失。资源与配置问题Shader中用到的纹理、Compute Shader、或自定义HLSL文件丢失或路径错误导致材质显示为洋红色Missing。性能与兼容性问题在目标平台尤其是移动端或WebGL上Shader特性不支持、计算量过大导致帧率暴跌。效果与逻辑问题云看起来不对太假、太糊、闪烁或者交互逻辑如云层移动、密度变化不按预期工作。一个高效的排查流程应该是先确认环境和资源解决“能不能跑”再优化性能和兼容性解决“跑得顺不顺”最后精细调整效果解决“跑得好不好看”。2.2 通用排查工具箱在开始之前请确保你熟练使用以下Unity内置工具它们是你解决问题的“瑞士军刀”Console窗口不要只看错误Error更要关注警告Warning。很多诡异的渲染问题根源可能是一个不起眼的Shader警告。Frame Debugger逐帧分解渲染过程查看Draw Call、渲染状态和Shader属性传递是诊断渲染问题的终极利器。Profiler特别是GPU Profiler和Rendering Profiler用于定位性能瓶颈看是CPU端脚本耗时还是GPU端Shader计算超支。Shader编译日志在Console中双击Shader编译错误或警告可以打开详细的编译日志里面会指出具体哪一行HLSL代码出了问题。3. 环境与依赖类问题解决方案这是新手遇到的第一道坎也是最容易解决的问题。3.1 Unity版本与渲染管线适配注意许多开源体积云项目最初是为Built-in Render Pipeline内置渲染管线或较旧的Universal Render PipelineURP版本开发的。问题现象导入项目后大量Shader报错错误信息中包含UNITY_MATRIX_MVP、UnityObjectToClipPos等Built-in管线特有函数或者提示ShaderGraph节点不兼容。解决方案确认项目管线首先在Project Settings - Graphics中确认你正在使用的渲染管线。如果原项目是Built-in而你的项目是URP或HDRP直接使用几乎必然失败。管线转换如果源为Built-inURP项目可以尝试使用Unity官方的Render Pipeline Converter工具Window - Rendering - Render Pipeline Converter。选择转换“材质球”和“Shader”。但请注意这个工具并非万能对于高度定制、包含复杂Custom Function节点的Shader转换后可能需要大量手动修复。手动迁移更可靠的方式是寻找专门为URP或HDRP编写的体积云开源项目。如果非要迁移你需要将Shader中#include “UnityCG.cginc”替换为 URP 的#include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”。替换所有Built-in的变换矩阵和工具函数为URP对应的版本。重写光照部分因为URP的光照架构完全不同。我的建议除非你有深厚的Shader功底否则不要轻易尝试将复杂的Built-in体积云Shader手动迁移到SRP。直接寻找基于URP/HDRP的同类开源项目是更高效的选择。检查Package Manager确保项目中安装了必要的渲染管线Package如Universal RP、High Definition RP并且版本没有过新或过旧。有时需要根据开源项目README的说明回退到某个特定版本。3.2 第三方插件冲突问题现象项目运行后云效果不显示或者与其他后期处理效果如Color Grading, Bloom叠加时出现异常画面撕裂、闪烁。解决方案隔离测试新建一个空白场景只放入体积云所需的核心组件摄像机、云渲染脚本/体积和最基本的地形/天空盒。观察效果是否正常。如果正常说明问题出在与其他系统如其他后处理栈、自定义渲染特性、地形系统的交互上。渲染顺序Queue与Layer体积云Shader的渲染队列Render Queue设置非常关键。它通常需要在天空盒之后、在不透明物体之前渲染即Queue为Transparent或AlphaTest之后的某个值。检查Shader的Tags { “Queue” “Transparent100” }这类设置确保它不会被其他物体错误遮挡。后处理冲突如果使用了URP的Volume后处理体积云渲染可能会与某些后处理效果特别是那些涉及深度纹理或屏幕空间操作的效果冲突。尝试暂时禁用所有Volume看云是否出现。然后逐个启用定位冲突源。有时需要调整体积云渲染的执行时机通过ScriptableRenderPass的RenderPassEvent。4. 资源与配置类问题解决方案这类问题通常表现为材质球变成洋红色或者运行时日志报错“Texture/ComputeShader not found”。4.1 噪声纹理丢失或导入设置错误问题现象云体形状怪异呈规则条纹或方块状或者材质直接显示为粉色。解决方案定位纹理打开出问题的材质球查看其Shader属性。找到那些标为“None (Texture)”的贴图槽位通常命名为“NoiseTex”、“WorleyNoise”、“WeatherMap”等。根据原项目文档或文件结构在Project窗口中找到这些纹理文件通常是.asset格式的3D Texture或普通的2D Texture。重新指定将找到的纹理拖拽到材质球的对应槽位中。检查导入设置关键选中这些噪声纹理在Inspector面板中检查其导入设置。Texture Type3D噪声必须设置为Texture 3D2D噪声通常为Default。如果是用于采样的Look-up表LUT可能需要设置为Normal map或关闭sRGB。sRGB (Color Texture)对于存储密度、梯度等非颜色数据的纹理必须取消勾选sRGB否则采样值会经过伽马校正导致计算错误。Wrap Mode通常设置为Repeat以确保云层可以无缝平铺。Filter Mode根据质量需求选择Trilinear或Bilinear。Point模式可能会导致采样锯齿。4.2 Compute Shader或HLSL文件问题问题现象编辑器或运行时报错提示“ComputeShader ‘XXX’ not found” 或 “HLSL file include error”。解决方案文件完整性确保项目Assets目录下包含了所有.compute和.hlsl文件。有时Git克隆会忽略这些文件需要检查.gitignore设置。引用路径在Shader代码中检查#include语句的路径。Unity的路径有时会因为项目结构不同而失效。使用相对路径如#include “../Noise/ClassicNoise3D.hlsl”比绝对路径更可靠。如果文件移动了位置必须同步更新所有引用它的Shader文件。Compute Shader平台兼容性在Compute Shader文件的Inspector面板中确保勾选了你的目标平台如Windows, Android, iOS。如果没有勾选在对应平台上该Compute Shader将无法加载。4.3 材质参数未正确初始化问题现象云层密度、厚度、光照颜色等效果与Demo相去甚远但材质并未报错。解决方案脚本绑定检查体积云的效果通常由一个C#脚本如VolumetricCloudController驱动该脚本会在运行时或Awake/Start时将风速、密度阈值、光照系数等参数通过Material.SetFloat或Material.SetVector传递给Shader。检查这个脚本是否被正确挂载到场景中的管理器物体如摄像机或空物体上并且是否成功获取到了对应的材质引用。默认值重置在材质球上右键选择“Revert Selected Properties”或“Copy Material Properties”然后粘贴到一个新的材质球上有时可以恢复丢失的默认参数。更好的做法是保留一份原项目中的“标准参数”材质球作为参考模板。序列化丢失如果材质球是预制体Prefab的一部分而预制体被频繁修改和覆盖有时会导致材质球上的自定义参数丢失。确保对材质球的修改在预制体模式下进行并应用。5. 性能与兼容性问题解决方案体积云渲染是性能消耗大户Ray Marching步进次数、噪声采样频率、分辨率缩放等因素都直接影响帧率。5.1 移动端/WebGL适配与性能优化问题现象在PC上运行流畅打包到Android/iOS或WebGL后帧率极低甚至崩溃。解决方案降低Ray Marching步进数这是最有效的优化手段。在Shader或控制脚本中找到控制步进次数的参数如_Steps、_MaxIterations。在移动端尝试从64或128步大幅降低到16-32步。虽然这会损失一些细节尤其是云层边缘但能换来可玩的帧率。可以尝试根据设备性能进行动态调整。启用降分辨率渲染不要在全分辨率下进行体积云渲染。使用一个降低分辨率的Render Texture如原分辨率的1/2或1/4来渲染云然后再上采样到屏幕。这能极大减少像素着色器的调用次数。在Shader中这通常通过_CloudRT纹理和相关的屏幕UV缩放计算来实现。简化光照模型基于物理的大气散射和多重散射计算非常昂贵。在移动端可以简化甚至替换为一个经验性的、基于视角和光方向的简单颜色混合模型。查找Shader中的光照计算函数通常包含HenveyGreenstein相位函数、Beer-Lambert定律等尝试用lerp或简单的幂运算来近似效果。检查Shader Target Level在Shader文件的#pragma target行检查其目标级别。对于需要大量计算和纹理采样的复杂Shader3.5或4.5可能在部分移动设备上不支持。可以尝试降级到3.0但这可能会禁用某些必要的指令或纹理采样次数需要测试兼容性。慎用discard操作在片段着色器中使用discard来跳过透明像素在移动端的某些GPU架构上性能开销很大。确保你的Shader只在必要时如密度低于某个阈值才使用discard。5.2 编辑器内卡顿与实时预览优化问题现象在Scene视图或Game视图拖动摄像机、调整参数时编辑器变得异常卡顿。解决方案动态降低编辑器质量编写一个编辑器专用的脚本在OnSceneGUI或EditorApplication.update中检测鼠标拖动或参数变化事件。当检测到这些交互操作时自动将体积云的质量参数步进数、降分辨率比例调至最低当交互停止一段时间后再恢复为设定质量。这能极大提升编辑体验。分离预览摄像机为体积云效果单独创建一个低精度的预览摄像机只在需要查看最终效果时才切换到主摄像机渲染。避免在编辑场景中所有物体时都进行全质量体积云计算。缓存噪声采样如果云形态是静态的或变化很慢可以考虑将一帧的噪声采样结果渲染到一张Render Texture中缓存起来后续几帧复用直到摄像机位置或时间参数发生显著变化后再重新计算。6. 渲染效果与逻辑问题解决方案解决了“能跑”和“跑得动”之后我们终于可以关心“跑得好不好看”了。6.1 云层边缘闪烁Flickering与噪声抖动问题现象云层的边缘或内部细节在摄像机移动或云层飘动时出现明显的闪烁或“沸腾”状抖动。问题根源这是Ray Marching 噪声采样的经典问题。当摄像机移动时采样射线与世界空间噪声场的交点发生变化由于步进是离散的每一步采样到的噪声值会发生跳变在视觉上就形成了闪烁。解决方案启用蓝噪声Blue Noise抖动这是解决此问题最有效的方法之一。不要在每一步使用固定的步进步长而是在每一步的采样位置引入一个基于屏幕像素坐标和帧数变化的、高频的蓝噪声纹理进行微小的随机偏移。这能将规则的条带状闪烁Banding和跳变转化为更不易察觉的、均匀的高频噪声。你需要在Shader中采样一张蓝噪声纹理并将其值映射到一个很小的偏移向量上加到Ray Marching的当前步进位置中。增加 Temporal Anti-Aliasing (TAA)如果项目启用了TAA它可以很好地平滑帧与帧之间的噪声变化。确保体积云的渲染输出被包含在TAA的历史缓冲混合过程中。优化噪声频率与步长比例闪烁的明显程度与噪声的频率和步进步长有关。尝试降低用于形状的噪声频率或者增加步进步长同时可能需要增加总步数以保持穿透深度。找到一个闪烁与性能/细节的平衡点。6.2 云层与场景融合不佳问题现象云层看起来像是漂浮在场景之上的“贴片”与远山、天空盒的过渡生硬或者无法正确地遮挡场景中的物体。解决方案深度融合Depth-Aware Compositing这是实现云与场景正确遮挡关系的关键。在Ray Marching的最后你需要知道当前像素的云渲染深度与场景中实际物体的深度。步骤通常如下在渲染云之前将场景的深度纹理_CameraDepthTexture准备好。在云渲染Shader中将Ray Marching的终止深度即射线首次达到足够密度的点的深度与从深度纹理中采样到的场景深度进行比较。如果场景深度更近即场景物体在云前面则丢弃或淡化该像素点的云颜色。同时在场景物体的着色器中特别是远处如山脉可以采样体积云的阴影信息让物体表面也受到云层阴影的影响增强融合感。天空盒渐变不要让云的底部突然截断。在Shader中根据世界空间高度或视线仰角计算一个从云密度到零的渐变因子。通常使用smoothstep函数在云底高度附近创建一个平滑的过渡区域。环境光遮蔽AO与多重散射真实的云层内部阴影丰富光线在云体内多次散射。开源项目可能实现了简化的多重散射模型。确保相关参数如散射系数、各向异性参数被正确设置。可以尝试增加散射次数即使只是近似这能让云体看起来更厚重、更有体积感而不是单薄的“棉花糖”。6.3 光照颜色与时间变化不自然问题现象日出日落时云的颜色过渡生硬或者云层的高光区域银边太强或太弱。解决方案基于物理的日光颜色不要直接用_LightColor0方向光颜色。在日出日落时日光颜色变化剧烈。更好的方法是使用一个基于太阳高度角可通过光源方向计算的渐变颜色曲线Gradient来动态决定照射到云上的光颜色。这能模拟出晨曦的暖黄和傍晚的橙红。相位函数Phase Function调参云的高光银边效果主要由相位函数控制它描述了光线在粒子云滴中散射的方向性。常用的Henvey-Greenstein相位函数有一个g参数各向异性参数。g接近0各向同性散射云看起来更柔和、弥散。g为正如0.7到0.9强烈的前向散射会产生非常明显、锐利的“银边”效果。实操心得对于蓬松的积云使用一个较小的正g值如0.3-0.5搭配一个较大的散射强度可以产生柔和而宽泛的高光。对于高层薄卷云可以使用更大的g值来模拟更锐利的光晕。不要只用一个相位函数可以尝试将两个不同g值的相位函数结果混合以获得更丰富的光照变化。环境光贡献云层背光面不应该完全是黑的。它应该受到天空盒环境光天空颜色的影响。在Shader中除了计算直射日光还要加上一个基于法线或简单使用顶面的环境光项其颜色可以取自天空盒的顶部分颜色。7. 进阶调试与自定义扩展思路当你解决了所有基础问题效果也基本满意后可能会想更进一步定制属于自己的云海。7.1 使用自定义噪声纹理原项目提供的Worley或Perlin噪声可能无法满足你对特定云形如层云、堡状云的需求。操作步骤生成噪声使用专业工具如Houdini、Substance Designer或开源库如libnoise生成自定义的3D噪声纹理.asset格式。关键是要生成一个3D的、可平铺的tilable噪声场。导入Unity将生成的纹理导入Unity确保Texture Type设置为Texture 3D并根据需要关闭sRGB。修改Shader在Shader中找到采样噪声的函数如SampleNoise(float3 pos)将其中的采样指令从原有的噪声纹理切换到你的新纹理。你可能需要调整采样时的缩放tiling和偏移offset因为不同噪声的数值范围可能不同。调整密度重映射新的噪声纹理值分布可能不同你需要调整后续的remap、smoothstep或指数函数将噪声值映射到合适的云密度范围0到1。这需要反复在场景中观察调整。7.2 实现动态天气系统让云层根据天气如湿度、气压动态变化密度、厚度和覆盖范围。实现思路创建天气图Weather Map这是一张覆盖游戏世界范围的2D纹理Render Texture它的R、G、B通道可以分别存储湿度、云层高度、风速等信息。这张图可以由程序化生成也可以由美术绘制。在Shader中采样天气图在Ray Marching的每一步根据世界XZ坐标采样这张天气图。用湿度通道影响基础密度用高度通道影响云层出现的垂直范围用风速通道影响噪声的动画速度。动态更新天气图通过一个单独的C#脚本或Compute Shader每帧或每隔几帧更新这张天气图。例如模拟风将湿度从一片区域吹到另一片区域或者根据时间在特定区域“生成”新的云增加湿度值。与游戏逻辑交互将天气系统与游戏的其他模块如任务系统、环境音效、植被着色连接起来。例如当云层密度超过某个阈值时触发下雨粒子效果并让场景中的水面材质切换为雨天状态。解决“Volumetric Clouds in Unity”这类开源项目的问题是一个典型的“从理解到掌控”的过程。最初你只是导入运行然后开始解决一个个报错接着优化性能最后才能游刃有余地调整效果甚至进行二次开发。这个过程里最重要的不是记住某个具体的参数值而是建立起一套图形学调试的思维方法遇到问题先看Console再用Frame Debugger和Profiler定位从管线、资源、Shader代码、性能预算等多个维度去分析可能性。希望这份汇集了常见“坑点”和解决方案的指南能成为你探索体积云乃至更广阔实时图形世界的一块有用的垫脚石。当那片完全由你掌控的云海终于在屏幕上舒卷开来时所有的调试和折腾都是值得的。

相关新闻

UE5像素流送Windows服务器部署全攻略:从打包到生产环境优化

UE5像素流送Windows服务器部署全攻略:从打包到生产环境优化

2026/7/19 5:14:10

1. 项目概述:从单机到云端的游戏体验革命如果你是一名UE5开发者,或者正在探索如何将高质量的虚幻引擎应用交付给更多用户,那么“像素流送”这个词你一定不陌生。它不再是实验室里的概念,而是实实在在能改变你产品分发方式的技术。…

Android线程安全与UI更新机制详解

Android线程安全与UI更新机制详解

2026/7/19 5:14:10

1. 为什么子线程不能直接更新UI?在Android开发中,UI线程(主线程)负责处理所有用户界面相关的操作。这个设计源于UI工具包的非线程安全特性。想象一下,如果多个线程同时修改同一个TextView的文本内容,就像几…

ROS 2的核心概念-服务

ROS 2的核心概念-服务

2026/7/19 5:14:10

一、概念服务(Service)是两个节点间的一种可靠通信方式。在服务中存在两个参与方:服务器(Server)和客户端(Client)。服务器负责提供服务,响应客户的请求(Request&#xf…

通用大模型、RAG与Agent在售前场景中怎么分工?别再把三者混成一个聊天机器人

通用大模型、RAG与Agent在售前场景中怎么分工?别再把三者混成一个聊天机器人

2026/7/19 9:54:25

文章摘要 企业建设AI售前助手时,常见误区是把通用大模型、RAG和Agent当成三个可以互相替代的方案。实际上,通用大模型负责语言理解与生成,RAG负责把内部知识送入上下文,Agent负责规划任务、调用工具和推动流程。本文围绕需求分析、产品匹配、方案生成、报价、投标和审批等…

历年CSP-J初赛真题解析 | 2017年CSP-J初赛

历年CSP-J初赛真题解析 | 2017年CSP-J初赛

2026/7/19 9:54:25

附上汇总帖:历年CSP-J初赛真题解析 | 汇总 单项选择 第1题 在8位二进制补码中,10101011表示的数是十进制下的( )。 A.43 B.-85 C.-43 D.-84 【答案】:B 【解析】 正数的原码、反码和补码均相同 最高位为符号…

MCP 接入验收:不要把 server 启动当成安全证明

MCP 接入验收:不要把 server 启动当成安全证明

2026/7/19 9:54:25

很多 MCP 教程从“把 server 加进配置文件”开始,但真正容易出事故的是接入之后:宿主到底暴露了哪些工具、资源和提示?文件系统边界有没有收窄?失败时能不能退回旧配置? modelcontextprotocol/servers 更适合作为参考服…

深度解析:AI驱动下的健康管理革命——【盗铃医生】引领绿色体检新趋势

深度解析:AI驱动下的健康管理革命——【盗铃医生】引领绿色体检新趋势

2026/7/19 9:54:25

深度解析:AI驱动下的健康管理革命——【盗铃医生】引领绿色体检新趋势在2026年的数字化医疗时代,健康管理已从“事后治疗”全面转向“预防先行”。随着人工智能与生物传感技术的深度融合,以盗铃医生为代表的创新性亚健康检测设备,…

基于大模型的Web自动化智能测试平台

基于大模型的Web自动化智能测试平台

2026/7/19 9:54:25

Web自动化智能测试平台一、项目背景二、项目简述三、项目亮点1. Web 测试全流程智能化2. 测试脚本自动修复闭环3. Playwright MCP 集成4. 报告和截图完整沉淀5. 定位器策略前置6. 测试资产统一管理四、项目功能展示一、项目背景 传统 Web 自动化测试通常会有以下几个问题&…

解锁科学健康管理,守护你的身心状态

解锁科学健康管理,守护你的身心状态

2026/7/19 9:44:24

什么是真正的健康管理?不少人对健康管理的认知还停留在「生病后再调理」,但实际上,健康管理是一套覆盖全周期的健康维护方案,贯穿预防、监测、干预全流程,核心是通过科学手段将我们的健康状态维持在稳定的良性区间。健…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/19 0:03:49

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/19 0:03:49

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/19 0:03:49

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/19 0:03:49

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/19 0:03:49

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/19 0:03:49

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…