在unity中實現簡單的程式紋理 10.3.1
阿新 • • 發佈:2018-12-14
using UnityEngine; using System.Collections; using System.Collections.Generic; //在unity中實現簡單的程式紋理 10.3.1 //在編輯模式執行 [ExecuteInEditMode] public class ProceduralTextureGeneration : MonoBehaviour { //宣告一個材質,這個材質將使用該指令碼中生成的程式紋理 public Material material = null; //宣告程式紋理將使用的各種引數 //使用外掛SetProperty將引數顯示在面板上,這使得當修改了材質屬性時,可執行_UpdateMaterial函式來使用新的屬性重新生成程式紋理 #region Material properties [SerializeField, SetProperty("textureWidth")] //材質紋理寬度 private int m_textureWidth = 512; public int textureWidth { get { return m_textureWidth; } set { m_textureWidth = value; _UpdateMaterial(); } } //材質紋理背景顏色 [SerializeField, SetProperty("backgroundColor")] private Color m_backgroundColor = Color.white; public Color backgroundColor { get { return m_backgroundColor; } set { m_backgroundColor = value; _UpdateMaterial(); } } //材質紋理圓形顏色 [SerializeField, SetProperty("circleColor")] private Color m_circleColor = Color.yellow; public Color circleColor { get { return m_circleColor; } set { m_circleColor = value; _UpdateMaterial(); } } //材質紋理模糊因子 [SerializeField, SetProperty("blurFactor")] private float m_blurFactor = 2.0f; public float blurFactor { get { return m_blurFactor; } set { m_blurFactor = value; _UpdateMaterial(); } } #endregion //為了儲存生成的程式紋理,宣告一個Texture2D型別的紋理變數 private Texture2D m_generatedTexture = null; //在start 函式中進行相應的檢查,以得到需要使用該程式紋理的材質 void Start () { //檢查material是否為空 if (material == null) { //如果為空嘗試從使用該指令碼所在的物體上得到相應材質 Renderer renderer = gameObject.GetComponent<Renderer>(); if (renderer == null) { Debug.LogWarning("Cannot find a renderer."); return; } material = renderer.sharedMaterial; } _UpdateMaterial(); } //_UpdateMaterial函式程式碼 private void _UpdateMaterial() { //確保material不會為空 if (material != null) { // 調取_GenerateProceduralTexture函式來生成一張程式紋理給 m_generatedTexture變數 m_generatedTexture = _GenerateProceduralTexture(); //利用material.SetTexture函式把生成的紋理賦給材質,材質material中需要有一個名為_MainTex的紋理屬性 material.SetTexture("_MainTex", m_generatedTexture); } } private Color _MixColor(Color color0, Color color1, float mixFactor) { Color mixColor = Color.white; mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor); mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor); mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor); mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor); return mixColor; } //_GenerateProceduralTexture函式程式碼 private Texture2D _GenerateProceduralTexture() { //初始化一張二維紋理,並且提前計算了一些生成紋理時需要的變數, Texture2D proceduralTexture = new Texture2D(textureWidth, textureWidth); // The interval between circles(定義圓與圓之間的間距) float circleInterval = textureWidth / 4.0f; // The radius of circles(定義圓的半徑) float radius = textureWidth / 10.0f; // The blur factor(定義模糊係數) float edgeBlur = 1.0f / blurFactor; // for (int w = 0; w < textureWidth; w++) { for (int h = 0; h < textureWidth; h++) { // Initalize the pixel with background color(使用背景顏色進行初始化) Color pixel = backgroundColor; //使用兩層巢狀的迴圈遍歷紋理中的每個畫素,並在紋理上依次繪製9個圓形 // Draw nine circles one by one(依次畫九個圓) for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // Compute the center of current circle(計算當前所繪製的圓的圓心位置) Vector2 circleCenter = new Vector2(circleInterval * (i + 1), circleInterval * (j + 1)); // Compute the distance between the pixel and the center(計算當前畫素與圓心的距離) float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius; // Blur the edge of the circle(模糊圓的邊界) Color color = _MixColor(circleColor, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur)); // Mix the current color with the previous color(與之前的到的顏色進行混合) pixel = _MixColor(pixel, color, color.a); } } proceduralTexture.SetPixel(w, h, pixel); } } //呼叫Texture2D.Apply函式來強制把畫素值寫入紋理中, proceduralTexture.Apply(); //返回該程式紋理 return proceduralTexture; } }
Shader "Unlit/Single Texture" { Properties{ _Color("Color Tint", Color) = (1, 1, 1, 1) _MainTex("Main Tex", 2D) = "white" {} _Specular("Specular", Color) = (1, 1, 1, 1) _Gloss("Gloss", Range(8.0, 256)) = 20 } SubShader{ Pass{ Tags{ "LightMode" = "ForwardBase" } CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Specular; float _Gloss; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float3 worldPos : TEXCOORD1; float2 uv : TEXCOORD2; }; v2f vert(a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; // Or just call the built-in function // o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target{ fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // Use the texture to sample the diffuse color fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); fixed3 halfDir = normalize(worldLightDir + viewDir); fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0); } ENDCG } } FallBack "Specular" }
外掛SetProperty 的下載地址