未用平滑的发光环 shader

本文提供了一个使用 GLSL (OpenGL Shading Language) 编写的着色器示例代码。该示例展示了如何设置精度、使用扩展特性、定义统一变量以及在片段着色器中进行基本的图形操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: http://glslsandbox.com/e#44852.0




#ifdef GL_ES
precision mediump float;
#endif


#extension GL_OES_standard_derivatives : enable


uniform float time;
uniform vec2 resolution;


void main( void ) {
vec2 position = ((gl_FragCoord.xy / resolution.xy) * 2. - 1.) * vec2(resolution.x / resolution.y, 1.0);
vec2 pos = gl_FragCoord.xy / resolution.xy * vec2(resolution.x / resolution.y, 1.);

float d = abs( length(pos* abs(1.2)) - 0.50 * abs(1.2)) * 6.0;



gl_FragColor += vec4(0.08/d, 0.04 / d, 0.02 / d, 1.0
                                   );
}



<think>我们之前讨论了URP2D菲涅尔效果(边缘光),现在用户询问的是URP2D内光效果。内光与菲涅尔效果不同,内光通常是在物体内部边缘产生光效果,类似于从边界向内扩散的光晕。实现内光的常见方法:1.基于距离场(SDF)的方法:使用一张存储了每个像素到边界的距离的纹理,然后根据距离控制光强度。2.基于边缘检测的方法:通过检测纹理的透明度边缘,然后向内模糊。然而,在2D中,我们通常使用精灵纹理,没有3D模型的法线信息。因此,内光效果可以通过以下步骤实现:方法一:使用ShaderGraph(推荐)步骤:1.创建ShaderGraph(URPUnlitGraph)。2.采样主纹理,并获取其透明度通道(Alpha)。3.计算内光的遮罩:通常是通过对透明度通道进行边缘检测(例如使用Sobel算子)或者使用膨胀(扩张)操作来生成内部边缘。4.对生成的边缘遮罩进行模糊(例如高斯模糊)以创建光晕效果。5.使用颜色和强度参数调整光晕,并与原纹理混合。但是,ShaderGraph中实现边缘检测和模糊可能比较复杂,因为需要多次采样。另一种更简单的方法是使用距离场(SDF)纹理,但需要预生成。方法二:编写HLSL代码(更高效,更灵活)我们采用一种简单的方法:通过多次采样纹理并取最大值(膨胀)来模拟内部边缘,然后进行模糊处理。但考虑到性能,我们可以简化:步骤:1.在片段着色器中,采样当前像素和周围8个方向的像素。2.计算这些采样中透明度的最大值(膨胀操作),这样可以得到比原区域稍大的区域。3.原纹理与膨胀后的区域相减,得到内部边缘(因为内部边缘就是原纹理内部与膨胀区域重叠的部分,但实际是取膨胀区域中不透明部分向内扩散的部分)。4.对内部边缘进行模糊(例如取周围像素的平均值)以产生光晕。5.将内光颜色与模糊后的边缘遮罩相乘,然后叠到原纹理上。但是,这种方法在片段着色器中多次采样可能会影响性能。另一种更高效的方法是使用两次Pass:-第一个Pass生成内光的遮罩(通过膨胀操作)-第二个Pass对遮罩进行模糊-第三个Pass将模糊后的遮罩叠到原纹理上然而,对于2D游戏,我们通常希望在一个Pass中完成。因此,这里提供一个简化的单Pass内Shader,它通过采样周围4个像素(上下左右)来模拟内光:具体思路:1.采样当前像素和上下左右四个方向的像素(偏移量可控制)。2.计算周围四个像素透明度的最大值(膨胀)。3.用这个最大值减去当前像素的透明度,得到边缘强度(这样只有在当前像素透明而周围有不透明像素时才会光,即内边缘)。4.对边缘强度进行平滑处理(例如乘以一个系数)并乘以光颜色。5.将光效果叠到当前像素上。注意:这种方法只能得到简单的内光,模糊效果不够柔和。但优点是简单快速。下面提供一个HLSL实现的URP2D内Shader:```hlslShader"URP/2D/InnerGlow"{Properties{_MainTex("MainTexture",2D)="white"{}_GlowColor("GlowColor",Color)=(1,1,1,1)_GlowIntensity("GlowIntensity",Range(0,10))=1_GlowSize("GlowSize",Range(0,0.1))=0.01}SubShader{Tags{"RenderType"="Transparent""Queue"="Transparent""RenderPipeline"="UniversalPipeline"}BlendSrcAlphaOneMinusSrcAlphaPass{HLSLPROGRAM#pragmavertexvert#pragmafragmentfrag#include"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"structAttributes{float4positionOS:POSITION;float2uv:TEXCOORD0;};structVaryings{float4positionHCS:SV_POSITION;float2uv:TEXCOORD0;};TEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);float4_GlowColor;float_GlowIntensity;float_GlowSize;Varyingsvert(Attributesinput){Varyingsoutput;output.positionHCS=TransformObjectToHClip(input.positionOS.xyz);output.uv=input.uv;returnoutput;}half4frag(Varyingsinput):SV_Target{//采样主纹理half4tex=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv);//采样周围四个方向(上下左右)half4up=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv+float2(0,_GlowSize));half4down=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv+float2(0,-_GlowSize));half4left=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv+float2(-_GlowSize,0));half4right=SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,input.uv+float2(_GlowSize,0));//计算周围像素的最大透明度(膨胀)halfmaxAlpha=max(max(up.a,down.a),max(left.a,right.a));//计算内光遮罩:当当前像素透明度小于周围最大透明度时,说明在内部边缘//注意:我们想要的是当前像素透明(或半透明)而周围不透明的地方光//因此,遮罩=(maxAlpha-tex.a)*周围不透明而当前透明的部分halfglowMask=maxAlpha*(1-tex.a);//计算光颜色half3glow=_GlowColor.rgb*_GlowIntensity*glowMask;//将光效果叠到纹理上(注意:光部分不改变原纹理的透明度,但光本身是半透明的)half3finalColor=tex.rgb+glow;//最终透明度:保持原纹理的透明度,但也可以根据需求调整returnhalf4(finalColor,tex.a);}ENDHLSL}}}```这个Shader的说明:1.通过_GlowSize控制采样偏移,即内光的宽度。2.通过_GlowIntensity控制光强度。3.内光颜色由_GlowColor指定。注意:这个简单的Shader只能产生基本的内光效果,且边缘是硬边。如果要更柔和的效果,可以采样更多方向(例如8个方向)或者进行多次模糊处理,但这样会增采样次数。优化建议:如果对效果要求较高,建议使用两个Pass:-第一个Pass生成内光的遮罩(通过膨胀操作得到内部边缘)-第二个Pass对遮罩进行模糊(可以使用高斯模糊)-第三个Pass将模糊后的遮罩叠到原纹理上但在移动设备上,多次Pass或多次采样可能会影响性能,因此需要权衡。另外,还可以考虑使用预生成的距离场纹理(SDF)来实现更高效和更高质量的内光,但这需要额外的纹理生成步骤。应用场景:-2D精灵的选中状态-魔法效果-UI元素的高亮相关问题:1.如何在URP2D中实现外光效果?2.如何优化2D内Shader的性能?3.如何使用ShaderGraph实现2D内光效果?4.内光效果在移动设备上性能消耗大吗?如何优化?引用:[^1]:Unity官方关于2D技术的介绍,包括2D光照和效果。[^2]:URPShader模板。</think>### Unity URP 2D内Shader实现方案 在Unity URP中实现2D内光效果的核心原理是通过纹理采样和边缘检测算法创建内部光晕。以下是两种高效实现方法: #### 方法1:基于Alpha通道的内Shader(HLSL代码) ```hlsl Shader "URP/2D/InnerGlow" { Properties { _MainTex ("Main Texture", 2D) = "white" {} _GlowColor ("Glow Color", Color) = (1,0.5,0,1) _GlowIntensity ("Intensity", Range(0,10)) = 2 _GlowSize ("Size", Range(0,0.2)) = 0.05 } SubShader { Tags { "RenderType"="Transparent" "Queue"="Transparent" "RenderPipeline"="UniversalPipeline" } Blend SrcAlpha OneMinusSrcAlpha Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; }; struct Varyings { float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; }; TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); float4 _GlowColor; float _GlowIntensity; float _GlowSize; Varyings vert(Attributes input) { Varyings output; output.positionHCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = input.uv; return output; } half4 frag(Varyings input) : SV_Target { // 主纹理采样 half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); // 边缘检测采样 float2 offsets[4] = { float2(0, _GlowSize), float2(0, -_GlowSize), float2(_GlowSize, 0), float2(-_GlowSize, 0) }; // 计算内部边缘 half glow = 0; for(int i = 0; i < 4; i++) { half neighbor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv + offsets[i]).a; glow += saturate(tex.a - neighbor); // 当前像素alpha高于邻居时光 } glow = saturate(glow * _GlowIntensity); // 混合效果 half3 glowColor = _GlowColor.rgb * glow; half3 finalColor = tex.rgb + glowColor; return half4(finalColor, tex.a); } ENDHLSL } } } ``` #### 方法2:使用Shader Graph可视化实现 1. **创建Shader Graph**: - 新建URP Unlit Graph - 添以下节点结构: ``` [Texture2D] → [Sample Texture 2D] (主纹理) [UV] → [Branching] → [4x Offset] (创建采样点) [Sample Texture 2D]×4 → [Subtract] → [Saturate] → [Add] (边缘检测) [Multiply] (强度控制) → [Color] → [Add] (混合颜色) ``` 2. **关键节点设置**: ```glsl // 内光核心计算 float glow = 0; for each offset: glow += saturate(centerAlpha - offsetAlpha); glow *= _Intensity; ``` 3. **参数控制**: | 参数 | 作用 | 推荐值 | |------|------|--------| | `_GlowSize` | 光晕扩散范围 | 0.01-0.1 | | `_GlowIntensity` | 光晕强度 | 1-5 | | `_GlowColor` | 光晕颜色 | RGBA | #### 进阶效果实现 1. **动态脉动效果**: ```hlsl // 添时间变量 float pulse = (sin(_Time.y * 3) + 1) * 0.5; glow *= pulse * _PulseIntensity; ``` 2. **多重光晕**: ```hlsl // 分层采样 float innerGlow = CalculateGlow(uv, 0.02); float outerGlow = CalculateGlow(uv, 0.05); finalColor = tex.rgb + _InnerColor * innerGlow + _OuterColor * outerGlow; ``` 3. **形状控制**: ```hlsl // 使用距离场增强形状控制 float dist = 1 - smoothstep(0.3, 0.7, length(uv - 0.5)); glow *= dist; ``` #### 性能优化技巧 1. **采样优化**: ```glsl // 减少采样次数 half2 diagOffsets[4] = { float2(_Size, _Size), float2(-_Size, _Size), float2(_Size, -_Size), float2(-_Size, -_Size) }; ``` 2. **预计算UV**: ```glsl // 顶点着色器预计算偏移UV output.uv1 = input.uv + float2(_GlowSize, 0); output.uv2 = input.uv + float2(0, _GlowSize); ``` 3. **LOD分级**: ```glsl // 根据距离降低采样质量 float lod = distance(_WorldSpaceCameraPos, positionWS) * 0.01; half neighbor = SAMPLE_TEXTURE2D_LOD(_MainTex, sampler_MainTex, uv, lod).a; ``` #### 应用场景示例 1. **2D角色技能特效**: ```glsl _GlowColor = (0.2, 0.8, 1, 1); // 青色光晕 _GlowSize = 0.03; _GlowIntensity = 3.5; ``` 2. **UI元素高亮**: ```glsl // 按钮激活状态 _GlowColor = (1, 0.9, 0.2, 0.8); // 金色光晕 _GlowIntensity = 2.0; ``` 3. **场景交互提示**: ```glsl // 可交互物体 float pulse = sin(_Time.y * 4) * 0.5 + 0.5; _GlowIntensity *= pulse; // 添脉动效果 ``` > 实现提示:URP 2D渲染需开启"Light Mode"为"Universal2D"并配置2D渲染器数据[^1]。复杂效果可参考Unity的2D技术演示项目[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值