2013年10月22日 星期二

Blur CubeMap

有時候會需要Blur CubeMap
例如 要用 CubeMap的Mip Map表現 roughness時
但一般自動產生的mip map邊緣會不連續

這時候可以用cubemapgen/產生連續的mip map結果

產生出來的圖,再到Unity裡讀進來,建立CubeMap
 using UnityEngine;  
 using System.Collections;  
 using System;  
 public class BlurCubeMap : MonoBehaviour {  
      public Cubemap TextureCube;  
      public Texture2D [] mTexture;  
      CubemapFace[] faces = {CubemapFace.PositiveX, CubemapFace.NegativeX, CubemapFace.PositiveY, CubemapFace.NegativeY, CubemapFace.PositiveZ, CubemapFace.NegativeZ };  
      // Use this for initialization  
      void Start () {  
       int miplevel = 0;  
       if(mTexture.Length > 0)  
       {  
           miplevel = mTexture[0].mipmapCount;  
       }  
      // TextureCube = new Cubemap (256, TextureFormat.ARGB32, true);  
       for(int i = 0; i <6 ; ++i){  
                for(int m = 0 ; m < miplevel; ++m)  
                {  
                     Color[] c = mTexture[i].GetPixels(m);  
                     //mip map level 6 is stranger   
                     if(m == 6)  
                     {  
                          if(i == 0)  
                               c = mTexture[1].GetPixels(m);  
                          if(i == 1)  
                               c = mTexture[0].GetPixels(m);                                
                     }  
                     if(m == 6) //mirror it  
                     {  
                          Color[] c2 = mTexture[i].GetPixels(m);  
                          int width =(int)Math.Sqrt(c.Length);  
                          int currentidx = 0;  
                          for(int idx = 0; idx < width; ++idx)  
                          {  
                               for(int idx2 = 0; idx2 < width; ++idx2)  
                               {  
                                    int switchidx = currentidx + (width -1 -(idx2 * 2));  
                                    c[currentidx] = c2[switchidx];  
                                    currentidx++;  
                               }  
                          }  
                     }  
                     else{  
                          Array.Reverse(c);  
                     }  
                     TextureCube.SetPixels(c,faces[i], m);  
                     //Debug.Log(m);  
                }  
           }  
      TextureCube.Apply(false);  
      }  
      // Update is called once per frame  
      void Update () {  
      }  
 }  

Toon Shader

參考
http://u16hp.blog134.fc2.com/page-2.html
的Shader

原來的效果可以找TMX Editor來看


Shader Code:
 Shader "Outlined/Diffuse" {  
      Properties {  
           _Color ("Main Color", Color) = (.5,.5,.5,1)  
           _OutlineColor ("Outline Color", Color) = (0,0,0,1)  
           _Outline ("Outline width",Float) = .005  
         _RimColor ("Rim Color", Color) = (0.26,0.19,0.16,0.0)  
         _RimPower ("Rim Power", Range(0.5,8.0)) = 3.0  
           _MainTex ("Base (RGB)", 2D) = "white" { }  
           _SpecTex ("Specular (RGB)", 2D) = "white" { }  
           _RampTex ("Ramp (RGB)", 2D) = "white" { }  
      }  
 CGINCLUDE  
 #include "UnityCG.cginc"  
 struct appdata {  
      float4 vertex : POSITION;  
      float3 normal : NORMAL;  
 };  
 struct v2f {  
      float4 pos : POSITION;  
      float4 color : COLOR;  
 };  
 uniform float _Outline;  
 uniform float4 _OutlineColor;  
 v2f vert(appdata v) {       
      v2f o;  
      o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
      float3 norm  = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);  
      float2 offset = TransformViewToProjection(norm.xy);  
      float viewScaler = (o.pos.z + 1) *0.5;  
      o.pos.xy += offset * viewScaler * _Outline;  
      o.color = _OutlineColor;  
      return o;  
 }  
 ENDCG  
      SubShader {  
      Tags { "RenderType"="Opaque" }  
 CGPROGRAM  
 #pragma surface surf Ramp vertex:myvert  
 #pragma target 3.0  
 sampler2D _MainTex;  
 sampler2D _RampTex;  
 sampler2D _SpecTex;  
 fixed4 _Color;  
 float4 _RimColor;  
 float _RimPower;  
 struct Input {  
      float2 uv_MainTex;  
      float3 Vnormal;  
 };  
 half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {  
      half NdotL = dot (s.Normal, lightDir);  
      half diff = max(NdotL,0); 
      half3 ramp = tex2D (_RampTex, float2(0,diff)).rgb;  
      half4 c;  
      // c.rgb = _LightColor0.rgb * ramp * (atten * 2);  
      c.rgb = s.Albedo * ramp;  
      c.a = s.Alpha;  
      return c;  
 }  
 void myvert (inout appdata_full v, out Input o) {  
      UNITY_INITIALIZE_OUTPUT(Input,o);  
      o.Vnormal = normalize(mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal));
    }  
 void surf (Input IN, inout SurfaceOutput o) {  
      fixed4 c = tex2D(_MainTex, IN.uv_MainTex)* _Color;  
      float2 specUV = float2(IN.Vnormal.x *0.5 +0.5, IN.Vnormal.y * 0.5 + 0.5);  
      fixed4 spec = tex2D(_SpecTex, specUV);  
   o.Emission = spec * _RimColor.rgb;  
      o.Albedo = c.rgb;  
      o.Alpha = c.a;  
 }  
 ENDCG  
           Pass {  
                Name "OUTLINE"  
                Tags { "LightMode" = "Always" }  
                Cull Front  
                //Cull off  
                ZWrite On  
                //ZTest Off  
                ColorMask RGB  
                Blend SrcAlpha OneMinusSrcAlpha  
                //Offset 20,20  
                CGPROGRAM  
                #pragma vertex vert  
                #pragma fragment frag  
                half4 frag(v2f i) :COLOR   
                {  
                 i.color.a = 0.5;  
                 return i.color;   
                }  
                ENDCG  
           }  
      }  
      Fallback "Diffuse"  
 }  
對描邊的效果還不大滿意
比較特別的是拿View Space的Normal x, y 當uv查一張貼圖做Rim Light的效果,這樣可以自己決定有漸層的顏色和Rim的範圍
For 3dsMax的(聽美術說有點問題,但還沒問是什麼問題 XD)
 // 3ds max effect file  
 // Simple Lighting Model  
 // This is used by 3dsmax to load the correct parser  
 string ParamID = "0x0000";  
 //DxMaterial specific   
 // light direction (view space)  
 float3 lightDir : Direction <   
      string UIName = "Light Direction";   
      string Object = "TargetLight";  
   string Space = "World";  
      //int refID = 0;  
      >;  
 // light intensity  
 float4 I_a = { 0.1f, 0.1f, 0.1f, 1.0f };  // ambient  
 float4 I_d = { 1.0f, 1.0f, 1.0f, 1.0f };  // diffuse  
 float4 I_s = { 1.0f, 1.0f, 1.0f, 1.0f };  // specular  
 // material reflectivity  
 float4 k_d <  
      string UIName = "Diffuse";  
      > = float4( 0.47f, 0.47f, 0.47f, 1.0f );  // diffuse  
 float outline <  
   string UIName = "outline";  
      > = float(0.005f);  
 float4 rimColor<  
      string UIName = "Rim Color";  
      > = float4( 1.0f, 1.0f, 1.0f, 1.0f );   
 float4 outlineColor<  
      string UIName = "Outline Color";  
      > = float4( 0.0f,0.0f, 0.0f, 0.0f );   
 texture diffuseTexture : DiffuseMap<   
      //string name = "seafloor.dds";   
      string UIName = "Diffuse Texture";  
 //     int Texcoord = 0;  
 //     int MapChannel = 3;       
      >;  
 texture specularTexture : SpecularMap<   
      //string name = "seafloor.dds";   
      string UIName = "Specular Texture";  
 //     int Texcoord = 0;  
 //     int MapChannel = 3;       
      >;       
 texture rampMap : RampMap <   
 //     string name = "NMP_Ripples2_512.dds";   
      string UIName = "Ramp Texture";  
 //     int Texcoord = 0;  
 //     int MapChannel = 3;       
      >;  
 //vertex color       
 int texcoord0 : Texcoord  
 <  
      int Texcoord = 0;  
      int MapChannel = 0;  
 >;  
 //uv 1  
 int texcoord1 : Texcoord  
 <  
      int Texcoord = 1;  
      int MapChannel = 1;  
 >;       
 // transformations  
 float4x4 World   :           WORLD;  
 float4x4 View    :           VIEW;  
 float4x4 Projection :           PROJECTION;  
 float4x4 WorldViewProj :      WORLDVIEWPROJ;  
 float4x4 WorldView :           WORLDVIEW;  
 struct VS_OUTPUT  
 {  
   float4 Pos : POSITION;  
      float2 TexCoord0 : TEXCOORD0;  
      float3 Normal : TEXCOORD1;  
      float3 LightVector : TEXCOORD2;  
      float3 Vnormal : TEXCOORD3;  
   float4 col : COLOR0;  
 };  
 struct VS_OUTPUT2  
 {  
   float4 Pos : POSITION;  
   float4 col : COLOR0;  
 };  
 VS_OUTPUT VS(  
   float3 Pos : POSITION,   
   float4 col     : TEXCOORD0,  
   float3 Norm : NORMAL,   
   float2 Tex : TEXCOORD1)  
 {  
   VS_OUTPUT Out = (VS_OUTPUT)0;  
   float3 L = lightDir;  
   float3 P = mul(float4(Pos, 1),(float4x4)World); // position (view space)  
   float3 N = normalize(mul(Norm,(float3x3)World)); // normal (view space)  
   float3 R = normalize(2 * dot(N, L) * N - L);     // reflection vector (view space)  
   float3 V = normalize(P);               // view direction (view space)  
   Out.Pos = mul(float4(Pos,1),WorldViewProj);  // position (projected)  
   Out.col = col;  
      Out.Normal = N;  
      Out.Vnormal = normalize(mul(Norm,(float3x3)WorldViewProj));  
   Out.TexCoord0 = Tex;  
      Out.LightVector = normalize(lightDir);  
      //Out.LightVector = normalize(mul(lightDir,(float3x3)World));;  
   return Out;  
 }  
 sampler2D diffuseSampler = sampler_state  
 {  
      Texture = <diffuseTexture>;  
      MinFilter = Linear;  
      MagFilter = Linear;  
      MipFilter = Linear;  
      ADDRESSU = Wrap;  
      ADDRESSV = Wrap;  
 };  
 sampler2D specularSampler = sampler_state  
 {  
      Texture = <specularTexture>;  
      MinFilter = Linear;  
      MagFilter = Linear;  
      MipFilter = Linear;  
      ADDRESSU = CLAMP;  
      ADDRESSV = CLAMP;  
 };  
 sampler2D rampSampler = sampler_state   
 {  
      Texture = <rampMap>;  
      MinFilter = Linear;  
      MagFilter = Linear;  
      MipFilter = Linear;  
      ADDRESSU = CLAMP;  
      ADDRESSV = CLAMP;  
 };  
 float4 PS(VS_OUTPUT IN,   
            uniform sampler2D DiffuseMap,  
            uniform sampler2D RampMap,  
            uniform sampler2D SpecularMap) : COLOR  
 {  
      float4 color = tex2D(DiffuseMap, IN.TexCoord0);  
      float2 specUV = float2(IN.Vnormal.x *0.5 +0.5, IN.Vnormal.y * 0.5 + 0.5);  
      half NdotL = max(0,dot (IN.Normal, IN.LightVector));  
      NdotL = clamp(NdotL, 0, 1);  
      half3 ramp = tex2D (RampMap, float2(0,1.0-NdotL)).rgb;  
      ramp = ramp* (IN.col.r) + 1.0 * (1.0- IN.col.r);  
      float4 spec = tex2D(SpecularMap, specUV);  
   color.rgb = color.rgb * ramp* (1.0 - IN.col.r) + color.rgb * ramp* (IN.col.r) + spec * rimColor;  
      //color.rgb = color*k_d;  
      //color.rgb = tex2D(DiffuseMap, IN.TexCoord0).rgb;  
      //color.a = 1;  
   return color ;  
 }  
 VS_OUTPUT2 VS_Outline(  
   float3 Pos : POSITION,   
   float3 Norm : NORMAL )  
 {  
      VS_OUTPUT2 Out;  
      Out.Pos = mul(float4(Pos,1),WorldViewProj);   
      float3 norm = (mul(Norm,(float3x3)WorldViewProj));  
      float viewScaler = (Out.Pos.z + 1) *0.5;  
      //float viewScaler = Out.Pos.z;  
      Out.Pos.xy += norm.xy * viewScaler * outline;  
      Out.col = outlineColor;  
      return Out;  
 }  
 float4 PS_Outline(  
      VS_OUTPUT IN  
 ) : COLOR  
 {  
  float4 color = IN.col;  
  color.a = 0.5;  
  return color;  
 }  
 technique DefaultTechnique  
 {  
   pass P1  
   {  
     // shaders  
           ZEnable = true;  
           ZWriteEnable = true;  
     CullMode = cw;  
           AlphaBlendEnable = true;  
           SrcBlend = srcalpha;  
           DestBlend = zero;  
     VertexShader = compile vs_2_0 VS_Outline();  
     PixelShader = compile ps_2_0 PS_Outline();  
   }   
    pass P0  
   {  
     // shaders  
           ZEnable = true;  
           ZWriteEnable = true;  
     CullMode = ccw;  
     // ShadeMode = Gouraud;  
     VertexShader = compile vs_2_0 VS();  
     PixelShader = compile ps_2_0 PS(diffuseSampler, rampSampler, specularSampler);  
   }   
 }  

CubeMap奇怪現象

前幾天在改Shader時,發現一個奇怪的現象

Unity 的shader可以在貼圖的地方,設定TexGen,讓它自動產生uv
SL-Properties

但是這個產生的UV (我指CubeReflect的部分) 和自己在Shader裡產生的結果不大一樣

最左邊的是用內建的Shader
中間的Shader code是
 Shader "Custom/testCubeMap1" {  
      Properties {  
           _Color ("Color", Color) = (1,1,1,1)  
           _ReflectTex ("Reflection Texture", Cube) = "dummy.jpg" {  
                TexGen CubeReflect  
           }  
      }        
      SubShader {  
           Tags {  
                "Queue" = "Geometry"  
           }  
           Pass {  
                Fog { Color (0,0,0,0)}  
                SetTexture [_ReflectTex] {  
                     combine texture  
                }  
           }  
      }  
      SubShader {  
           Pass {  
                Color [_Color]  
           }  
      }  
 }  
最右邊的是:
 Shader "Custom/testCubeMap2" {  
      Properties {  
           _Cube ("Reflection Cubemap", Cube) = "_Skybox" { TexGen CubeReflect }  
      }  
      SubShader {  
           Tags { "RenderType"="Opaque" }  
           LOD 200  
           CGPROGRAM  
           #pragma surface surf Lambert  
     #pragma target 3.0  
           samplerCUBE _Cube;  
           struct Input {  
                float3 worldRefl;  
           INTERNAL_DATA  
           };  
           void surf (Input IN, inout SurfaceOutput o) {  
           o.Emission = texCUBE (_Cube, WorldReflectionVector (IN, float3(0,0,1))).rgb;  
           }  
           ENDCG  
      } 
中間的是用自動產生的UV,左右都是用算的(左的產生方法是 fixed4 reflcol = texCUBE (_Cube, IN.worldRefl);  可以抓unity Default shader來看) 自動產生的uv x方向反了,而且視角在動時,邊緣Distort很明顯。 目前用的版本是Unity 4.2.0f4

2013年10月2日 星期三

學習筆記-IMR, TBR, TBDR

IMR (Immediate Mode Rendering)
現在PC上的顯卡架構


可以看出來常存取 framebuffer,而且pixel 有很多overdraw,導致bandwidth 需求很高,也有許多浪費。並且在行動平台上也較秏電。
ex. NVIDIA Tegra

TBR(Tile Based Rendering)

確保了 100% cache efficiency在color buffer和depth buffer,因為不是寫在ram裡,而是寫在on-Chip memory。但對於看不見的物件還是有overdraw。
ex. Arm Mali (Small tiles), Qualcomm Adreno(Large tiles)
TBDR(Tile Based Deferred Rendering)


delay或defer all texturing and shading operations until their visibility is known
HSR(Hidden Surface Removal)
ex. Imagination的PowerVR

Tiled的種類
-small (ex. 16x16) SGX, Mali
-relatively large (ex. 256K) - Adreno

memory is on chip - Fast
once GPU is done rendering tile -> tile is "resolved" - written out  to  slower RAM

Sort opaque geom differently for Traditional vs Tiled
Tiled - sort by material to reduce cpu drawcalls
Traditional - sort roughly front-to-back to maximize ZCull efficiency then by material
Tiled Deferred: render alpha-tested after opaque (有很高的機率expensive alpha-test 會occluded)

Use EXT_discard_framebuffer extensions on Tiled
• will avoid copying data (color/depth/stencil) you're not planning to use

Clear RenderTarget before rendering into it
• otherwise on Tiled driver will copy color/depth/stencil back from RAM
• not clearing is not an optimization! (和傳統不一樣, 傳統可能不clear buffer減少cost)

Benefits
• Tiled: MSAA is almost free (5-10% of rendering time)
• Tiled: AlphaBlending is significantly cheaper
• Tiled: less dithering artifacts for 16bit framebuffers

Caveats
• TBDR: RenderTarget switch might be more expensive
• TBDR: Too much geometry will flush whole pipeline (ParameterBuffer overflow)
reference:
http://withimagination.imgtec.com/index.php/powervr/understanding-powervr-series5xt-powervr-tbdr-and-architecture-efficiency-part-4

http://www.realtimerendering.com/downloads/MobileCrossPlatformChallenges_siggraph.pdf