今天有个奇怪的尝试,打算实现一下让场景里一张图片直接转换成为黑白的效果,首先想到的是使用 Shader。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| Shader "Custom/GrayscaleShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc"
struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; };
struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; };
sampler2D _MainTex;
v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); float grayscale = dot(col.rgb, float3(0.299, 0.587, 0.114)); return fixed4(grayscale, grayscale, grayscale, col.a); } ENDCG } } }
|
创建一个新的Material,并将新创建的Shader赋给这个Material。在你的场景中,找到想要转换为黑白的SpriteRenderer,并将这个新创建的Material赋给它们。
但是操作起来太麻烦了,于是尝试了一种纯粹使用代码完成的思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| using UnityEngine;
public class ConvertSpriteToBlackAndWhite : MonoBehaviour { void Start() { SpriteRenderer[] allSprites = FindObjectsOfType<SpriteRenderer>(); foreach (SpriteRenderer spriteRenderer in allSprites) { ConvertToBlackAndWhite(spriteRenderer); } }
void ConvertToBlackAndWhite(SpriteRenderer spriteRenderer) { if (spriteRenderer.sprite == null) return;
Texture2D originalTexture = spriteRenderer.sprite.texture; Texture2D grayscaleTexture = new Texture2D(originalTexture.width, originalTexture.height); Color[] originalPixels = originalTexture.GetPixels(); Color[] grayscalePixels = new Color[originalPixels.Length];
for (int i = 0; i < originalPixels.Length; i++) { Color originalColor = originalPixels[i]; float grayscaleValue = originalColor.grayscale; grayscalePixels[i] = new Color(grayscaleValue, grayscaleValue, grayscaleValue, originalColor.a); }
grayscaleTexture.SetPixels(grayscalePixels); grayscaleTexture.Apply();
spriteRenderer.sprite = Sprite.Create(grayscaleTexture, spriteRenderer.sprite.rect, new Vector2(0.5f, 0.5f)); } }
|
原理是,复制Sprite的原始纹理,然后对这个复制品的每个像素应用灰度转换。当然这种方法的效率非常低。
之后又改进了一下代码,可以实现渐变为黑白的效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| using System.Collections; using UnityEngine;
public class GradualBlackAndWhite : MonoBehaviour { public float transitionDuration = 2f;
void Start() { StartCoroutine(ApplyBlackAndWhiteGradually()); }
IEnumerator ApplyBlackAndWhiteGradually() { SpriteRenderer[] allSprites = FindObjectsOfType<SpriteRenderer>(); float time = 0;
while (time < transitionDuration) { foreach (SpriteRenderer spriteRenderer in allSprites) { ConvertToBlackAndWhite(spriteRenderer, time / transitionDuration); }
time += Time.deltaTime; yield return null; }
foreach (SpriteRenderer spriteRenderer in allSprites) { ConvertToBlackAndWhite(spriteRenderer, 1); } }
void ConvertToBlackAndWhite(SpriteRenderer spriteRenderer, float lerpFactor) { if (spriteRenderer.sprite == null) return;
Texture2D originalTexture = spriteRenderer.sprite.texture; Texture2D grayscaleTexture = new Texture2D(originalTexture.width, originalTexture.height); Color[] originalPixels = originalTexture.GetPixels(); Color[] grayscalePixels = new Color[originalPixels.Length];
for (int i = 0; i < originalPixels.Length; i++) { Color originalColor = originalPixels[i]; float grayscaleValue = originalColor.grayscale; Color grayscaleColor = new Color(grayscaleValue, grayscaleValue, grayscaleValue, originalColor.a); grayscalePixels[i] = Color.Lerp(originalColor, grayscaleColor, lerpFactor); }
grayscaleTexture.SetPixels(grayscalePixels); grayscaleTexture.Apply();
spriteRenderer.sprite = Sprite.Create(grayscaleTexture, spriteRenderer.sprite.rect, new Vector2(0.5f, 0.5f)); } }
|
最后测试了一下,转换为黑白的效果有点没必要,虽然代码写了,但最后没用 ……