寫shader現在一般在u3d引擎上寫,其實shader在max,maya也是可以隨便寫,問題是要建立合適的環境,預設是不開啟的。這次使用是dx11標準shader,hlsl格式,事實上,u3d新版本的urp也是這種語言寫成,垃圾的cg已經13年後不更新,也不支援dx12,事實上這幾年,顯示卡兩廠都是擠牙膏,我13年的電腦還是玩遊戲,完全不覺得有多卡,0708年之時多強大,一年一個天與地,今年3090顯示卡,ati有大動作,連蘋果都出m1了,看來x86需要放棄了。
三維軟體
前作說明一下:
1。在上面寫shader沒有像u3d那樣,大量的宏直接用,很多時候要寫很多程式碼才能執行
2。事實上有專門寫shader的工具,只有用cg語言,而且多年不更新,就是fx,maya max也支援,就是那個連連看的shader
3。現在的發展的方向是連連看式,根連線,連根線,線連根,反正就不用程式碼,後面我來提到的
4。無法直接使用_time這個方法,後面會說,用動畫代替_time
5。線性環境用maya,珈瑪2。2用max
第一步設環境:
maya如下:
以2018為例,基本原理:使用
直接點選左上角圖示
hypershade渲染實時材質
步驟如下:1。開啟dx11shader 2。(小圖示)開啟hypershade 3。在模型上連上材質
其實效果還是不太對,由於線性與珈瑪有點不對齊,max就直接對齊2。2的珈瑪校正。
3dsmax如下:
以2016為例
原理:開啟slate材質編輯器,使用hlsl檔案寫材質
步驟如下:1。開啟驅動程式dx11 2。(按下m)開啟slate材質編輯器(經典材質編輯也行)3。連上材質
下面的程式碼部分,將兩個 hlsl(實際用。fx,語法是hlsl標準)寫在一起,平時開發時,少寫在一起因為很容易出錯
/*********************************************************************NVMH3****
$Revision$
Copyright NVIDIA Corporation 2007
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE。 IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS
BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY
LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES。
To learn more about shading, shaders, and to bounce ideas off other shader
authors and users, visit the NVIDIA Shader Library Forums at:
http://developer。nvidia。com/forums/
******************************************************************************/
#ifndef _MAYA_
#define _3DSMAX_
#endif
float
Time
<
string
UIWidget
=
“slider”
;
float
UIMin
=
-
1000。0
;
float
UIMax
=
1000。0
;
float
UIStep
=
0。03
;
string
UIName
=
“時間”
;
>
=
1
;
bool
mainTexBool
<
string
UIName
=
“主貼圖開關”
;
>
=
true
;
bool
matCapMapBool
<
string
UIName
=
“matCapMap開關”
;
>
=
true
;
bool
fresnelBool
<
string
UIName
=
“僅菲涅爾”
;
>
=
true
;
bool
showNormalBool
<
string
UIName
=
“只顯示法線”
;
>
=
true
;
bool
onlyMainTexBool
<
string
UIName
=
“僅主貼圖”
;
>
=
true
;
float4
OutLineColor
<
string
UIName
=
“描邊顏色”
;
>
=
{
1。0f
,
0。0f
,
0。0f
,
1。0f
};
float
OutlineSize
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。001
;
float
UIMax
=
1
;
float
UIStep
=
0。001
;
string
UIName
=
“描邊寬度”
;
>
=
0。08
;
float4
DiffuseColor
:
Diffuse
<
string
UIName
=
“主顏色”
;
>
=
{
1。0f
,
1。0f
,
1。0f
,
1。0f
};
float4
FresnelColor
<
string
UIName
=
“菲涅爾色”
;
>
=
{
1。0f
,
1。0f
,
1。0f
,
1。0f
};
float
BringLight
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。0001
;
float
UIMax
=
3
;
float
UIStep
=
0。01
;
string
UIName
=
“主貼圖亮度”
;
>
=
1
;
float
fresnelVal
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。5
;
float
UIMax
=
1。5
;
float
UIStep
=
0。1
;
string
UIName
=
“菲涅爾強度”
;
>
=
1
;
float
fresnelPower
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。0001
;
float
UIMax
=
15
;
float
UIStep
=
0。1
;
string
UIName
=
“菲涅爾亮度”
;
>
=
3。5
;
float
Bump
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。0
;
float
UIMax
=
2。0
;
float
UIStep
=
0。01
;
string
UIName
=
“法線強度”
;
>
=
1。0
;
float
ScreenUV_Scale
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。00001
;
float
UIMax
=
8。0
;
float
UIStep
=
0。05
;
string
UIName
=
“內部UV縮放”
;
>
=
1
;
float
Alpha
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。0
;
float
UIMax
=
0。25
;
float
UIStep
=
0。01
;
string
UIName
=
“通透度”
;
>
=
0。1
;
float
ScreenUV_Offset
<
string
UIWidget
=
“slider”
;
float
UIMin
=
0。0
;
float
UIMax
=
1
;
float
UIStep
=
0。01
;
string
UIName
=
“偏移值”
;
>
=
0。89
;
//// UN-TWEAKABLES - AUTOMATICALLY-TRACKED TRANSFORMS ////////////////
float4x4
WorldITXf
:
WorldInverseTranspose
<
string
UIWidget
=
“None”
;
>
;
float4x4
WvpXf
:
WorldViewProjection
<
string
UIWidget
=
“None”
;
>
;
float4x4
WorldXf
:
World
<
string
UIWidget
=
“None”
;
>
;
float4x4
ViewIXf
:
ViewInverse
<
string
UIWidget
=
“None”
;
>
;
float4x4
VXf
:
View
<
string
UIWidget
=
“None”
;
>
;
//// TWEAKABLE PARAMETERS ////////////////////
//////// SAMPLER & TEXTURE /////////////////////
Texture2D
<
float4
>
diffuseMap
:
DiffuseMap
<
string
name
=
“default_color。dds”
;
string
UIName
=
“主貼圖”
;
string
ResourceType
=
“2D”
;
>
;
Texture2D
<
float4
>
g_NormalTexture
<
string
UIName
=
“法線圖”
;
string
ResourceType
=
“2D”
;
>
;
Texture2D
<
float4
>
matCapMap
<
string
UIName
=
“MatCap 圖”
;
string
ResourceType
=
“2D”
;
>
;
Texture2D
<
float4
>
CutMap
<
string
UIName
=
“分層貼圖”
;
string
ResourceType
=
“2D”
;
>
;
//////////////////////////////
SamplerState
CutMapSampler
{
FILTER
=
MIN_MAG_MIP_POINT
;
AddressU
=
Wrap
;
AddressV
=
Wrap
;
AddressW
=
Wrap
;
};
SamplerState
MatCapMapSampler
{
FILTER
=
ANISOTROPIC
;
AddressU
=
Clamp
;
AddressV
=
Clamp
;
AddressW
=
Clamp
;
};
SamplerState
g_NormalSampler
{
FILTER
=
ANISOTROPIC
;
AddressU
=
Clamp
;
AddressV
=
Clamp
;
AddressW
=
Clamp
;
};
SamplerState
diffuseMapSampler
{
FILTER
=
ANISOTROPIC
;
AddressU
=
Clamp
;
AddressV
=
Clamp
;
AddressW
=
Clamp
;
};
//////////////////////////////////
// shared shadow mapping supported in Cg version
//////// CONNECTOR DATA STRUCTURES ///////////
/* data from application vertex buffer */
struct
appdata
{
float3
Position
:
POSITION
;
float2
UV
:
TEXCOORD0
;
float3
Normal
:
NORMAL
;
float3
Tangent
:
TANGENT0
;
float3
Binormal
:
BINORMAL0
;
};
/* data passed from vertex shader to pixel shader */
struct
vertexOutput
{
float4
HPosition
:
POSITION
;
float2
UV
:
TEXCOORD0
;
// The following values are passed in “World” coordinates since
// it tends to be the most flexible and easy for handling
// reflections, sky lighting, and other “global” effects。
float3
WorldNormal
:
TEXCOORD2
;
float3
WorldTangent
:
TEXCOORD3
;
float3
WorldBinormal
:
TEXCOORD4
;
float3
WorldView
:
TEXCOORD5
;
float2
ScreenUV
:
TEXCOORD6
;
};
///////// OULINE VERTEX AND PIXEL SHADING /////////////////////
vertexOutput
v_line
(
appdata
In
)
{
vertexOutput
Out
=
(
vertexOutput
)
0
;
#
ifdef
_MAYA_
Out
。
UV
=
float2
(
In
。
UV
。
x
,(
1。0
-
In
。
UV
。
y
));
#else
Out
。
UV
=
In
。
UV
。
xy
;
#endif
float
dist
=
distance
(
ViewIXf
[
3
]。
xyz
,
mul
((
float3x3
)
WorldXf
,
In
。
Position
。
xyz
))
*
0。01
;
Out
。
HPosition
=
mul
(
float4
(
In
。
Position
。
xyz
+
In
。
Normal
。
xyz
*
OutlineSize
*
dist
,
1
),
WvpXf
);
return
Out
;
}
float4
f_line
(
vertexOutput
In
)
:
COLOR
{
float4
ColorTexture
=
diffuseMap
。
Sample
(
diffuseMapSampler
,
In
。
UV
。
xy
);
float4
color
=
float4
(
OutLineColor
。
rgb
,
1
)
*
ColorTexture
*
1。5
;
color
。
a
=
1
;
return
color
;
}
///////// BASE VERTEX SHADING /////////////////////
/*********** Generic Vertex Shader ******/
vertexOutput
std_VS
(
appdata
IN
)
{
vertexOutput
OUT
=
(
vertexOutput
)
0
;
OUT
。
WorldNormal
=
mul
(
IN
。
Normal
,(
float3x3
)
WorldITXf
)。
xyz
;
OUT
。
WorldTangent
=
mul
(
IN
。
Tangent
,(
float3x3
)
WorldITXf
)。
xyz
;
OUT
。
WorldBinormal
=
mul
(
IN
。
Binormal
,(
float3x3
)
WorldITXf
)。
xyz
;
float4
Po
=
float4
(
IN
。
Position
。
xyz
,
1
);
float3
Pw
=
mul
(
Po
。
xyz
,(
float3x3
)
WorldXf
)。
xyz
;
float3
SUV
=
mul
(
IN
。
Position
。
xyz
,
(
float3x3
)
VXf
);
#ifdef _MAYA_
OUT
。
UV
=
float2
(
IN
。
UV
。
x
,(
1。0
-
IN
。
UV
。
y
));
OUT
。
ScreenUV
=
SUV
。
xy
*
ScreenUV_Scale
;
#else
OUT
。
UV
=
IN
。
UV
。
xy
;
OUT
。
ScreenUV
=
SUV
。
xy
*
0。01
*
ScreenUV_Scale
;
#endif
OUT
。
WorldView
=
normalize
(
ViewIXf
[
3
]。
xyz
-
Pw
);
OUT
。
HPosition
=
mul
(
Po
,
WvpXf
);
return
OUT
;
}
///////// BASE PIXEL SHADING //////////////////////
// Utility function for blinn shading
inline
float4
UV_Funct
(
SamplerState
inputSampler
,
Texture2D
<
float4
>
inputTex
,
float2
UV
)
{
float4
Color
=
inputTex
。
Sample
(
inputSampler
,
UV
);
#ifdef _MAYA_
Color
=
pow
(
Color
,
2。2
);
#endif
Color
。
a
=
1
;
return
Color
;
}
float4
std_PS
(
vertexOutput
IN
)
:
COLOR
{
///////// FOUR VARIABLE //////////////////////
float3
Vn
=
normalize
(
IN
。
WorldView
);
float3
Nn
=
normalize
(
IN
。
WorldNormal
);
float3
Tn
=
normalize
(
IN
。
WorldTangent
);
float3
Bn
=
normalize
(
IN
。
WorldBinormal
);
float3
Normal
=
g_NormalTexture
。
Sample
(
g_NormalSampler
,
IN
。
UV
)。
rgb
*
2。0
-
1。0
;
Normal
。
xy
*=
Bump
;
//法線無需要轉換pow 2。2
float3x3
rotation
=
float3x3
(
Tn
,
Bn
,
Nn
);
Normal
=
normalize
(
mul
(
Normal
,
rotation
));
float3
V
=
Vn
;
float4
mainCol
=
UV_Funct
(
diffuseMapSampler
,
diffuseMap
,
IN
。
UV
);
float4
ColorTexture
=
lerp
(
half4
(
1
,
1
,
1
,
1
),
mainCol
*
DiffuseColor
*
BringLight
,
mainTexBool
)
;
///////// MATCAP //////////////////////
half3
r
=
reflect
(
Vn
,
Nn
);
#ifdef _3DSMAX_
r
。
xyz
=
r
。
xzy
;
#endif
float
m
=
2。
*
sqrt
(
pow
(
r
。
x
,
2。
)
+
pow
(
r
。
y
,
2。
)
+
pow
(
r
。
z
+
1。
,
2。
)
);
half2
vN
=
r
。
xy
/
m
+
。5
;
float4
matCapCol
=
UV_Funct
(
MatCapMapSampler
,
matCapMap
,
vN
);
matCapCol
=
saturate
(
matCapCol
);
half4
base
=
lerp
(
half4
(
1
,
1
,
1
,
1
),
matCapCol
,
matCapMapBool
);
///////// END MATCAP //////////////////////
float
NdotV
=
dot
(
Normal
,
V
);
half
rgbMax
=
max
(
mainCol
。
r
,
max
(
mainCol
。
g
,
mainCol
。
b
));
float4
cutMapCol
=
CutMap
。
Sample
(
CutMapSampler
,
IN
。
UV
);
float
offset
=
lerp
(
NdotV
,
1
,
ScreenUV_Offset
);
float2
MovUV
=
IN
。
ScreenUV
*
offset
-
float2
(
0
,
Time
);
float4
_cutMapCol
=
CutMap
。
Sample
(
CutMapSampler
,
MovUV
);
float2
Ramp_UV
=
float2
((((
NdotV
*
NdotV
)
*
_cutMapCol
。
b
)
+
(
1。0
-
max
(
0
,
NdotV
))),
0。0
);
float4
Ramp_val
=
CutMap
。
Sample
(
CutMapSampler
,
Ramp_UV
);
float
RampVal
=
Ramp_val
。
r
;
float3
F_Color
=
FresnelColor
。
rgb
*
RampVal
*
fresnelPower
;
//得到主貼圖+菲涅爾效果
half4
Color
=
float4
(
F_Color
*
ColorTexture
。
rgb
,
1
);
Color
=
max
(
Color
,
Alpha
);
//得到主貼圖與混合效果的最終效果
Color
=
lerp
(
ColorTexture
,
Color
,
saturate
(
cutMapCol
。
g
*
rgbMax
*
fresnelVal
));
//靈魂材質去除matMat
Color
。
rgb
=
lerp
(
Color
。
rgb
*
base
。
rgb
,
Color
。
rgb
,
cutMapCol
。
g
);
if
(
fresnelBool
)
{
Color
。
rgb
=
F_Color
;
}
if
(
showNormalBool
)
{
Color
。
rgb
=
Normal
;
}
if
(
onlyMainTexBool
)
{
Color
=
mainCol
;
}
Color
。
a
=
1
;
return
Color
;
}
///// TECHNIQUES /////////////////////////////
RasterizerState
Rasterizer_Base
{
#ifdef _MAYA_
CullMode
=
FRONT
;
#else
CullMode
=
BACK
;
#endif
};
RasterizerState
Rasterizer_Outline
{
#ifdef _MAYA_
CullMode
=
BACK
;
#else
CullMode
=
FRONT
;
#endif
};
DepthStencilState
DepthEnabling
{
DepthEnable
=
TRUE
;
};
BlendState
DisableBlend
{
BlendEnable
[
0
]
=
true
;
};
technique11
Main11
<
string
Script
=
“Pass=p0;Pass=p1;”
;
>
{
pass
p0
<
string
Script
=
“Draw=geometry;”
;
>
{
SetVertexShader
(
CompileShader
(
vs_5_0
,
v_line
()));
SetGeometryShader
(
NULL
);
SetPixelShader
(
CompileShader
(
ps_5_0
,
f_line
()));
SetRasterizerState
(
Rasterizer_Outline
);
//SetDepthStencilState(DepthEnabling, 0);
//SetBlendState(DisableBlend, float4( 0。0f, 0。0f, 0。0f, 0。0f ), 0xFFFFFFFF);
}
pass
p1
<
string
Script
=
“Draw=geometry;”
;
>
{
SetVertexShader
(
CompileShader
(
vs_5_0
,
std_VS
()));
SetGeometryShader
(
NULL
);
SetPixelShader
(
CompileShader
(
ps_5_0
,
std_PS
()));
SetRasterizerState
(
Rasterizer_Base
);
//SetDepthStencilState(DepthEnabling, 1);
//SetBlendState(DisableBlend, float4( 0。0f, 0。0f, 0。0f, 0。0f ), 0xFFFFFFFF);
}
}
/////////////////////////////////////// eof //
/*
//法線方法
//方法1
float3 bump = Bump * (g_NormalTexture。Sample(g_NormalSampler, IN。UV)。rgb - float3(0。5,0。5,0。5));
Nn = Nn + bump。x*Tn + bump。y*Bn;
Nn = normalize(Nn);
//方法2
float4 bumpNormal = (2 * (g_NormalTexture。Sample(g_NormalSampler, IN。UV)-0。5)) * 1。5;
float3 N = bumpNormal。xyz;
N = normalize(N);
//方法3 (暫用)
float3 normal = tex2D(normalMapSampler, In。texCoord)。xyz * 2。0 - 1。0;
*/
/*
//菲涅爾效果
half fresnel =pow( NdotV,fresnelVal);
fresnel=1+fresnelPower*(1-saturate(fresnel));
float4 Fresnel_Color=float4(FresnelColor*fresnel,1);
Fresnel_Color=lerp(float4(1,1,1,1),Fresnel_Color,cutMapCol。g);
*/
其他開發中發現
:
1。fx檔案,設定宏的方法:
#ifndef _MAYA_
#define _3DSMAX_
#endif
2。由於maya與 max很多時候是yz軸反向。
3。maya與max設定的單位也是不同步,很多時候需要放大或者縮小100倍
下面說一下
_time.y
怎樣做:
使用動畫方式來做,相當於u3d執行,時間不斷向前
先說maya使用海洋的shader,再選出時間,老實說,我沒有找到好的方式,雖然山寨了點,能用。
左邊的海洋shader,右邊的比例轉換用0。00005
再說max,使用公式
新增浮點指令碼,寫f*0。005就行了
最後說一下,以後的發展,必定是連連看式
max如下:
maya如下: