Unity3D Shader:科幻風線框渲染

2021-03-02 遊戲蠻牛

之前看了一本小說叫《副本》,裡面有個描寫就是拷問犯人的時候進入虛擬空間,進入的時候顯示基礎的線條,然後在變得越來越精細,最後女主角為男主角遞上一根煙,正好全部加載完成,之後一直在腦中想像了這個效果,當然最終的實現還是和想像的有點差距,下面我們先來看看最終的效果:


第一步首先先根據模型創建線框,對於這一步我一開始聯想到了Unity的warframe,但是卻不知道如何繪製兩點之間的直線,

然後去找它的類似效果的實現方式,卻意外的發現了Geometry Shader,它介於頂點和片元之間,可以在這一階段通過圖元來修改頂點,下面的實現參考:(文章底部擴展閱讀)

下面來開始編寫我們的shader:

#pragma vertex vert
#pragma geometry geom
#pragma fragment frag

現在我們從原先的頂點-》像素 變成 頂點--》幾何--》像素的方式 同時頂點階段也要變為輸出數據給幾何階段

struct appdata
{
float4 vertex: POSITION;
float2 uv: TEXCOORD0;
};

struct v2g
{
float2 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
};

struct g2f
{
float2 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
};

sampler2D _MainTex;
float4 _MainTex_ST;

v2g vert(appdata v)
{
v2g o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream < g2f > triStream)
{
g2f OUT;

OUT.vertex = IN[0].vertex;
OUT.uv = IN[0].uv;
triStream.Append(OUT);

OUT.vertex = IN[1].vertex;
OUT.uv = IN[1].uv;
triStream.Append(OUT);

OUT.vertex = IN[2].vertex;
OUT.uv = IN[2].uv;
triStream.Append(OUT);
}

fixed4 frag(g2f i): SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}

下面繪製線框,繪製線框的原理是這樣的,在幾何階段,我們得到一個三角形,那麼對於這個三角形內部的點來說,該點距離其他三條邊的距離是0的話,說明這個點在這個三角形的邊上,我們可以使用一個變量來控制最小的距離來實現控制線框的寬度。

[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream < g2f > triStream)
{
float2 p0 = IN[0].vertex.xy / IN[0].vertex.w;
float2 p1 = IN[1].vertex.xy / IN[1].vertex.w;
float2 p2 = IN[2].vertex.xy / IN[2].vertex.w;

float2 v0 = p2 - p1;
float2 v1 = p2 - p0;
float2 v2 = p1 - p0;
//triangles area
float area = abs(v1.x * v2.y - v1.y * v2.x);

// //到三條邊的最短距離
g2f OUT;
OUT.vertex = IN[0].vertex;
OUT.uv = IN[0].uv;
OUT.dist = float3(area / length(v0), 0, 0);
triStream.Append(OUT);

OUT.vertex = IN[1].vertex;
OUT.uv = IN[1].uv;
OUT.dist = float3(0, area / length(v1), 0);
triStream.Append(OUT);

OUT.vertex = IN[2].vertex;
OUT.uv = IN[2].uv;
OUT.dist = float3(0, 0, area / length(v2));
triStream.Append(OUT);
}

首先P0,P1,P2三個點根據世界坐標除以w得到視口坐標,v0,v1,v2則是對應的三個邊的方向,area則利用叉積的幾何意義得到三角形的面積(應該是平行四邊形),那麼對於每個點而言,這個點到對著邊的距離根據面積公式反推可以得到 平行四邊形的面積除以對邊的長度,我們將距離記錄下來。

fixed4 frag(g2f i): SV_Target
{

fixed4 col_Wire;
float d = min(i.dist.x, min(i.dist.y, i.dist.z));
col_Wire.rgb = d < _WireWidth?_WireColor: _FillColor;
col_Wire.a = 1;
return col_Wire;
}

到了像素階段,我們就可以比較這個點到三條邊的最短距離,得到一個最短距離,然後就可以通過這個最短距離來決定如何渲染,這裡我們添加了一個變量_WireWidth 來判斷距離,另外添加了兩種顏色,分別取渲染線和其他區域

到這裡線框處理好了,下面我們再來實現斷層的效果

struct v2g
{
float3 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
};

struct g2f
{
float3 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
float3 dist: TEXCOORD1;
};

..

v2g vert(appdata v)
{
v2g o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
o.uv.z = _Clip + v.vertex.x;
return o;
}
....
fixed4 frag(g2f i): SV_Target
{
clip(i.uv.z);
....

我們新加入了一個變量_Clip來對模型進行clip,將z的高度信息暫時保存在uv.z中,然後進行clip

模型已經被裁剪掉了,下面再來實現對原有材質的漸變

half blendValue = smoothstep(_Lerp - _WireLerpWidth, _Lerp + _WireLerpWidth, i.uv.z);
fixed4 col_Tex = tex2D(_MainTex, i.uv);
//return blendValue * col_Tex;
return lerp(col_Wire, col_Tex, blendValue);

_Lerp用於控制離線框的遠近,_WireLerpWidth用於控制邊緣寬度

完成!

完整代碼如下

Shader "Unlit/Wireframe2"
{
Properties
{
_MainTex ("Texture", 2D) = "white" { }
_WireColor ("WireColor", Color) = (1, 0, 0, 1)
_FillColor ("FillColor", Color) = (1, 1, 1, 1)
_WireWidth ("WireWidth", Range(0, 0.005)) = 1

_Clip ("Clip", Range(-2, 2.5)) = 1
_Lerp ("Lerp", Range(0, 1)) = 0.5
_WireLerpWidth ("WireLerpWidth", Range(0, 1)) = 0.1
}
SubShader
{
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
LOD 100

Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
CGPROGRAM

#pragma vertex vert
#pragma geometry geom
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex: POSITION;
float2 uv: TEXCOORD0;
};

struct v2g
{
float3 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
};

struct g2f
{
float3 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
float3 dist: TEXCOORD1;
};

sampler2D _MainTex;
float4 _MainTex_ST;

float4 _FillColor, _WireColor;
float _WireWidth, _Clip, _Lerp, _WireLerpWidth;

v2g vert(appdata v)
{
v2g o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
o.uv.z = _Clip + v.vertex.x;
return o;
}

[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream < g2f > triStream)
{
float2 p0 = IN[0].vertex.xy / IN[0].vertex.w;
float2 p1 = IN[1].vertex.xy / IN[1].vertex.w;
float2 p2 = IN[2].vertex.xy / IN[2].vertex.w;

float2 v0 = p2 - p1;
float2 v1 = p2 - p0;
float2 v2 = p1 - p0;
//triangles area
float area = abs(v1.x * v2.y - v1.y * v2.x);

// //到三條邊的最短距離
g2f OUT;
OUT.vertex = IN[0].vertex;
OUT.uv = IN[0].uv;
OUT.dist = float3(area / length(v0), 0, 0);
triStream.Append(OUT);

OUT.vertex = IN[1].vertex;
OUT.uv = IN[1].uv;
OUT.dist = float3(0, area / length(v1), 0);
triStream.Append(OUT);

OUT.vertex = IN[2].vertex;
OUT.uv = IN[2].uv;
OUT.dist = float3(0, 0, area / length(v2));
triStream.Append(OUT);
}

fixed4 frag(g2f i): SV_Target
{
clip(i.uv.z);
fixed4 col_Wire;
float d = min(i.dist.x, min(i.dist.y, i.dist.z));
col_Wire = d < _WireWidth?_WireColor: _FillColor;
//return col_Wire;
//顏色差值
half blendValue = smoothstep(_Lerp - _WireLerpWidth, _Lerp + _WireLerpWidth, i.uv.z);


fixed4 col_Tex = tex2D(_MainTex, i.uv);
//return blendValue * col_Tex;
return lerp(col_Wire, col_Tex, blendValue);
}
ENDCG

}
}
}

來源知乎專欄:Unity開發學習

擴展閱讀:

GeometryShader這個概念,已經出現很久了,但由於性能不佳,所以使用的並不多。甚至移動平臺根本就不支持。移動平臺的硬體更新速度也是越來越快,GS的應用普及應該不會太遠。就現階段而言,GS來做一些輔助效果也是有一定用武之地的。就像本文要提到的這個線框渲染的效果(如下圖)。在Unity編輯模式中,偶爾有時候希望能有這種效果, 我在AssetStore裡找到了一個叫UCLA Wireframe Shader的資源,裡面有Shader源碼。發現它是利用GS來實現的,本文就以它的源碼為例來說明一下它是如何利用GeometryShader來實現這種線框渲染效果(WireFrame)的。

概念解釋

在具體看代碼之前,需要先對幾何著色器階段有個初步了解,大概需要知道需要下面幾兩個概念:

1.圖元(graphics primitive)

  幾乎所有的圖形渲染入門書籍裡,都要提到這個概念,我們知道,所有的幾何模型都是有點,線,三角形等基本單元組成的(這裡以三角形為例),每個圖元又是由若干個頂點構成。在渲染管線的開始,GPU處理的是每一個頂點,但是GPU是知道每一個頂點是屬於哪個三角形的。所有頂點經過頂點著色器處理後輸出的結果會經過一個圖元裝配(Primitive Assembly)的階段,這個階段就是把這些處理後的頂點組裝成成一個個三角形。為什麼這麼做呢?因為之後的無論是光柵化和頂點信息插值過程,以及視椎體的裁剪,都是以圖元為單位進行的(如果你對這個過程不是非常了解,可以查查資料,或者去看一下劉鵬翻譯的《計算機圖形學—基於3D圖形開發技術》),經過上述的這些階段後再到達我們熟悉的片元著色階段,也就離最終渲染結果不遠了。

2.幾何著色器(Geometry Shader)

  對於VS,FS我們都比較熟悉,那GS出現在哪呢?從下面這種圖中我們可以看到GS是位於VS和FS之間的。並且是虛線連接,即是可選的。GeometryShader所接收的實際是對VS輸出的圖元進行添加,刪除,或修改,然後輸出新的圖元信息。再之後的流程就和之前的一樣了。

進行線框渲染,一個比較困擾的地方就是我們不知道一個頂點是屬於哪一個圖元的。但是有了GS的參與之後,這一切就迎刃而解了。後面解釋代碼時會具體說。

代碼解釋

Shader "UCLA Game Lab/Wireframe/Single-Sided"

{

Properties

{

_Color ("Line Color", Color) = (,,,)

_MainTex ("Main Texture", 2D) = "white" {}

_Thickness ("Thickness", Float) =

}

 

SubShader

{

Pass

{

Tags { "RenderType"="Transparent" "Queue"="Transparent" }

 

Blend SrcAlpha OneMinusSrcAlpha

ZWrite Off

LOD

 

CGPROGRAM

#pragma target 5.0

#include "UnityCG.cginc"

#include "UCLA GameLab Wireframe Functions.cginc"

#pragma vertex vert

#pragma fragment frag

#pragma geometry geom

 

// Vertex Shader

UCLAGL_v2g vert(appdata_base v)

{

return UCLAGL_vert(v);

}

 

// Geometry Shader

[maxvertexcount()]

void geom(triangle UCLAGL_v2g p[], inout TriangleStream<UCLAGL_g2f> triStream)

{

UCLAGL_geom( p, triStream);

}

 

// Fragment Shader

float4 frag(UCLAGL_g2f input) : COLOR

{

return UCLAGL_frag(input);

}

 

ENDCG

}

}

}

可以看到這個文件裡調用了很多定義在"UCLA GameLab Wireframe Functions.cginc"這個文件中的函數。後面用到時候再看。

第26行:指定了用於幾何著色器執行的函數。與vs,fs一樣。另外21行中指定了要是用的ShaderModel(SM定義了著色器代碼的一些規範和能力),這裡必須是4.0以上的版本。

29~32行:vs的代碼沒有什麼特殊的,下面貼出的UCLAGL_vert和UCLAGL_v2g的代碼也沒啥不一樣的。唯一值得提一下就是UCLAGL_v2g中pos後面的語意是POSITION而非SV_POSITION,我試了一下這樣沒啥問題。可以看出vs的代碼和以前的意義,進行完頂點處理之後,GPU會進行圖元裝備,接下來就進入到GS階段了。

// DATA STRUCTURES //

// Vertex to Geometry

struct UCLAGL_v2g

{

float4 pos : POSITION; // vertex position

float2 uv : TEXCOORD0; // vertex uv coordinate

};

// Vertex Shader

UCLAGL_v2g UCLAGL_vert(appdata_base v)

{

UCLAGL_v2g output;

output.pos = mul(UNITY_MATRIX_MVP, v.vertex);

output.uv = TRANSFORM_TEX (v.texcoord, _MainTex);//v.texcoord;

 

return output;

}

  35~39行:這段就是GS的執行函數了,其中第35行[maxvertexcount(3)]是用來限制GS輸出的最大頂點數,這裡必須理解清楚,前面說過GS可以對輸入的圖元進行刪除,添加,修改,也就是進來一個圖元,可能輸出0~n個圖元,不論圖元是以何種形式組織的,它都是由頂點構成的,這個maxvertexcount就是用來限定這個頂點數量的,記住它只是限定最大數量,也就是你提供小於等於這個數量的頂點就可以。

  36行:估計你第一次看到這行代碼的時候應該和我一樣感到奇怪。這怎麼還有點模板的意思,還有剛才的那個[maxvertexcount],這個語法看上去有點C#的Attribute的意思啊。平常寫的UnityShader不是說CG語言(C for Graphics),這可和C不太一樣啊。其實Unity的Shader代碼是基於自己的ShaderLab結構的,他用的CG也並不是和Nvidia的CG一模一樣。我查了下OpenGL和官方CG的GS用法,大家的意思都是差不多,但是語法細節上是不一樣的。無論怎麼樣最終Unity會負責對ShaderLab進行編譯,轉化成對於平臺的GLSL或者HLSL語言。

  回到這個函數聲明,第一個參數triangle UCLAGL_v2g p[3],GS接收的是圖元,那這個圖元是以什麼樣的形式傳遞進來的呢?就是以頂點結構數組的形式,比如一個三角形圖元由三個頂點構成,那麼數組大小就是3,相應的點和線就是1和2。這個參數最前面的triangle就是用來表示這個的,還有兩個就是point和line。要記住這個標識符必須和後面數組大小相配。還有一點就是你填寫的圖元標識符類型和Unity原始模型資源的頂點組織方式不要求一定匹配,比如Unity默認組織模型資源是三角圖元的,你在這裡可以用point接收,但這樣的結果就是本來這個圖元有三個頂點,但是你只能接收到第一個了。

第二個參數inout TriangleStream<UCLAGL_g2f> triStream,這裡的inout就和C#的inout是一樣的,CG本身就有這個關鍵字。而TriangleStream決定了輸出的圖元是三角形圖元。對應的還有LineStream和PointStream。UCLAGL_g2f的內容如下:

// Geometry to UCLAGL_fragment

struct UCLAGL_g2f

{

float4 pos : POSITION; // fragment position

float2 uv : TEXCOORD0; // fragment uv coordinate

float3 dist : TEXCOORD1; // distance to each edge of the triangle

};

  這個結構定義了構成GS輸出圖元的頂點結構。這裡有個dist,後面再解釋。可以想像,GS就是把第一個參數的信息拿過來經過處理後把結果填充到第二個參數中去。需要額外說明一下,這裡的Stream類型和上面的maxvertexcount是有一些關聯的,上面代碼輸出圖元類型是三角形,構成三角形最少需要三個頂點,如果我們最終在GS中像triStream提供了小於三個頂點,則GS將放棄這個片元,當然你也可以提供多餘三個頂點,但是超過了maxvertexcount的部分也會被拋棄掉。總之他們兩個是有聯繫的,這裡只是提一下,使用時候要注意。

現在來看一下UCLAGL_geom函數,也是這個Shader的核心部分。

// Geometry Shader

[maxvertexcount()]

void UCLAGL_geom(triangle UCLAGL_v2g p[], inout TriangleStream<UCLAGL_g2f> triStream)

{

//points in screen space

float2 p0 = _ScreenParams.xy * p[].pos.xy / p[].pos.w;

float2 p1 = _ScreenParams.xy * p[].pos.xy / p[].pos.w;

float2 p2 = _ScreenParams.xy * p[].pos.xy / p[].pos.w;

 

//edge vectors

float2 v0 = p2 - p1;

float2 v1 = p2 - p0;

float2 v2 = p1 - p0;

 

//area of the triangle

float area = abs(v1.x*v2.y - v1.y * v2.x);

 

//values based on distance to the edges

float dist0 = area / length(v0);

float dist1 = area / length(v1);

float dist2 = area / length(v2);

 

UCLAGL_g2f pIn;

 

//add the first point

pIn.pos = p[].pos;

pIn.uv = p[].uv;

pIn.dist = float3(dist0,,);

triStream.Append(pIn);

 

//add the second point

pIn.pos = p[].pos;

pIn.uv = p[].uv;

pIn.dist = float3(,dist1,);

triStream.Append(pIn);

 

//add the third point

pIn.pos = p[].pos;

pIn.uv = p[].uv;

pIn.dist = float3(,,dist2);

triStream.Append(pIn);

}

  先說一下開頭處,p0,p1,p2處的計算,因為GS接收的頂點信息都是VS處理過的,在VS中頂點輸出的pos信息已經是其在投影空間下的坐標了。現在p[x].pos.xy/p[x].ps.w實際就是手動進行透視除法,得到視口坐標。_ScreenParams.xy是一個Unity為我們提供的內置變量,表示屏幕的解析度。那麼這兩者相乘就得到了p[x]在屏幕空間的坐標(單位像素)。這裡分別對當前三角圖元的三個頂點進行了計算。

  再分別講頂點兩兩相減,得到三角形的三個邊向量。之後利用叉積的幾何意義得到三角形的面積,這裡實際是平行四邊形面積,注意這裡用的是v1和v2,思考一下為什麼。得到面積後,利用四邊形面積公式(底邊長X高)來得到當前頂點的對角邊的距離。

  計算出這三個距離之後就可以進行輸出了。前面我們提到UCLAGL_g2f結構中有一個dist,現在可以解釋一下了。他是個float3類型,他的xyz分量分別代表了當前頂點到達三角圖元三邊的距離,你可能會奇怪為什麼要用float3,明明一個頂點到其中兩條邊的距離都是0,之後另外一條邊才不是0。要知道我們GS最後輸出的依然是圖元,還沒有進行光柵化插值。最終我們要進行渲染的是片元,這些片元可不一定是正好在圖元的三個頂點上。所以用float3是為了能夠正確的插值,將來光柵化時候能得到片元距離圖元三邊的距離。進行輸出時候先定義了一個UCLAGL_g2f類型的pIn變量。可以看到後面賦值就沒什麼說的,注意dist的賦值。每當構造完一個UCLAGL_g2f變量以後,就調用Append方法把它添加到輸出結構中。

  可見這裡的GS並沒有刪除或者添加圖元,它只是對輸入圖元進行修改再輸出。進來的是三角片元的三個頂點,出去的還是三角片元三個頂點。但是經過GS處理,現在每個頂點都知道他距離他所在的三角圖元三條邊的距離了。正式這個值讓我們在fs中能完成線框渲染的效果。

  第42~45行:fs我們主要看UCLAGL_frag這個函數,代碼如下:

// Fragment Shader

float4 UCLAGL_frag(UCLAGL_g2f input) : COLOR

{

//find the smallest distance

float val = min( input.dist.x, min( input.dist.y, input.dist.z));

 

//calculate power to 2 to thin the line

val = exp2( -/_Thickness * val * val );

 

//blend between the lines and the negative space to give illusion of anti aliasing

float4 targetColor = _Color * tex2D( _MainTex, input.uv);

float4 transCol = _Color * tex2D( _MainTex, input.uv);

transCol.a = ;

return val * targetColor+ ( - val ) * transCol;

}

  要知道現在input參數裡的所有信息,都是經過插值了,它代表的是片元,而不是頂點了。先選出該片元到其所在三角圖元三邊的最短距離val.看最後的幾行代碼,可以知道是利用一個混合因子來進行blend,來達到距離圖元邊越近的片元,可見程度越高。那麼混合因子值的計算就決定了後面這個融合步驟的好壞。如果混合因子選取的不好,最終線框渲染的效果就不好。

  最後來看看混合因子的計算:val = exp2( -1/_Thickness * val * val );這行代碼可以從最外層開始理解,exp2是CG的內置函數,代表2位底的指數函數。你去看看指數函數的圖像就知道,當x小於0的時候y值是在0~1區間內的。而且不會為負。而我們的混合因子也是要在0~1區間的。上式括號中的-1就決定了exp2的參數一定為負,因為_Thickness是大於等於0,val的平方也是大於等於0的。那為什麼要用val的平方的。看一下y=x^2的函數圖像。val是距離,他是大於等於0的,那麼隨著x的增大,y的增大幅度越來越大(y的導函數是個上升函數),也就是說隨著val的增大val*val的取值跨度越來越大。你會問,這又有什麼用呢?你現在把兩個函數圖像結合起來,先不看_Thickness,得到下圖3.

  從圖像上看出當x在0~2範圍內,函數曲線急劇下降。並在之後無限趨近於0。這樣計算後的混合因子大概只在片元距離三角圖元邊線0~2個像素的距離內,可見性才明顯一些,這樣就能畫出比較明顯的邊線效果。 之所以又加上了_Thickness,可以看到把曲線的最終結果除以一個正數,這個數越大,那麼就會越明顯的減緩圖像三曲線的下降效果,也就是圖像不會太快的趨近於0,那麼新的混合因子在表現的時候邊線顯得更寬了。

總結

  這個方法只是視覺上達到了WireFrame的效果,實際上還是以三角圖元的方式來渲染的,只是利用透明度的混合來達到效果。如果真正的想要按照線框模式來渲染,應該修改GS讓他輸出的圖元是LineStream。也就完全不需要像這種方法計算這麼多中間變量了。如果感興趣,不妨寫寫試試。只是想透過這個例子來說明一下Unity中GeometryShader的基本原理和語法。

  貌似Unity的GS好像還只能在DX11API上用,OpenGL上還不行。OpenGL ES目前還不支持GeometryShader。

  利用GS確實能做出很多以前做不出或者很難做出的效果,其中一個關鍵點就是頂點能知道它所在圖元的一些信息,這是以前的VS-FS結構做不到的。

擴展閱讀來源:cnblog作者- esfog

相關焦點

  • Unity VR全景漫遊
    Unity5.3.1 X64 http://unity3d.com/cn/get-unity/download/archive
  • 如何運用Unity製作VR全景漫遊?
    Unity5.3.1 X64: http://unity3d.com/cn/get-unity/download/archivePTGui[可選]: 把全景圖轉成6個立方小圖 http://www.ptgui.com/download.htmlGoogle VR SDK For Unity: https://github.com/googlevr
  • Unity免費的優質場景資源
    使用了HD高清晰渲染管線渲染得到的環境場景。擁有玩家控制器和攝像機飛行模式,可以在運行模式中用來探索場景 。區域體積:基於體積的系統驅動的大氣散射效果、陽光和風力屬性。自定義大氣散射效果。為程序化風動畫製作的自定義頂點著色器,應用在所有的植被上。項目特有的光照著色器自定義內容。
  • Unity Shader屏幕特效之馬賽克(Mosaic)材質
    "white" {}     _MosaicSize("MosaicSize", int)=5 } 然後聲明一個內置四元數變量_MainTex_TexelSize,這個變量的從字面意思是主貼圖_MainTex的像素尺寸大小,是一個四元數,它的值為 Vector4(1 / width, 1 / height, width, height);這個屬於unity
  • 【Unity Shader- UV動畫原理及簡易實現
    下圖是 Unity 內置的時間變量名稱類別作用_Timefloat4t 是從場景加載開始時經歷的時間,(t/20 , t , 2t , 3t)_SinTimefloat4t 是時間的正弦值,(t/8 , t/4 , t/2 ,t)_CosTimefloat4t 是時間的餘弦值,(t/8 , t/4 , t/2 ,t)unity_DeltaTimefloat4dt 是時間增量,(dt , 1/
  • Unity入門課|01讓世界暗下來
    ,比如Sphere,Cube,就可以從菜單直接新建一個對象默認的Material叫HDRP LitMaterial材質由哪些組件構成1 Shader 著色器,unity有shader graph連連看做shader也有shader程式語言來編寫shader2 各類texture 貼圖(非必須),用來顯示顏色的貼圖,像是穿了件衣服。
  • Unity中實現2D光照系統
    所涉及到的前置技術棧包括 Unity, C#, render pipeline, shader programming 等。而在圖形渲染中,通常通過模擬該過程,計算攝像機所接收到的來自物體反射的光,從而渲染出圖像。1986年,James T.
  • Unity URP中的深度depth用法全解
    演示基於Unity URP, shader用shader graph 或者HLSL
  • ...增加深度渲染管線、增加DirectLightMap全局光照貼圖等3D功能
    Camera設置depthTextureMode為Depth,可以在渲染流程中增加深度圖的渲染,貼圖的渲染結果存儲在Camera的u_CameraDepthTexture,開發者可以在shader中直接取到DepthTexture。Camera設置depthTextureMode為DepthNormals,可以在渲染流程中增加法線深度圖的渲染。
  • 在《英雄聯盟手遊》中,使用Unity實現的渲染技術與畫面
    unlit幾乎沒有計算量,兼容各種低端設備,早期手機遊戲常使用unlit來渲染模型。這也是《英雄聯盟》常被人詬病"就是個手機遊戲"的原因。不像《英雄聯盟》人物展示是一張圖片,他們都是用3D模型,所以對渲染要求較高。其中Dota2使用魔改BlinnPhong來渲染。
  • 實現unity級聯陰影的過渡和屏幕空間改善shadowmap漏光!
    實現unity 級聯陰影的過渡需求場景的shadowmap 精度勉強滿足場景物件的需求,但對於近距離角色的小掛件投影 衣服厚度 領子等投影精度是不足的。雖然獨佔的shadowmap可以實現,但為了不增加開銷我嘗試了用級聯陰影的最近1級做角色陰影。這樣操作很簡單不值得寫這篇內容,但這樣做需要解決2個級聯接縫問題。
  • Unity3D 2017
    3、點擊Next。6、點擊Browse更改安裝路徑,建議安裝在除C盤以外的其它磁碟,可以在D盤或者其它磁碟創建一個unity2017文件夾,然後點擊Next。11、雙擊打開D盤中unity2017文件夾。
  • 程序丨Unity大牛姚霄凌:Unity 5.6+版本中GPU Instance研發實操
    aabb你們開發者可以知道,你們可以把這個包圍盒告訴unity,然後可以做一個很簡單的camera的視錐剔除。它是需要API去支持的,所以需要你跑在D3D11以上。包括openGL4.3是不支持的,然後安卓的話需要GLES3.1。我相信一年半年以後就可以了,然後IOS Metal應該是支持的。
  • UNITY-Fungus學習(上)
    (百度摘抄)UNITY的安裝和使用首先進入unity中國的官網點擊下載unityunity裡面有許多功能,比如學習,社群之類的。不過我們點擊新建。unity可是製作2d和3d的遊戲。不過我們選擇2d的。起一個好聽一點的名字。確定儲存的位置。點擊創建經過一段時間的加載,出現了這個
  • LayaAir 2.10新特性:可動態修改渲染管線、增加深度渲染管線、增加...
    Camera設置depthTextureMode為Depth,可以在渲染流程中增加深度圖的渲染,貼圖的渲染結果存儲在Camera的u_CameraDepthTexture,開發者可以在shader中直接取到DepthTexture。Camera設置depthTextureMode為DepthNormals,可以在渲染流程中增加法線深度圖的渲染。
  • 請收下這份Unity交互黑科技大禮包
    例如要編寫shader時,不需要學習shader程序語言,在package manager中下載Render - pipliines.light安裝包即可使用可視化編輯界面製作著色器shader。在製作特效時,可以在package manager中下載visual effect graphics進行粒子特效的製作。
  • WebGL 手擼 3d 賀卡+小草飄動濾鏡
    前言這兩天接到一個項目,是有關全屏視頻的,整個項目中分到我這兒最主要的部分就是結束頁要求 3d 賀卡展示,正巧和前幾天 NingBo 童鞋分享的一樣
  • Unity中Animator做UI動畫的一些細節
    由於我之前經歷的項目,動畫使用的要麼是舊版的Legacy Animation(https://docs.unity3d.com/Manual/Animations.html),要麼是還在試用階段的Playable Graph +Animation Job(https://blogs.unity3d.com/2018/08/27/animation-c-jobs/)。