This content is a brief summary of part of the mobile MMORPG development process from 2018 to early 2019.



Passcode : Asking to JP.Lee

How to enable two-sided rendering in Substance Designer?

如何在 Substance Designer 中启用两侧渲染?

How can I enable Two side rendering in Substance designer?

Yesterday I was asked a question by a colleague of mine I worked with before.

My old colleague was able to figure it out on his own.

Anyway, here are a few things to clear up.

If you’re not a student or a TA, is this really annoying?

Check out the reference links for learning.






Shader API | Substance 3D Painter (adobe.com)

This is a link to the API documentation for writing shaders in Substance Painter.

In the documentation, you will find a State section.

这是在 Substance Painter 中编写着色器的 API 文档的链接。

在文档中,您会找到一个 State 部分,例如.

Let’s check inside the file.让我们检查一下文件内部。

Here is an example state for Backface culling.

The above API is the Substance Painter Shader API.

Now, check if you can refer to the above API document.


上面的 API 是 Substance Painter Shader API。

现在,检查您是否可以参考上述 API 文档。

C:\Program Files\Adobe\Adobe Substance 3D Designer\resources\view3d\shaders

There is a shader file in SD in the location.

SD defines shader properties and states in XML format.

This file is usually saved as a file called .glslfx.

Open the above shader location with Open Folder in Sublime Text and search for the cull_off state keyword.


SD 以 XML 格式定义着色器属性和状态。

该文件通常保存为名为 .glslfx 的文件。

使用 Open Folder in Sublime Text 打开上述着色器位置,然后搜索 cull_off 状态关键字。

<?xml version="1.0" encoding="UTF-8"?>
<glslfx version="1.0.0" author="Adobe" label="Metallic Roughness">
    <!-- TECHNIQUES -->
    <technique name="Tessellation" label="Tesselation + Displacement">
        <!-- PROPERTIES -->
        <property name="blend_enabled"     value="true"/>
        <property name="blend_func"        value="src_alpha,one_minus_src_alpha"/>
        <property name="cull_face_enabled" value="true"/>
        <property name="cull_face_mode"    value="back"/>

        <!-- SHADERS -->
        <shader type="vertex"       filename="common/tessellation/vs.glsl" primitiveType="patch3"/>
        <shader type="tess_control" filename="common/tessellation/tcs.glsl"/>
        <shader type="tess_eval"    filename="common/tessellation/tes.glsl"/>
        <shader type="fragment"     filename="physically_metallic_roughness/fs.glsl"/>

        <!-- UNIFORMS -->
        <uniform name="parallax_mode"       guiName="Parallax Mode" min="1" max="1" />
        <uniform name="tessellationFactor"		guiGroup="Height"       guiName="Tessellation Factor"	default="4"   min="1" max="64" guiMin="1" guiMax="16" guiStep="1"   guiWidget="slider"/>
        <uniform name="scalarZeroValue"			guiGroup="Height"       guiName="Scalar Zero Value"		default="0.5" min="0" max="1"  guiMin="0" guiMax="1"  guiStep="0.1" guiWidget="slider"/>		

        <uniform name="usePhongTessellation"    guiGroup="Height"  guiName="Phong Tessellation"         default="false"      guiWidget="checkbox" />
        <uniform name="phongTessellationFactor" guiGroup="Height"  guiName="Phong Tessellation Factor"  default="0.6" min="0.0" max="1.0" guiMin="0.0" guiMax="1.0" guiStep="0.05" guiWidget="slider"/>
    <technique name="Parallax Occlusion" label="Parallax Occlusion">
        <!-- PROPERTIES -->
        <property name="blend_enabled"     value="true"/>
        <property name="blend_func"        value="src_alpha,one_minus_src_alpha"/>
        <property name="cull_face_enabled" value="true"/>
        <property name="cull_face_mode"    value="back"/>

        <!-- SHADERS -->
        <shader type="vertex"   filename="common/parallax/vs.glsl"/>
        <shader type="fragment" filename="physically_metallic_roughness/fs.glsl"/>

        <!-- UNIFORMS -->
        <uniform name="parallax_mode" guiName="Parallax Mode"         min="0" max="0" />

You will find this XML code block. Copy one original glsl fx file and rename it. I created another file with this name.

您将找到此 XML 代码块。 复制一个原始的 glsl fx 文件并重命名。 我用这个名字创建了另一个文件。


Then you need to change <glslfx version=”1.0.0″ author=”Adobe” label=”Metallic Roughness”> to <glslfx version=”1.0.0″ author=”Adobe” label=”Metallic Roughness TwoSide”> . This part is used as the name of the shader list in the UI.

Then change <property name=”cull_face_enabled” value=”true”/> to <property name=”cull_face_enabled” value=”false”/> .

然后您需要将 <glslfx version=”1.0.0″ author=”Adobe” label=”Metallic Roughness”> 更改为 <glslfx version=”1.0.0″ author=”Adobe” label=”Metallic Roughness TwoSide”> 。 这部分用作 UI 中着色器列表的名称。

然后将 <property name=”cull_face_enabled” value=”true”/> 更改为 <property name=”cull_face_enabled” value=”false”/> 。

<?xml version="1.0" encoding="UTF-8"?>
<glslfx version="1.0.0" author="Adobe" label="Metallic Roughness TwoSide">
    <!-- TECHNIQUES -->
    <technique name="Tessellation" label="Tesselation + Displacement">
        <!-- PROPERTIES -->
        <property name="blend_enabled"     value="true"/>
        <property name="blend_func"        value="src_alpha,one_minus_src_alpha"/>
        <property name="cull_face_enabled" value="false"/>
        <property name="cull_face_mode"    value="back"/>

        <!-- SHADERS -->
        <shader type="vertex"       filename="common/tessellation/vs.glsl" primitiveType="patch3"/>
        <shader type="tess_control" filename="common/tessellation/tcs.glsl"/>
        <shader type="tess_eval"    filename="common/tessellation/tes.glsl"/>
        <shader type="fragment"     filename="physically_metallic_roughness/fs.glsl"/>

        <!-- UNIFORMS -->
        <uniform name="parallax_mode"       guiName="Parallax Mode" min="1" max="1" />
        <uniform name="tessellationFactor"		guiGroup="Height"       guiName="Tessellation Factor"	default="4"   min="1" max="64" guiMin="1" guiMax="16" guiStep="1"   guiWidget="slider"/>
        <uniform name="scalarZeroValue"			guiGroup="Height"       guiName="Scalar Zero Value"		default="0.5" min="0" max="1"  guiMin="0" guiMax="1"  guiStep="0.1" guiWidget="slider"/>		

        <uniform name="usePhongTessellation"    guiGroup="Height"  guiName="Phong Tessellation"         default="false"      guiWidget="checkbox" />
        <uniform name="phongTessellationFactor" guiGroup="Height"  guiName="Phong Tessellation Factor"  default="0.6" min="0.0" max="1.0" guiMin="0.0" guiMax="1.0" guiStep="0.05" guiWidget="slider"/>
    <technique name="Parallax Occlusion" label="Parallax Occlusion">
        <!-- PROPERTIES -->
        <property name="blend_enabled"     value="true"/>
        <property name="blend_func"        value="src_alpha,one_minus_src_alpha"/>
        <property name="cull_face_enabled" value="false"/>
        <property name="cull_face_mode"    value="back"/>

        <!-- SHADERS -->
        <shader type="vertex"   filename="common/parallax/vs.glsl"/>
        <shader type="fragment" filename="physically_metallic_roughness/fs.glsl"/>

        <!-- UNIFORMS -->
        <uniform name="parallax_mode" guiName="Parallax Mode"         min="0" max="0" />

If you turn off the Substance designer and rerun it, it will be applied as shown below.

In older versions, you could update a modified shader by pressing Crtl + R.

Lately, I’ve been applying auto-corrected shader compilation (It used to be really uncomfortable.)

如果您关闭 Substance 设计器并重新运行它,它将按如下所示应用。

在旧版本中,您可以通过按 Crtl + R 来更新修改后的着色器。

最近,我一直在应用自动更正的着色器编译(以前真的很不舒服。) Properties
Allow to set up some part of the OpenGL state.

XML Element Definition:
	- Name: 'property'
	- Attributes:
		- 'name': The name of the property to set. The name are based on the OpenGL function or glEnum name:
			- enum:
				- without the 'GL_' prefix, in lower case.
				- Ex:
					glEnable(GL_BLEND_ENABLE) => "<property name="blend_enabled" value="true"/>"
					glDisable(GL_CULL_FACE) => "<property name="cull_face_enabled" value="false"/>"
			- functions:
				- without the 'gl' prefix, in lower case and with all words separated with '_' character.
				- Ex:
					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) => "<property name="blend_func" value="src_alpha,one_minus_src_alpha"/>"
					'value': The value of the property
			- Allowed properties are:
				| 'name' values		| 'value' values			| Description 											|
				| blend_enabled		| boolean 					| Enable/disable the blending mode 						|
				| 					| true 						| 														|
				| 					| false 					| 														|
				| blend_func		| string, string			| Set the sources and destination blending functions	|
				| 					| zero						| for OpenGL enum GL_ZERO								|
				| 					| one						| for OpenGL enum GL_ONE								|
				| 					| src_color					| for OpenGL enum GL_SRC_COLOR							|
				| 					| one_minus_src_color 		| for OpenGL enum GL_ONE_MINUS_SRC_COLOR				|
				| 					| dst_color					| for OpenGL enum GL_DST_COLOR							|
				| 					| one_minus_dst_color		| for OpenGL enum GL_ONE_MINUS_DST_COLOR				|
			 	| 					| src_alpha					| for OpenGL enum GL_SRC_ALPHA							|
			 	| 					| one_minus_src_alpha 		| for OpenGL enum GL_ONE_MINUS_SRC_ALPHA				|
				| 					| dst_alpha					| for OpenGL enum GL_DST_ALPHA							|
			 	|					| one_minus_dst_alpha		| for OpenGL enum GL_ONE_MINUS_DST_ALPHA				|
				| 					| constant_color			| for OpenGL enum GL_CONSTANT_COLOR						|
				| 					| one_minus_constant_color	| for OpenGL enum GL_ONE_MINUS_CONSTANT_COLOR			|
				| 					| constant_alpha			| for OpenGL enum GL_CONSTANT_ALPHA						|
			 	| 					| one_minus_constant_alpha	| for OpenGL enum GL_ONE_MINUS_CONSTANT_ALPHA			|
			 	| 					| src_alpha_saturate		| for OpenGL enum GL_SRC_ALPHA_SATURATE					|
			 	| 					| src1_color				| for OpenGL enum GL_SRC1_COLOR							|
				| 				 	| one_minus_src1_color		| for OpenGL enum GL_ONE_MINUS_SRC1_COLOR				|
				|					| src1_alpha				| for OpenGL enum GL_SRC1_ALPHA							|
				| 					| one_minus_src1_alpha		| for OpenGL enum GL_ONE_MINUS_SRC1_ALPHA				|
				| blend_equation	| string					| Set the Blend Equation 								|
				| 					| func_add					| for OpenGL enum GL_FUNC_ADD							|
				| 					| func_subtract				| for OpenGL enum GL_FUNC_SUBTRACT						|
				| 					| func_reverse_subtract		| for OpenGL enum GL_FUNC_REVERSE_SUBTRACT				|
				| 					| min						| for OpenGL enum GL_MIN								|
				| 					| max						| for OpenGL enum GL_MAX								|
				| cull_face_enabled	| boolean					| Enable/disable the face culling						|
			 	| 					| true						| 														|
				| 					| false						| 														|
			 	| cull_face_mode	| string					| Set the face culling mode								|
				| 					| front						| for OpenGL enum GL_FRONT								|
				| 					| back						| for OpenGL enum GL_BACK								|
				| 					| front_and_back			| for OpenGL enum GL_FRONT_AND_BACK						|
				| depth_test_enabled| boolean					| Enable/disable the depth test							|
			 	| 					| true						| 														|
				| 					| false						| 														|
				| depth_func		| string					| Set the depth compare function						|
				|					| never						| for OpenGL enum GL_NEVER								|
				|					| less						| for OpenGL enum GL_LESS								|
				|					| lequal					| for OpenGL enum GL_LEQUAL								|
				|					| equal						| for OpenGL enum GL_EQUAL								|
				|					| notequal					| for OpenGL enum GL_NOTEQUAL							|
				|					| gequal					| for OpenGL enum GL_GEQUAL								|
				|					| greater					| for OpenGL enum GL_GREATER							|
				|					| always					| for OpenGL enum GL_ALWAYS								|

If you look at the API Format normative book, you can see that it is bound as a property to use the gl function as it is.

To be precise, this would just mean turning off backface culling by removing Cull mode rather than Two Side vertex normal rendering.

Now that Backface Culling is applied, I apply a Two side normal sign to modify the rendering on the opposite side receiving the light to be rendered more correctly.

如果您查看 API 格式规范书,您可以看到它被绑定为一个属性,以按原样使用 gl 函数。



Navigate and modify the Shader path shown in the picture above. We will edit vs.glsl inside the tessellation folder.

导航并修改上图所示的着色器路径。 我们将在 tessellation 文件夹中编辑 vs.glsl。

/////////////////////////////// Vertex shader
#version 330

in vec4 iVS_Position;
in vec4 iVS_Normal;
in vec2 iVS_UV;
in vec4 iVS_Tangent;
in vec4 iVS_Binormal;

out vec4 oVS_Normal;
out vec2 oVS_UV;
out vec4 oVS_Tangent;
out vec4 oVS_Binormal;

uniform mat4 viewInverseMatrix;

void main()
    gl_Position = iVS_Position;
    oVS_Normal = iVS_Normal;
    vec4 viewDir = normalize(viewInverseMatrix[3] - gl_Position);
    float normalSign = sign(dot(oVS_Normal, viewDir));
    oVS_Normal *= normalSign;
    oVS_UV = iVS_UV;
    oVS_Tangent = iVS_Tangent;
    oVS_Binormal = iVS_Binormal;

Modifying like above code.

Rendering when only back face culling is changed to false. (There is no distinction between lighting directions)仅背面剔除更改为 false 时的渲染。 (光照方向没有区别)

Apply NormalSign to differentiate the lighting direction and darken it. I took a simple look.

应用 NormalSign 来区分照明方向并使其变暗。 我简单看了一眼。编辑于刚刚

Iridescence Lit model improvement for URP

Iridescence Lit model improvement for URP

Iridescence based thin film.

Transparent refraction with distortion.

Preserved Physically correct pbr based.

Masking for decal printing.

More learning about this?

Check it my Patreon.



2018 in years my presentation of definition of stylized.

Written by JP.Lee
心动 Tech art team leader.

我是专门设计材质与Shader的韩国人 JP.Lee

今天想和大家分享Stylized game art 的主题




那么Stylized art的定义是什么呢?

在美术层面什么是Stylized texture ,Stylized
game art 到底是什么我们究竟知道吗?





年 ‘The
Great Soviet Dictionary’定义说 “包括线与形态的简化和空间和颜色的关系在内,使用多种多样的传统方法,将其视为人物和物体装饰的普通化。”表现的卓越风格。



‘程式化艺术’ 可以说从很远也可以看到的古代洞穴壁画的简单的视觉表现中开始的。


但是19世纪初,中期的‘印象派艺术’ 以学问衍生出来后












watch 。




为了做这样的模仿,有必要了解Over Watch美术组所理解的表面质感规格和块状感。













参考图片中要注意的部分是在大的体面部分做的折断,大的面完全转折了5 0度以上,有各种各样的折面。












这将把大家投入大量精力所做出来的Normal Map和细密质感都抹掉,甚至表现光泽的辅助贴图的一部分会看起来像杂点。





可以放 Vertex RGB上 ,Metallic 可以放
Vertex Alpha













material production。




map是很有用的,可以在Zbrush制作的整体造型后,在Substance painter或Designer中改变表面纹理。






粗糙度和 Metallic金属度显示材质属性的方法。





painter 与Photoshop使用类似的Layer层,工程构成的理解是比较难的。

一开始的时候Node Graph节点图表很生疏,但是过程追踪会很快很容易修正。


但是由于最近增加了与不同层级效果连接的功能,还没有追踪结果。特别是Smart Material智能材质的缺点是按照原本应用的时候方便,但是想要按照自己的意愿修改的话,需要理解整体结构,这需要相当的时间,这一点成为了问题。原本Smart Material开发的理由是,为了工作室内部制作规则的统一,将它保存成Smart Material来灵活使用。

像上面一样的制作工程Dota 2的开发也使用了。

这里重要的部分是利用模型的点信息算出Position方位图的信息,使用Mask遮罩World Space Normal 世界方向法线改变RGB数值,烘焙的灯光数值在内部制作用来作为照明效果,使用混合颜色的Mask遮罩。

另外Curvature曲线是在内部使用Normal map得到边角高亮或破损的效果来制作Stylized art风格化美术。

用方便的Multi Switch Node节点,提前制作几种结果,同时也使用了和美术总监一起讨论后的功能。





illumination或Spherical Harmonic技术层上的一面。

Advanced Skin Shader for Next-Gen Mobile games.


通常,移动游戏开发环境不常使用Normal Blur Sub-Surface技术的原因是,因为Normal纹理的Mip-Map需要使用DDX、DDY或Gaussian Blur进行实时Blur处理。

In order to check the demand of the internal art team, it is the process of extracting the mobile game character data of Netease and testing the internally developed Shader.
The left side is a shader using the Gaussian Blur method, mipmap-chain and Diffusion Profile, and the left side is produced by introducing an optimization formula from myself. Although there is a huge difference in instruction quantities, there is not a big difference visually in the mobile game environment.

When dealing with character rendering, you often hear a lot about SSS effects.
In general, the reason why mobile game development environments do not often use Normal Blur Sub-Surface technology is that the normal texture Mip-Map requires DDX, DDY or Gaussian Blur for real-time blur processing.
Now, the content will introduce the idea steps of preprocessing the real-time processing part.


Texture-Space SSS 或 Screen-Space SSS 的概念,目标是移动设备也可以使用的轻巧、近似的( approximated ) SSS 。

Code hint

假设使用如图6所示的内核模糊法线贴图( 假设 L 是 Directional-Light Vector )。 那么可以得到以下结果。

实际上,由于没有执行将内在结果剪除到零以下的过程 max( dot( N, L ), 0 ) , 所以不能说完全一样, 但是可以用于近似值。使用punctual光源(如点光源)时,每个像素的光源向量会有所不同,但由于模糊的周围像素,因此在使用它作为近似值时不会有困难。
所以,如果预先模糊法线向量并计算出 Diffuse Lighting,就能大致计算出 SSS 结果。此方法的主要优点是,可以再使用一张法线贴图,仅需要一次 dot( N, L ) 演算就可以计算近似 SSS 。 问题是 ” SSS 近似到哪种程度” 。

Suppose you want to Blur a normal map using the Normal kernel as shown above. For convenience, let’s assume that L is a Directional-Light Vector. This will give you the following result:

In fact, we didn’t do max (dot (N, L), 0), which truncates the inner product to zero or less, so it’s not exactly the same, but it’s a good approximation.
Using point lights, etc., the light vector at each pixel is different.
Therefore, if you calculate the Diffuse Lighting by blurring the normal vector in advance, you can approximate the SSS result to some extent. And the biggest advantage of this method is that we can approximate SSS at the cost of using one more normal texture and doing another dot (N, L) operation. The bottom line is “how close is the SSS?”Also, two normal textures were compressed into one texture.

由于美术们的倾向,没有做出正确的纹理信息,所以制作和提供Substance Designer的滤镜是一个很好的方法。需要导出的信息由Substance Designer存储为Sbsar,并在Substance Painter上应用。

The artist must output the textures that are appropriate for the shader structure.
Since the exact texture information was not created according to the artist’s inclination, it is a good idea to create and provide a filter with Substance Designer.The information to be printed is saved as Sbsar in Substance Designer so that it can be directly applied in Substance Painter.

Refer model copyright by Netease : Not my own work , shader dev work result are my own.
Left result used to Spherical Gaussian method and Right result it my normal cluster kernel method.
My method have 5X more faster on mobile even very closet final result from SG method.
Refer model copyright by Netease : Not my own work , shader dev work result are my own.

添加SKIN BRDF和Back Scatter的初版结果。
开发手机皮肤shader时,通常需要确保在OpenGL 2.X或更高版本中工作。
如果使用Energy Conservation Normalized Blinn-Phong,则OpenGL 2.0的行为也不受限制。此外,还应避免使用尚未在特定硬件上支持的DDX和DDY。

This is the primary output of SKIN BRDF and Back Scatter.
When developing a mobile skin shader, always work to ensure that it works with OpenGL 2.X and above.Energy Conservation Normalized Blinn-Phong also works with OpenGL 2.0 without restriction. Also avoid using DDX or DDY, which is not yet supported by certain hardware.

Skin Shading with ACES tone mapped test.(Mobile)

这是有点西洋风格的角色制作案例。阴影部分使用OPTIMIZED PCSS。
可以优化Iteration Sample count,使用3D Lookup将运算数降至最低,并且可用于角色选择窗口专用。

This is an example of making a Western character.
The shadow part uses OPTIMIZED PCSS.I am currently testing Penumbra Scatter for shadows.
Optimize the Iteration Sample count and use 3D Lookup to minimize the amount of calculation and use it for character selection window only.It is available only in a conversation window without using it in a real game.

根据色温和颜色表,shader实现必须多次重复。在上面的插图中,有一个皮肤Shader是根据PBR shader实现的,它使用Blinn-Phong,在完全低性能的智能手机上也可以跑,并且存在未使用任何BRDF纹理的皮肤Shader。

Shader implementations need to be repeated many times, based on color temperature and color palette.In the picture above, there are skin shaders based on PBR shaders, and there are skin shaders that use Blinn-Phong, which works perfectly on low-end smartphones, and do not use any BRDF textures.

Old version of Skin shading

Blinn-Phong based Skin shader since by 2013 in years.

Additional further works

Automatic skin material applies system.

Beck-mann NDF for the dual specular robe.

Related post


toon Shader Additional FX

Purpose of implementations

  • Simple transmittance FX for toony rendering.
  • mesh attribute based shade expression.
  • Bloom and tone-mapped for toony rendering look-development.

This character model from XRD game data not my own works.

左边是一般的Cartoon rendering。


虽然美术们认为Tone Mapping主要用于具有真实效果的渲染效果中,但是在最近制作的日本动画渲染技巧下,即使是2D,也往往会使用HDR的情况很多。根据这种趋势,使用Tone Mapping、Bloom和Exposure方法,会得到更有高级感的产物。

最近在日本动漫中甚至还出现了使用Reflection Mapping的情况。

Left is a typical Cartoon rendering.

The right side renders closer to the more recent Japanese animation tones the results are shown.

Most artists think that Tone Mapping is only used for realistic renderings, but even if you look at the recent Japanese animation rendering techniques, it is often 2D, but HDR is used. You can get a more luxurious result.In recent Japanese animations, reflection mapping may be used.

Light Transmitted scatter Shadow Color.

When the character is back-lit, the light is transmitted through the light direction and the depth value deliberately set.Light Transmitted scatter Shadow Color.


它被称为Light Space Outline,但仅仅使用贴图信息控制的话会缺乏空间感,因此追加实现。

From the direction the light comes in, the lighter outline becomes thicker and thinner toward the darker side.It’s called Light Space Outline, but it lacks the space to control texture information alone.

None light-space outline
light-space outline


Too flat cartoon shaders look a bit like an old technique, where N〮L and N〮V are transformed to capture information and finally modify the lighting model.Looking at the hair on the bright side, the volume was created, and the shadowed area was not too unobtrusive.

code block

This is a comparison of before and after.


Before and After

X2M mobile mmo rpg

整个世界的空间为32 Km X 32 Km
真实地形世界空间为16Km x 16Km

运行时包括Light Probe SH数据流时完全流式处理(内部开发)。

-VariableShadow,Distance ShadowMap(将视差阴影缓存视为纹理数组)

– 网格地形的自适应密度。
– 网格地形lod + HLOD。



Fully world space have 32Km X 32Km
Real terrain world space have 16Km x 16Km
Full streaming when runtime included LightProbe SH data streaming(Inhouse develop).

Near and far shadow treatment.
-VariableShadow, Distance ShadowMap (Considered Parallax Shadow cache as texture array)
-Shadow volume proxy mesh system.

Mesh Terrain.
-Adaptive density of mesh terrain.
-mesh terrain lod + HLOD.
-Displaced mesh decal for terrain surface detail system.(Mobile friendly system that I made)
-Anti-Tilled technique by Stochastic.

Detail Vista terrain.
-Pre baked Light stage data.
-Adaptive vista terrain mesh generation.
-Support to Time of day.
-Distance fadeout blending with real terrain texture sets.

-Infinite ocene surface by Perspective space culled surface mesh.
-Plane reflection system regardless of the height difference.

Tree and Foliege.

  • light space AO.
  • Fade-Angle for cross billboard look improvement.


Liked it? Take a seco

[Advanced]Anti-Tilled technique by Stochastic

以下包含对于Anti-Tilled technique 的技术理论上的内容.

Unity 基于技术内容创建技术演示。

Unity3D Engine.

World Machine for generation big terrain.

View distance blending for vista texture.

Stochastic anti-repeating visualization result.

Xrp Feature result.

Test type for Rocky Ground texture.

(Before : LEFT , After : Right)

Example of Unlit.

Grass field


此 Feature 使 ALU 数量增加近 15 个。
但是,此功能通常使用 LOD1 的 LOD2 着色器。
审查并应用整个 Velod。
对于地形,混合 4 张纹理的情况很常见,在某些情况下,有时混合到 7 或 8 张,但此功能仅在性能方面不是一大问题,因为它仅在 Vista map 的上一步运行,因此性能方面不是一大问题。

Vista-Map visual explaining demo preview.

1, Bake Light-Stage data into the BaseMap as Vista view texture.

2. Debug Tiling texture set to Layer0 texture phase.

3. Simply test via Vertex position depth fade through Camera near and far.

Only tested based on Unlit.
Vista map has used to pre-baked light-stage by Vray offline renderer basically.


Implemented refer to

Dual Specular IBL demonstration.


When I set up the lighting, I think I want to control the reflection expression of golden armor or metallic independently of the ambient light. By modifying the Specular IBL and Custom Specular IBL created from SkyIBL in the shader, you can understand how the material expression can be further enhanced.

라이팅 설정을 하다보면 황금 갑옷이나 메탈릭의 Reflection 표현을 환경광 독립적으로 제어 하고 싶다는 생각을 많이 합니다. SkyIBL 로 부터 생성 된 Specular IBL 과 Custom Specular IBL 을 셰이더에서 수정 하여 어떤 식으로 재질 표현을 더 상승 시킬 수 있는지 이해 할 수 있습니다.


See below for a link to the shader code used in this visualization.


Synopsis of Helinesia

*Cat god race

Eight cats that survived the first disaster gain mysterious powers to become eight heroes, and descendants prospered by them to form a civilization in land of Helynesia.


*8 cats (8 heroes) 8只猫(8位英雄)

Gionas + Remy (ancestor of the Glix family) (Glix家族的祖先)

Kai + Rotte (ancestor of the Reus family)(Reus家族的祖先)

Astrid + Avelia (ancestor of the Neinrad family)(Neinrad家族的祖先)

Kalis + Lilian (ancestor of the Mecklen family)(Mecklen家族的祖先)

Each family produces many derivative families, each of which grows into a tribe.

*4 tribes (Brun, Akun, Tejas, Avoel)4个部落(布鲁恩,阿克特,特哈斯,阿沃尔)

1. Melee warrior propensity for flesh system train (Brun section) / 近战战士对肉体系统的倾向(布鲁恩节)

The descendants of Gionas and Remy used mystical powers to develop their physical abilities, and their melee combat power was high. / 吉奥纳斯和雷米的后代利用神秘的力量来发展自己的身体能力,他们的近战战斗力很高。

2. The tendency to hide the flesh system fever (Akun section) / 隐藏肉体发烧的倾向(阿坤节)

They are the descendants of Kai and Rotte, and while developing their physical abilities was the same, they developed their skills to attack enemies through hiding and surprise./他们是Kai和Rotte的后裔,尽管他们的身体能力得到了发展,但他们却发展了通过躲藏和惊奇来攻击敌人的技能。

3. Spiritual attack magic propensity (Tehas section) / 精神攻击的魔法倾向(特哈斯节)

The descendants of Astrid and Avelia, a tribe that developed an offensive magic that can substantiate the mystical power, pure energy, using mental power. / 阿斯特里德(Astrid)和艾维利亚(Avelia)的后代,一个部落开发了一种进攻性魔法,可以利用智力来证实神秘的力量,即纯净的能量。

4. Spiritual Healing and Sub-Magic Orientation (Aboel section) / 精神疗愈和超魔术取向(Aboel部分)

The descendants of Kalis and Lilian, a tribe that has been developed so that they can be used to heal colleagues and protect groups, rather than using their mysterious powers for attacks. / 卡利斯(Kalis)和莉莲(Lilian)的后代已经发展起来,因此可以用来医治同事和保护团体,而不是利用他们的神秘力量进行攻击。

*Families of each tribe

After a long period of time from the 8 heroes, the 4 tribes flourished, and numerous families repeated creation and extinction, and only the important large families could continue their history.


-Brunn section- 棕色Brunn

@Glix section family @Glix斯节家庭

After hundreds of years, Gionas’ Glix family was divided into three main groups: Brabant, Glix, and Pross, and these three families were again divided into relatives, forming a tribe.

1. 글릭스家 : 지오나스의 직계이며, 3가문중 능력이 제일 강하다.

2. 브라반트家 : 최초 글릭스가에서 분파했으며 부족의 한축을 이룬다.

3. 프로스家 : 마찬가지로 글릭스가에서 분파한 가문

큰 3가문은 세월이 지나 또다시 여러줄기로 나뉘어진다.

글릭스계열 가문

1. 글릭스家

2. 에스쿠家

3. 루이사드家

브라반트계열 가문

1. 브라반트家

2. 플랜더家

3. 에르콜家

프로스계열 가문

1. 프로스家

2. 리엘란家


@네인라드계열 가문

아스트리드의 후손인 네인라드 가문의 분파

1. 네인라드家

2. 베스트로家

3. 콘라드家


1. 네인라드家

2. 페르트家


1. 베스트로家

2. 샤이아란家

3. 리드론家


1. 콘라드家

2. 홀란츠家

3. 위슬리어家

4. 태니커家


@메클랜계열 가문

칼리스와 릴리안의 후손들이며 많은 분파가문을 만든다.

1. 메클랜家

2. 버스타드家

3. 보나콜라家

4. 코르나家


1. 메클랜家

2. 고르돈家

3. 스트리어家

4. 캐러블家


1. 버스타드家

2. 브래타家


1. 보나콜라家

2. 스콘티家

3. 실메이니아家


1. 코르나家

2. 베르거家

* 4부족 외 부족


레우스家의 선조 카이와 네인라드家의 선조인 아벨리아 사이에서 태어난 자손의 후손인 이마넬 이란 인물에 의해 생겨난 집단.

정식부족으로 인정받지 못하고 헬리네시아 주변을 떠돌아다니며 성장한다.

사용하는 힘도 육체계열과 마법계열을 혼용하며, 마전사의 특징이 있다.

* 4부족의 대립

8영웅의 각 계파에서 발전된 4개 부족들은 자신들의 성향대로 신비한 힘을 발전시켜 갔고, 그 결과 힘의 사용에 있어서 견해 차이를 보이게 된다.

이러한 가운데 양쪽 계열의 적자 출신인 이마넬 이란 인물이 도화선이 되어 감정대립의 골이 깊어지고, 영역 권에 대한 갈등으로 증폭되게 되었다.

* 양 계열간의 갈등

육체계열 부족( 브룬, 아쿤 )과 영적계열 부족( 테하스, 아보엘 ) 간의 갈등이 점점 심화되어 가면서 영역 경계점에선 사소한 마찰이 종종 빚어지고, 각 부족의 수뇌를 이루던 부족장과 장로들은 급기야 자신들의 신념의 정당성을 주장하며 전쟁을 결심한다.

* 두 번의 큰 싸움

양측의 전쟁은 누가 이기고 진다고 할 것 없이 팽팽하게 지속되었고, 많은 희생자를 내며 소모전 양상을 보였다.

수년에 걸쳐 두 번의 큰 싸움을 겪고 나서야 이대로 가면 모두 공멸한다는 인식을 하게 되었다.

* 불안전한 화해

묘신족 들이 내부에서 갈등을 빚고 있는 사이 바이러스는 영역을 더욱 넓히고 있었고 몬스터들도 나날이 강력해져갔다.

여러 곳에서 불안한 징후가 발견되고, 헬리네시아 외곽이 몬스터들에게 습격 받는 일이 잦아지자, 위기의식을 느낀 묘신족 들은 제한적인 휴전을 합의한다.

* 연합마을 엘리아스

휴전을 하고 각 부족이 개별적으로 몬스터들과의 싸움을 시작했지만, 강대해진 몬스터들의 힘 앞에 무력했다.

아쿤 부족의 부족장 캐스터는 타부족장들과 장로들이 모인 자리에서 8영웅들의 전설 속에 전해 내려오는 신비한 힘의 원천 이였던 곳의 탐험을 제의한다.

그 곳에서 그동안 자신들이 잊고 지내던 순수한 힘을 다시금 얻어와 몬스터들과 맞서려는 의도였다.

계획은 성공적 이였고, 묘신족 들은 큰 힘을 얻을 수 있었다. 그리고 몬스터와의 전쟁에 최전선 기지를 세우기로 하고 접경지역에 엘리아스라는 부족연합마을을 건설한다.

* 종족통합의 희망

엘리아스 마을의 촌장 카알 네인라드는 종족의 분열과 갈등으로 인해 묘신족의 미래가 어둡자 모종의 계획을 세우기 시작한다.

우선 자신과는 대립 관계에 있지만 출중한 능력을 지닌 아쿤 부족장 캐스터를 설득하여 계획을 실행에 옮긴다.

촌장의 손자이자 네인라드家의 적통인 스콘 네인라드와 레우스家의 적통인 아쿤 부족장 캐스터의 조카 이즈 레우스, 글릭스家의 적통 로이 글릭스, 메클렌家의 적통인 나디아 메클렌.

각 부족에서 선발한 이들 4명을 어린 시절부터 같이 생활하게 하며 부족 간의 경계심을 푸는 것 이였다.

로이, 스콘, 이즈, 나디아, 넷은 아직 어리지만, 훌륭한 자질을 갖추고 있었고, 미래엔 각 종족의 지도자가 될 만한 아이들이였다.


모든 생명체들의 원천 에너지가 흘러 나오는 지역, 지구의 여러 곳에 존재하지만 가장 강한 힘이 발산되는 지역을 헬리네시아라고 부르고 있다.

헬리네시아는 인간들이 아직 범접하지 못한 울창한 원시림 속에 존재하며 인간들이 최초로 지구상에 출현했을 당시엔 다른 생명체들과 마찬가지로 신성한 지역으로 여겼으나 문명과 기술의 발전으로 자연을 바라보는 눈이 퇴화되며 인간들에겐 헬리네시아가 잊혀져 갔다.

그러한 이유로 인간들에겐 차원이 다른 공간이 되어 버렸으며 다른 생명체들만이 그 존재를 인식하고 있다.

헬리네시아 외에 비슷한 지역은 인간의 개발로 인해 많은 수가 없어졌고 견신족이 출현하게 되는 알하르츠계곡은 헬리네시아보단 적은 에너지가 흘러 나오는 지역이다.

흘러나오는 에너지의 형태는 음파, 자기장등과 같이 눈으로 식별 할 수 없으며 인간에겐 퇴화되어 버린 초자연적인 감각기관으로만 인지가 가능하다.

인간들은 자신들의 생명을 유지 시키기 위해 필수인 지구 본연의 에너지 임에도 인지를 할 수가 없어 개발이라는 명목 하에 에너지의 출구를 파괴하며 자신들의 문명을 발전 시켜가는 악순환을 반복했다.

헬리네시아의 초자연적인 힘

지구는 표면을 둘러싼 지표아래 중심부에 생명의 정기(핵)가 존재하며 그 중심부의 외곽으로 카오스상태의 선과 악이 공존하는 층으로 구성되어 있다.

카오스층은 지표면에서의 악의 기운을 정화시키고 가두어 놓는 임무를 담당하는 층이다.

이 층의 물질은 지표면으로 유출시 매우 위험하기 때문에 강력한 물질로 형성된 봉인체가 겉을 감싸고 있다.

이 봉인체의 곳곳엔 인간들의 에너지가 되는 석유가 포함되어 있으며, 석유가 모두 사라져 대공동이 형성된 곳에 카오스층의 물질이 유입이 된다.

카오스층의 물질이 지하의 큰 구멍 속에서 생화학반응으로 바이러스를 탄생시키게 되고 이 바이러스가 지구 전체를 뒤덮어 생명체들을 멸종시킨다.

바이러스가 지구의 표면을 거의 잠식했을 때, 헬리네시아는 그 신성함과 생명의 정기의 힘으로 바이러스의 침범을 막아 냈으며 생명체들에게 조그만 안전지역을 제공했다.

불완전하고 실체가 없던 힘을 지오스라는 고양이가 헬리네시아 중심부의 성스러운 나무 안에 있던 빛나는 물웅덩이에 들어가 한번 부활을 거친 후 묘신족으로 변신하게 된다.

지구의 생명에너지의 정수를 몸 안에 얻은 지오스는 다른 생존한 고양이들도 물에 들어가게 해 묘신족으로 탈바꿈 시킨다.

그들의 힘은 각자의 성향에 따라 차이가 나며 근원적인 힘의 원류는 동일했다. 



바이러스에 감염된 생명체는 생과 사의 구분이 없어지고 육체적인 감각만이 남아 육체에 강한 자극만을 추구하게 된다.

그로 인해 느껴지는 주변의 모든 것을 파괴하기 위해 움직이고 서로를 살육하기에 이른다.

태풍과 같았던 초기의 바이러스의 침범이 그 속도를 늦추어 갈 때쯤 바이러스에 중독된 생명체 중에서 변이가 생기는 개체가 발생하게 되고 그 변이된 생명체는 다른 오염된 생명체를 일부 조종이 가능한 능력이 생기고 지능도 발전하게 되었다.


헬리네시아에 피신을 해 살아남은 8마리 고양이들이 초자연적인 힘을 얻어 변신한 후 오랜 시간이 흘러 그들의 자손이 묘신부족을 형성하게 된다.

묘신족은 헬리네시아의 안위를 위해 선택 받은 종족으로 그들의 힘을 이용해 헬리네시아와 살아남은 생명체들을 지키는 임무를 최우선시 해왔다.

하지만 부족이 형성되며 성향이 나뉘게 되어 고양이 특유의 영역개념이 남아 각 부족간의 갈등이 생기게 되고 급기야 많은 피해를 발생시킨 두 차례의 큰 싸움을 겪는다.

이후 전설의 8영웅의 정신을 이어받은 젊은 지도자가 통합을 위해 노력하게 되고 헬리네시아에서 자신들의 위치를 상기하며 더욱 강해진 힘으로 세계를 정화 시키기 위해 노력한다.

묘신족은 8영웅들의 자손들이 퍼져나가 크게 4개 부족으로 나뉘었으며 비슷한 문화를 형성했지만 초자연적인 능력의 활용에서 차이를 보였다.

바이러스에 중독된 몬스터들과의 전쟁에서 이겨 확보한 영토엔 헬리네시아에서 가져간 흙, 돌, 나무, 물 등으로 바이러스를 정화 시켜 영역을 늘려나갔다.

묘신족의 무기와 방어구

무기 체계와 특성

무기 타입은 한손근접무기, 양손근접무기, 원거리무기, 마법형무기로 나뉘어진다.

각 타입 별로 여러 가지 무기가 있다.

캐릭터는 직업에 따라 근접, 원거리 무기형 캐릭터와 마법형무기 캐릭터로 분류되어 각 직업에 맞는 무기만 사용 할 수 있다.

각 무기는 레벨에 따라 한계점까지 성장 할 수 있으며, 레벨업 아이템과 외형변화 아이템을 사용해 능력과 외형을 바꿀수 있다. 그리고 DIY툴킷을 이용해 자유로운 커스터마이즈가 가능하다.

무기 타입

한손근접무기, 양손근접무기

깃털, 나무방망이, 채찍, 뿔, 나무망치등 자연적인 소재를 이용해 검, 단검, 창등의 모습으로 변형시켜 사용한다.


새총, 요요, 부메랑, 프리스비등을 이용해 자연적인 모습으로 변형시킨다.


나무지팡이, 구슬, 탬버린등의 소재를 마법능력이 있는 무기로 변형시켜 사용한다.

Custom Mipmap encoding practice.

This example is not a production level.
This example can be used at the production level, but it can be upgraded to a full production level function by adding more efficient features.

公司内部还没有请求,但是我们根据JP Friends Company项目团队提出的类似要求进行研究。
通过改善Unity mipmap过滤的质量并改善模糊的Texel采样,我们希望改善更清晰的法线贴图表达(中等距离)或Albedo表达。

Purpose of experiment.
There is no request from within our company yet, but we study this based on the similar demand that arose from the project team of JP Friends Company.
By improving the quality of Unity mipmap filtering and improving the ambiguous Texel sampling, we want to improve a more clear normal map expression (medium distance) or Albedo expression.
In the case of roughness, there is no need to improve.

Preview of concept demonstration.


如果您看一下代码,它会将 @”.mip(\d)+$”  作为子字符串处理。









In the code above, there are functions for the pre-processing step and the post-processing step.

If you look at the code, it is processing @”.mip(\d)+$” as a substring.

The preprocessed file consists of filename.mipNum.format.

In other words, a file with the following structure is required to calculate the user mipmap.








The format above must be satisfied.


It is necessary to raise it to the production level.

Let’s work with the DEV-OPS team.


Compare the result obtained by modifying the Mip level with the default setting result

On the left, a custom mip-chain was applied, and on the right, the mip-chain result directly created by Unity.
All aniso level = 0 and Kaiser filter is applied.
所有aniso级别= 0,并应用Kaiser滤波器。








We learned the above approach.

What ideas can TA get after learning this?

How can We apply the above concept in the process of rendering texels?

If you can’t create an idea, what’s the difference between a programmer and a TA?

Let’s think.

In addition, it can be further developed by using the DCC program.

In this process, you can understand that TAs are people who go beyond the limits of programmers’ ideas.

Further learning.
Mip chain is easily produced using SD.
Create a mip chain generator using SD and create a template.

Addition reading reference documents.




Development of three-dimensional pupil shader.

Purpose of implementations.

  • One draw call rendering by one mesh.
  • Supporting customization of eyeball pupil.
  • Simple refraction FX.
Refer to desired result of eyeball.

preview of result.


我为美术提供的最终目标是Horizon Zero Dawn。

在实现过程中,我们合并了两个Draw-call,最大限度地降低了精度,消除了所有的GGX运算,只使用Normalized Blinn-Phong Specular实现。

ALU在处理折射时有所增加,但删除了依赖于PBR的某些部分,使得整体ALU比正常的PBR少了一些,实现了CustomUV,从而减少了Pixel Shader Stage计算的部分。

现在,我们使用Replection Cubemap来实现油膜的光泽度,而在下一个优化版本中,将更改为Dual Parabolic Reflection,以进一步优化它。

创作原型时,使用Amplify Shader Editor来实现了它。

实现了Eye Refraction function, Mode写为Create的话之后在代码中会以函数形式来记录。


An important part of my development of the pupils was to pinpoint exactly what the final requirements of the art team were.

The first two meshes were used by the art team voluntarily, but the two draw-calls were consumed and there was no refraction, so we simply discussed with the art team and then used two specular One is calculated from the position of the actual solar light source and the other is calculated from the point of view of the camera, that is, the camera point of view.

I also had to find the overall feeling of completeness, and my final goal for the art team was Horizon Zero Dawn.

In the implementation process, we merged two draw-calls into one, and we reduced the precision as much as possible, eliminated all GGX operations, and implemented only with Normalized Blinn-Phong Specular.

The ALU increased slightly when refracting, but by removing some of the PBR dependent parts, the overall ALU was reduced compared to the normal PBR, and the CustomUV implementation reduced some of the computation on the Pixel Shader Stage.Currently, the reflection cube map is used to realize the gloss of the retina. In the next optimized version, it will be changed to Dual Parabolic Reflection to optimize it further.

通常,Cube-Map reflection主要用于角色选择窗口。
在实际游戏中,通过仅选择视觉上不明显的部分来删除命令,并制作一个Shader for LOD MATERIAL。当前尽量不把Sub shader划分为多个。

It is a good idea to develop prototypes with simple textures so that the art team knows their implementation intent.

At this point, I discussed further with the art team to discuss how to improve the pupil lighting process and to continue to develop.

Normally Cube-Map reflection is only used in the character selection window.

In real gameplay, we’ll only remove parts that aren’t visually obvious and remove commands and create another shader for LOD MATERIAL.We are not dividing the currently available Sub shader into several.

Energy conserved specular blinn-phong.

Energy conserved specular blinn-phong implementation record

Elements of Implementations

  • Energy conserved diffuse with specular.
  • Physically based Fresnel.
  • Environments Reflectance.
  • Ambient lighting adjustment controller.

Energy conserved diffuse with specular.

about energy conserved specular.

Method of Simple energy calculations of shader.
Applied Energy Conservation of blinn-phong specular.
//                      Lighting Functions                                   //
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
    half NdotL = saturate(dot(normal, lightDir));
    return (1.0 / PI ) * lightColor * NdotL;
    return lightColor * NdotL;

half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specular, half smoothness)
    float3 halfVec = SafeNormalize(float3(lightDir) + float3(viewDir));
    half NdotH = saturate(dot(normal, halfVec)); //specualrDot
    half modifier = 0;
//PI is already defined location from "Packages/com.unity.render-pipelines.core/ShaderLibrary/Macros.hlsl"
    half norm = (smoothness + 2 ) / (2 * PI ); //refer document by "http://mathinfo.univ-reims.fr/IMG/pdf/Using_the_modified_Phong_reflectance_model_for_Physically_based_rendering_-_Lafortune.pdf"
    modifier = pow(NdotH, smoothness) * norm;
    modifier = pow(NdotH, smoothness);

    half norm = (smoothness + 2)*(smoothness + 4 ) / ((8 * PI )*(2-(smoothness/2) + smoothness)); //refer document by "http://mathinfo.univ-reims.fr/IMG/pdf/Using_the_modified_Phong_reflectance_model_for_Physically_based_rendering_-_Lafortune.pdf"
    modifier = pow(NdotH, smoothness) * norm;
    modifier = pow(NdotH, smoothness);
    half3 specularReflection = specular.rgb * modifier;
    return lightColor * specularReflection;

half3 LightingPhysicallyBased(BRDFData brdfData, half3 lightColor, half3 lightDirectionWS, half lightAttenuation, half3 normalWS, half3 viewDirectionWS)
    half NdotL = saturate(dot(normalWS, lightDirectionWS));
    half3 radiance = lightColor * (lightAttenuation * NdotL);
    return DirectBDRF(brdfData, normalWS, lightDirectionWS, viewDirectionWS) * radiance;

half3 LightingPhysicallyBased(BRDFData brdfData, Light light, half3 normalWS, half3 viewDirectionWS)
    return LightingPhysicallyBased(brdfData, light.color, light.direction, light.distanceAttenuation * light.shadowAttenuation, normalWS, viewDirectionWS);

half3 VertexLighting(float3 positionWS, half3 normalWS)
    half3 vertexLightColor = half3(0.0, 0.0, 0.0);

    uint lightsCount = GetAdditionalLightsCount();
    for (uint lightIndex = 0u; lightIndex < lightsCount; ++lightIndex)
        Light light = GetAdditionalLight(lightIndex, positionWS);
        half3 lightColor = light.color * light.distanceAttenuation;
        vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);

    return vertexLightColor;

Energy conserved experimental code block.

Simulate of Specular Reflectance

Applied Ambient Contrast
half3 GlossyEnvironmentReflectionExt(half3 reflectVector, half smoothness, half occlusion)
            #if !defined(_ENVIRONMENTREFLECTIONS_OFF)
                half mip = smoothness;
                half4 encodedIrradiance = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectVector, mip);
            #if !defined(UNITY_USE_NATIVE_HDR)
                half3 irradiance = DecodeHDREnvironment(encodedIrradiance, unity_SpecCube0_HDR);
                half3 irradiance = encodedIrradiance.rbg;
                return irradiance * occlusion;
            #endif // GLOSSY_REFLECTIONS
                return _GlossyEnvironmentColor.rgb * occlusion;
half4 UniversalFragmentBlinnPhongExtend(InputData inputData, half3 reflectVector,  half3 diffuse, half4 specularGloss, half smoothness, half reflectionRoughness,  half3 emission, half occlusion,half alpha)
                Light mainLight = GetMainLight(inputData.shadowCoord);
                MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));
                half3 attenuatedLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);
                half3 diffuseColor = 1;
                diffuseColor = inputData.bakedGI + LightingLambertExt(attenuatedLightColor, mainLight.direction, inputData.normalWS);
                diffuseColor *=occlusion;
                half3 specularColor = LightingSpecularExtend(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
                diffuseColor +=GlossyEnvironmentReflectionExt(reflectVector, reflectionRoughness, occlusion);
            #ifdef _ADDITIONAL_LIGHTS
                uint pixelLightCount = GetAdditionalLightsCount();
                for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
                    Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
                    half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
                    diffuseColor += LightingLambertExt(attenuatedLightColor, light.direction, inputData.normalWS);
                    specularColor += LightingSpecularExtend(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
            #ifdef _ADDITIONAL_LIGHTS_VERTEX
                diffuseColor += inputData.vertexLighting;
                half3 finalColor = diffuseColor * diffuse + emission;
            #if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
                finalColor += specularColor;
                return half4(finalColor, alpha);

Specular Reflectance experimental code block.

Journey to the west [:西遊記:]

사진 설명이 없습니다.

即使有一个基准测试游戏,但制作过程却是由于这样的事实,即诞生更接近工程师。 第二天就去公司工作……这并不困难,但游戏性也是一个问题。
在开发的早期阶段,游戏本身与技术方法之间的联系非常差,而且不是很好。 可能已经过了几个月,但这是值得的。

In 2013, I introduced indie games that I started making with two acquaintances when I worked as a technical art director for a company.
I didn’t build a company, but I got a small office at the Soho Center in Yangjae-dong and developed it after work with Someone.
Even though there was a game of bench-marking, the process of making it was due to the fact that the birth was closer to the engineer. Posted to the company the next day to work … It was not hard, but also game-play was a problem.
It was not so fun.
It’s such an indie game project that I’ve been so excited about the lack of fun that I’ve gained a lot from this process.
I seemed to have been paid for a long time and didn’t feel it.
In the early stages of development, the game-play itself was very badly related to the technical method, and it wasn’t very good. It may have been a few months, but it was well worth it.

这是我以Tech art director的身份工作期间,在下班后一点点开发出来的Indie Game画面。和以前的同事引擎程序员一起以COCOS2D engine为基础,添加了Bullet Physics,追加开发了3D概念。开发过程中,引擎程序员入职其他大公司后忙得不可开交,我也转到了外籍公司,之后开发中断了。说实话,我们停止开发的原因是虽然这是我们做的,但也太没意思了。

These are Indie Game screens that I developed a little after work while working as a tech art director in Korea a long time ago.
I worked with my former colleague engine programmer to add Bullet Physics and 3D concepts based on the COCOS2D engine.
During the development, after the engine programmer moved to another big company and became too busy, I also moved to a foreign company, and then development stopped.
Honestly, the reason we stopped developing was that we made it too much fun.

Tool Research and developments




利用 Blend node 的 Cropping Area。



Part1. Basic wooden tile pattern.


Part2. Material compositing.


Extra. 设置 Iray rendering 的 Tessellation 后渲染。

制作 Base Shape 。

生成 Shape Node 后根据上图修改选项。

Pattern : Square

Scale : 0.6

Angle : 45 Degrees

Shape 修改结果。


添加 Blend Node 并连接。

会使用 Blend Node 的 Cropping Area 。

剪掉 Shape 的左右。

为了获得上面的要求值修改 Cropping Area。

Cropping Area ( 左右的合是 1。 )

Left : 0.13

Right : 0.87

0.13 + 0.87 = 1


各自添加 Bevel Node 和 Blur HQ Grayscale Node ,跟上图一样连接。 ( Height – > Grayscale)

Bevel Node 设置。

Blur HQ Grayscale Node 设置。

Intensity : 0.41
Quality : 1

各自添加一个 Blend Node , Transformation 2D , Gradient Linear1 node 。

Blend Node 设置

Gradient Linear1 设置。

Transformation 2D设置

主要是修改 Offset Y 轴 Gradient Linear 1 值做成 Shape 的分层深度值,把这个在 Blend  Node 里合成制作 Depth 。

Offset Y : -0.0341(使用任意值。)


添加 Tile Sampler 把最后生成的 Blend Node 连接到 Pattern Input 1 。

Tile Sampler 设置。

X Amount : 5
Y Amount : 8
Pattern : Pattern Input
Size X : 1.12
Size Y : 2.24
Scale : 1.26
Scale Random : 0.01

为了任意修改深度感,添加 Levels node 连接到 Tile Sampler 。

Level node 设置

变更成 Parameter mode 后修改值。

Level In Low : 0

Level In High : 1

Level In Mid : 0.5 ~ 0.55

Level Out Low : 0

Level Out High : 0.7

Clamp : On


先在 PBR Shader 适用深度图。

把 Levels Node 连接到 Height Out-put node 。

把鼠标放到 Height node 上并右击执行 View in 3D view 指令。

连接到 Material 的 Height 后把 Tessellation Scale 变更成 10 。

如果不方便确认中间阶段的结果,在下方连接下载 SIMPLE OUTPUTS  utility使用就可以了。

다운로드 경로.


중국 내륙과 해외에서 모두 다운 로드 받기 용이 저장소 서비스 https://mega.nz/ 사용 했다.



使用了中国和海外都便于下载的储存库 https://mega.nz/

Custom Filter 에 등록을 했다면(Custom Filter 등록 방법은 다른 장에서 배우기로 하자.)

如果登记到了 Custom Filter (登记到 Custom Filter 的方法在其他章节学习下吧。)


点击后拖动储存到 Graph 窗口。

在3D View 适用预览。

巴 ed U28 
014 M 
OE pue 
Pleoqd!lD 010 ~ - 'GOD 
M a 一 > a 」 d n d n O 
: - 5 Lu 巴 ed 250dX 亠 
saPON 」 ed 
“ uadO 
巴 亠 P PV 
de 一 一 OD 
× 9 6 0

Levels 连接到 Output Preview 后,把鼠标放到 Output Preview 上面右击。


Output Preview Node 获取高度(深度) 信息后, 便于用 Normal map 和 Curvature smooth map , AO map 简单自动变换后,确认中间过程的 Height map 适用内容。



为了实现那种操作,添加 Height to Normal World Unit Node 并连接。

Normal Map 会成为生成 Curvature map 的重要材料, Curvature Map 是制作最终 AO Map 的重要材料。


Surface Size(cm) 根据平均值 300 或者想要的感觉设置成 200 左右。

Height Depth(cm) 根据叠层图层的高度设置。

因为作者把一层大概假设成是 3cm ,所以这个值设成了 3

Normal Format : OpenGL

Sampling : Sobel

NORMAL SOBEL 高度图用 sobel 算法让边缘明暗部的像素更明显,生成法线。

Sampling 类型的相关详细内容 Sobel 请参考 Basic algorithm ( 基本算法 ) 。


通常 Height Map 直接变换成 AO MAP 。

这时通常使用的变换 NODE 是使用 Ambient Occlusion(HBAO)

因为已经做了 Height Map ,所以把 Height Map 直接连接到 Ambient Occlusion(HBAO) 。


在图案边缘稍微添加 Edge 效果。

添加 Curvature Smooth node 连接  Height to Normal World Unit Node 。

把 Curvature Smooth node 连接到 Ambient Occlusion(HBAO) 。

Curvature Smooth node 的 Normal Format 是 OpenGl。

Ambient Occlusion(HBAO) 的参数。
Use World Units : True
Surface Size : 300
Height Scale(cm) : 3
Radius : 0.02
Quality : 16 samples
Non Square : False
GPU Optimization : True

做AO Final Polishing 。

为了让边缘更自然,添加 Blur HQ Grayscale node 。

把 Ambient Occlusion(HBAO) 连接到 Blur HQ Grayscale node 。

把 Blur HQ Grayscale node 连接到 AO 最终输出的 ambientOcclusion output 。


适用 Height map 和 Normal Map 和 AO MAP 的中介阶段结果。

把 Normal Map 和连接到 AO Map 节点的部分整理为 Part1 。

Part 2.


在 Part 1 制作的材质表面混合细节质感。


使用 CREATE SIMPLE WOODEN FLOOR TEXTURE 过程制作的方法里的一部分,就可以很轻易把表面质感做出来。

Wood Base Material 设置。

适用 Albedo Color 和  Roughness 基本值。




添加 Directrional noise 2 。
Directrional noise 2
Scale : 1
Disorder : 0.24
Angle : Degrees – > 90

添加 BnW Spots 1 。

添加 Directional Warp 并连接。

BnW Spots 1
Scale : 2
Roughness : 0.53
Non Square Expansion : True.
Directional Warp
Intensity : 122.5
Warp Angle : 90 ~ 91

添加 Blend ,把原版 Directional Noise 2 连接到 Foreward 。

把 Directional Warp 连接到 Blend 的 Background 上。


Opacity : 0.82
Blending Mode : Copy


在程序化贴图制作里,添加表面颜色时最常用的是 Gradient Map 。

添加一个 Gradient Map 。



之后会用 HSL 调整细节色调。

添加两个 HSL 。

Gradient Map 各自连接到两个 HSL 。

上方 HSL

Hue : 0.53

Saturation 0.38

Lightness : 0.5

下方 HSL

Hue : 0.53

Saturation 0.43

Lightness : 0.45

添加 Blend 并连接两个 HSL 。

把连接到 Gradient Map 的 Blend output 连接到新做的 Blend 的 Mask Input 上。

这将用于混合两个不同 HSL 色调的权重。

把节点用 Frame 绑起来,并命名。

作者设置成了 Wood Surface Color Base 。

添加 Color Match 。

虽然是和 Replace Color 类似的节点,可以根据输入的平均颜色来变更色调。

Color Match
Source Color Mode : Average
Target Color Mode : Parameter
Target Color : RGB(130,88,64)



Part 1 样式适用 Random grayscale 后把这个用成 Directional Warp intensity 值。

为了变化 Base Color 的色调,做个节点。

添加 Edge Detect 和 Flood Fill 。

添加 Flood Fill to Random Grayscale ,用 Blur HQ Grayscale 稍微添加 Blur 效果。

Edge Detect
Edge Width : 1
Flood Fill
Safety/Speed trade-off : Complex or big shapes
Blur HQ Grayscale
Intensity : 0.18
Quality : 1

添加 Directional Warp ,连接 Wood Surface Color Base Frame 的 Color Match 。

Directional Warp
Intensity : 196.66
Warp Angle : Degrees -> 65

Directional Warp 的 Intensity Input 连接 Blur HQ grayscale 。

生成为 Flood Fill 的值用于 Directinal Warp 的 Warp Angle 的权重(Weight)。


在各个区域适用不同的灰色调,可以在 Warp Angle 的角度以区域为单位给变化。



Anisotropic noise
X Amount : 4
Y Amount : 128
Rotate : True
Smoothness : 1
Smoothness Interpolation : 0.5
Non Square Expansion : True
Directional Warp
Intensity : 3.78
Warp Angle : 58

吐过添加了 Blend ,连接 Anisotropic noise 和 Directional Warp 。

Opacity : 0.57
Blending Mode : Add(Linear Dodge)

添加 Detail Normal 。

添加 Height to Normal World Unit 节点并连接。

为了尽量维持路面的细节描写, Sampling type  直接用基本值 Standard 。

Height to Normal World Unit
Surface Size (cm) : 300
Height Depth(cm) : 0.15
Normal Format : DirectX
Sampling : Standard
Height to Normal World Unit
Surface Size(cm) : 300
Height Depth (cm) : 3
Normal Format : DirectX
Sampling : Sobel

两个 Normal 结果合并为一个。

Normal Combine
Technique : Channel Mixer (High Quality)


确认 Base Color 和 Normal Map 阶段的材质。

在中间确认阶段应该也感觉到了,现在棱角部分的明暗不是很明显,所以要添加 Ambient Occlusion 和 Roughness 等所有 Material Propertices 。

Ambient Occlusion 要制作更明显的 Ambient Occlusion 和细腻的 Ambient Occlusion 这两种。

制作 Ambient Occlusion 和 Detail Ambient Occlusion  。

添加 Ambient Occlusion(HBAO) 连接 Part1 的 Level Output 。

Ambient Occlusion(HBAO)
Use World Units (cm): 50
Height Scale (cm): 5
Radius : 1
Quality : 8 Samples
GPU Optimization : True

因为变换的 AO 品质太锐利了,为了变得更柔和添加 Blur HQ Grayscale 并连接 Ambient Occlusion(HBAO) 。

Blur HQ Grayscale
Intensity : 0.2 ~ 0.3
Quality : 1

为了获取 Detail AmbientOcclusion ,添加 Curvature smooth 和 Ambient Occlusion (HBAO) ,连接和 Wood Surface Color Detail Frame 连接的 Normal Combine 。

Curvature smooth
Normal Format : OpenGL
Ambient Occlusion (HBAO)
Use World Units : True
Height Scale(cm) : 1
Radius : 0.02
Quality : 16 samples
GPU Optimization : True

用 Blend 混合两个 Ambient Occlusion 。

Opacity : 0.5
Blending Mode : Multiply

对比 Detail Ambient Occlusion 添加前后。

制作 Roughness 。

Wood Surface Color Base Frame 开始制作。

添加 HSL 节点,跟 Blend output 连接。

和 Wood Surface Color Detail Frame 连接的 Curvature Smooth 上再添加一个 Level 。

Level In Low : 0.46
Level In High : 0.84
Level In Mid : 0.5
Level Out High : 1
Intermediary clamp : Clamp

添加 Blend ,把 HSL 全部连到 Foreground 和 Background 。

然后添加 Level ,修改的 Curvature Smooth 信息用于 Blend 里将要混合的 Maks 区域。

Opacity : 0.7
Blending Mode : Add (Linear Dodge)

输入的相同 HSL 信息混合成 Add (Linear Dodge) ,同时为了表现木纹的细节,把 Curvature Smooth 值变形输入为 Mask 就可以表现更丰富的表面粗糙效果。这种节点连接方法是很常用的。

简单的 Roughness 结果和添加几个连接得出的更写实的 Roughness 结果。

添加可以修改 Roughness 值的 Level 。

这时中间再连接 Grayscale conversion 变更为单一色彩。

Roughness 在 RGBA 中只要把 R 值储存为 Grayscale 就可以了。

Level In Mid : 0.531


最终 Output 连接。