The Lab Renderer for Unity是Valve针对VR在Unity的体验渲染器,提高VR的渲染效率,更多的大家可以查相应资料,在这,说个The Lab Renderer for Unity现阶段的问题,可能是第一版,在地形并不能接受Valve渲染产生的阴影,对应地形上的树啥的也不能产生阴影,经过相应修改后,如下是改动后的效果图。  

  

  我们首先需要分析下Lab Renderer的基本渲染流程,主要代码在ValveCamera中,可以看到,渲染流程还是很简单的,相应的Lab Renderer文档也首先点明了,前向单通道渲染。

  我们知道在以前如Ogre2.0以前的前向渲染时,如果有多个灯光,是需要多次PASS来叠加光源得到效果,嗯,Unity本身也是这样处理的,这样灯光越多,灯光与模型就是L*M的关系,所以大家开始采用后向渲染,把模型相应数据渲染到GBuffer中,然后与光源计算得到正确显示,只需要L+M,虽然延迟渲染解决了多光源的问题,但是如下透明度,硬件AA,复杂材质,大量带宽是延迟渲染比较难搞的部分。

  而在VR中,延迟渲染前没有比较好用的空间AA算法,一般来说在VR中,采用后向抗锯齿算法,一些UI还有字体还是还看到锯齿,而VR眼睛分辨率比主机高的多,GBuffer你搞低了效果不好,大一点,双摄像头需要的显存带宽更是比主机多了去,所以当你导入Stream VR的包时,都会让你选择前向渲染,嗯,前向渲染的问题前面说了,多光源,而ValveCamera主要就是来解决如何在前向渲染里的单Pass里渲染多个光源的。

  Lab Renderer会要求你在每个实时光源下挂一个ValveRealtimeLight脚本,这个脚本主要是收集所有实时光源,然后在渲染时做二件事情,都是在OnPreCull之前,一是生成光源阴影图(RenderShadowBuffer),二是把所有灯光的信息填入到vr_lighting.cginc中的ValveVrLighting的const buffer中。

  在以每个光源位置与方向来渲染当前的模型来生成阴影,不同类型光源会有些不同,如方向光,位置移到老后面,FOV也需要调整,肯定要保证所有模型都渲染到,而Point光源,需要渲染六个面,只有spot光源,其属性与Camera对应,不需要啥特殊处理,渲染的RenderTarget只需要一个差不多类似深度的值就行了,所有RenderTarget全在m_shadowDepthTexture中,根据在每个ValveRealtimeLight脚本中设置的大小自动选择一个位置,注意在场景中的任何地方不能有摄像机视野内的所有光源的ValveRealtimeLight设置的大小加起来不能超过m_shadowDepthTexture本身的大小。

  然后就是写入所有灯光的信息到ValveVrLighting的const buffer中,在UpdateLightConstants这个方法中,其实这个过程和Ogre2.1的灯光处理很类似,大家可以看我以前写的 Ogre2.1 灯光与阴影,当然Ogre2.1会复杂的多,采用的是Forward+,会把屏幕分成N多小格,每个小格确定受到那些光源的影响,不过思路确实有很多是一样的。

  明白了Lab Renderer做了啥,我们才开始做最主要的部分,替换地形着色器的代码,使之采用上面的m_shadowDepthTexture来产生阴影,并去掉原来的光照计算,采用Lab Renderer的光照算法,注意在这,我们还是想要能够使用Unity本身的地形编辑器,所以我们并不是简单把地形着色器有材质改成使用Custom,我们需要替换他本身的Standard地形着色器代码,在Unity5以后,对应shader文件为Standard-FirstPass.shader,我们要做的就是,把Standard-FirstPass.shader与vr_standard.shader终合起来,地形表面的颜色采用的Standard-FirstPass.shader里的SplatmapMix方法,而阴影以及光源影响在vr_standard.shader中的ComputeLighting方法。

  需要注意的,Standard-FirstPass.shader本身做为SurfaceShader,提供的Input并不满足我们ComputeLighting想要的参数,所以我们需要先看下Standard-FirstPass.shader生成完整的,包含顶点,片断着色器的代码,如下最下面的按钮:

  

  注意,产生的文件会有很多Pass,如每种Fog对应不同的Pass,在这我们只需要一个Pass就够了,其中Fog也让Lab Renderer里的vr_standard.shader中的处理方法来处理。

  我们根据vr_standard.shader开始改造我们选择的一个Pass,首先我们要确认vr_standard.shader有那些预处理定义与相应操作是我们根本不需要的,或者是在地形中默认处理方式,可以简化大部分vr_standard.shader片断着色器中的代码,移除Standard-FirstPass.shader大部分片断着色器代码,添加vr_standard.shader片断着色器的代码,如前面所说,处理好Standard-FirstPass.shader里的SplatmapMix方法与vr_standard.shader中的ComputeLighting方法就成功了99%。如下是处理后的版本,还有Fog这边没有测试,大家自己去改,不麻烦。

  文件链接:vr_terrain.zip

  1. Shader "Nature/Terrain/Standard" {
  2. Properties{
  3. // set by terrain engine
  4. [HideInInspector] _Control("Control (RGBA)", 2D) = "red" {}
  5. [HideInInspector] _Splat3("Layer 3 (A)", 2D) = "white" {}
  6. [HideInInspector] _Splat2("Layer 2 (B)", 2D) = "white" {}
  7. [HideInInspector] _Splat1("Layer 1 (G)", 2D) = "white" {}
  8. [HideInInspector] _Splat0("Layer 0 (R)", 2D) = "white" {}
  9. [HideInInspector] _Normal3("Normal 3 (A)", 2D) = "bump" {}
  10. [HideInInspector] _Normal2("Normal 2 (B)", 2D) = "bump" {}
  11. [HideInInspector] _Normal1("Normal 1 (G)", 2D) = "bump" {}
  12. [HideInInspector] _Normal0("Normal 0 (R)", 2D) = "bump" {}
  13. [HideInInspector][Gamma] _Metallic0("Metallic 0", Range(0.0, 1.0)) = 0.0
  14. [HideInInspector][Gamma] _Metallic1("Metallic 1", Range(0.0, 1.0)) = 0.0
  15. [HideInInspector][Gamma] _Metallic2("Metallic 2", Range(0.0, 1.0)) = 0.0
  16. [HideInInspector][Gamma] _Metallic3("Metallic 3", Range(0.0, 1.0)) = 0.0
  17. [HideInInspector] _Smoothness0("Smoothness 0", Range(0.0, 1.0)) = 1.0
  18. [HideInInspector] _Smoothness1("Smoothness 1", Range(0.0, 1.0)) = 1.0
  19. [HideInInspector] _Smoothness2("Smoothness 2", Range(0.0, 1.0)) = 1.0
  20. [HideInInspector] _Smoothness3("Smoothness 3", Range(0.0, 1.0)) = 1.0
  21.  
  22. // used in fallback on old cards & base map
  23. [HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "white" {}
  24. [HideInInspector] _Color("Main Color", Color) = (,,,)
  25. }
  26.  
  27. SubShader{
  28. Tags{
  29. "Queue" = "Geometry-100"
  30. "RenderType" = "Opaque"
  31. "PerformanceChecks" = "False"
  32. }
  33.  
  34. Pass
  35. {
  36. Name "FORWARD"
  37. Tags{ "LightMode" = "ForwardBase" "PassFlags" = "OnlyDirectional" } // NOTE: "OnlyDirectional" prevents Unity from baking dynamic lights into SH terms at runtime
  38.  
  39. CGPROGRAM
  40. #pragma target 5.0
  41. #pragma only_renderers d3d11
  42. #pragma exclude_renderers gles
  43. #pragma vertex MainVs
  44. #pragma fragment MainPs
  45. #pragma shader_feature S_RECEIVE_SHADOWS
  46. #pragma multi_compile _ D_VALVE_SHADOWING_POINT_LIGHTS
  47. #pragma shader_feature S_OVERRIDE_LIGHTMAP
  48. #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
  49. #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
  50. #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
  51. // Includes -------------------------------------------------------------------------------------------------------------------------------------------------
  52. #include "UnityCG.cginc"
  53. #include "UnityLightingCommon.cginc"
  54. #include "UnityStandardUtils.cginc"
  55. #include "UnityStandardInput.cginc"
  56.  
  57. #define S_RECEIVE_SHADOWS 1
  58. #define D_VALVE_SHADOWING_POINT_LIGHTS 1
  59. #include "Lighting.cginc"
  60.  
  61. #pragma multi_compile __ _TERRAIN_NORMAL_MAP
  62. #define TERRAIN_STANDARD_SHADER
  63. #define TERRAIN_SURFACE_OUTPUT SurfaceOutputStandard
  64. #include "TerrainSplatmapCommon.cginc"
  65. #include "vr_utils.cginc"
  66. #include "vr_lighting.cginc"
  67. #include "vr_matrix_palette_skinning.cginc"
  68. #include "vr_fog.cginc"
  69.  
  70. #define LIGHTMAP_ON 1
  71. #define DYNAMICLIGHTMAP_ON 1
  72. #define DYNAMICLIGHTMAP_OFF 0
  73. #define DIRLIGHTMAP_COMBINED 1
  74. #define S_OVERRIDE_LIGHTMAP 0
  75.  
  76. half _Metallic0;
  77. half _Metallic1;
  78. half _Metallic2;
  79. half _Metallic3;
  80.  
  81. half _Smoothness0;
  82. half _Smoothness1;
  83. half _Smoothness2;
  84. half _Smoothness3;
  85.  
  86. // Structs --------------------------------------------------------------------------------------------------------------------------------------------------
  87. struct VS_INPUT
  88. {
  89. float4 vPositionOs : POSITION;
  90. float3 vNormalOs : NORMAL;
  91. float2 vTexCoord0 : TEXCOORD0;
  92. float2 vTexCoord1 : TEXCOORD1;
  93. #if ( DYNAMICLIGHTMAP_ON || UNITY_PASS_META )
  94. float2 vTexCoord2 : TEXCOORD2;
  95. #endif
  96. };
  97.  
  98. struct PS_INPUT
  99. {
  100. float4 vPositionPs : SV_Position;
  101. float3 vPositionWs : TEXCOORD0;
  102. float3 vNormalWs : TEXCOORD1;
  103. float2 vTextureCoords : TEXCOORD2;
  104. float4 vLightmapUV : TEXCOORD3;
  105. float2 vFogCoords : TEXCOORD4;
  106. float4 pack0 : TEXCOORD5; // _Splat0 _Splat1
  107. float4 pack1 : TEXCOORD6; // _Splat2 _Splat3
  108. float2 custompack0 : TEXCOORD7; // tc_Control
  109. };
  110.  
  111. float g_flValveGlobalVertexScale = 1.0; // Used to "hide" all valve materials for debugging
  112.  
  113. // World-aligned texture
  114. float3 g_vWorldAlignedTextureSize = float3(1.0, 1.0, 1.0);
  115. float3 g_vWorldAlignedNormalTangentU = float3(-1.0, 0.0, 0.0);
  116. float3 g_vWorldAlignedNormalTangentV = float3(0.0, 0.0, 1.0);
  117. float3 g_vWorldAlignedTexturePosition = float3(0.0, 0.0, 0.0);
  118.  
  119. float4 _Splat0_ST;
  120. float4 _Splat1_ST;
  121. float4 _Splat2_ST;
  122. float4 _Splat3_ST;
  123. // MainVs ---------------------------------------------------------------------------------------------------------------------------------------------------
  124. PS_INPUT MainVs(appdata_full i)
  125. {
  126. PS_INPUT o = (PS_INPUT);
  127.  
  128. UNITY_SETUP_INSTANCE_ID(i);
  129. UNITY_TRANSFER_INSTANCE_ID(v, o);
  130. Input customInputData;
  131. SplatmapVert(i, customInputData);
  132. o.custompack0.xy = customInputData.tc_Control;
  133.  
  134. float3 vPositionWs = mul(unity_ObjectToWorld, i.vertex).xyz;
  135. o.vPositionWs.xyz = vPositionWs.xyz;
  136. o.vPositionPs.xyzw = mul(UNITY_MATRIX_MVP, i.vertex.xyzw);
  137.  
  138. // Normal
  139. float3 vNormalWs = UnityObjectToWorldNormal(i.normal);
  140. o.vNormalWs.xyz = vNormalWs.xyz;
  141. #if ( LIGHTMAP_ON )
  142. o.vLightmapUV.xy = i.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
  143. #endif
  144.  
  145. #if ( DYNAMICLIGHTMAP_ON )
  146. o.vLightmapUV.zw = i.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
  147. #endif
  148.  
  149. o.vFogCoords.xy = CalculateFogCoords(vPositionWs.xyz);
  150.  
  151. o.pack0.xy = TRANSFORM_TEX(i.texcoord, _Splat0);
  152. o.pack0.zw = TRANSFORM_TEX(i.texcoord, _Splat1);
  153. o.pack1.xy = TRANSFORM_TEX(i.texcoord, _Splat2);
  154. o.pack1.zw = TRANSFORM_TEX(i.texcoord, _Splat3);
  155. return o;
  156. }
  157.  
  158. // MainPs ---------------------------------------------------------------------------------------------------------------------------------------------------
  159. struct PS_OUTPUT
  160. {
  161. float4 vColor : SV_Target0;
  162. };
  163.  
  164. PS_OUTPUT MainPs(PS_INPUT i)
  165. {
  166. PS_OUTPUT po = (PS_OUTPUT);
  167.  
  168. Input surfIN;
  169. UNITY_INITIALIZE_OUTPUT(Input, surfIN);
  170. surfIN.uv_Splat0.x = 1.0;
  171. surfIN.uv_Splat1.x = 1.0;
  172. surfIN.uv_Splat2.x = 1.0;
  173. surfIN.uv_Splat3.x = 1.0;
  174. surfIN.tc_Control.x = 1.0;
  175. surfIN.uv_Splat0 = i.pack0.xy;
  176. surfIN.uv_Splat1 = i.pack0.zw;
  177. surfIN.uv_Splat2 = i.pack1.xy;
  178. surfIN.uv_Splat3 = i.pack1.zw;
  179. surfIN.tc_Control = i.custompack0.xy;
  180.  
  181. half4 splat_control;
  182. half weight;
  183. fixed4 mixedDiffuse;
  184. half4 defaultSmoothness = half4(_Smoothness0, _Smoothness1, _Smoothness2, _Smoothness3);
  185. SplatmapMix(surfIN, defaultSmoothness, splat_control, weight, mixedDiffuse, i.vNormalWs);
  186. //mixedDiffuse.rgb;weight;mixedDiffuse.a;dot(splat_control, half4(_Metallic0, _Metallic1, _Metallic2, _Metallic3));
  187.  
  188. float3 vAlbedo = mixedDiffuse.rgb;
  189.  
  190. float3 vTangentUWs = float3(1.0, 0.0, 0.0);
  191. float3 vTangentVWs = float3(0.0, 1.0, 0.0);
  192. float3 vGeometricNormalWs = float3(0.0, 0.0, 1.0);
  193. i.vNormalWs.xyz = normalize(i.vNormalWs.xyz);
  194. vGeometricNormalWs.xyz = i.vNormalWs.xyz;
  195. float3 vNormalWs = vGeometricNormalWs.xyz;
  196. float3 vNormalTs = float3(0.0, 0.0, 1.0);
  197.  
  198. // Roughness //
  199. float2 vRoughness = float2(0.6, 0.6);
  200. // Reflectance and gloss
  201. float3 vReflectance = float3(0.0, 0.0, 0.0);
  202. float flGloss = 0.0;
  203. vRoughness.xy = (1.0 - flGloss).xx;
  204.  
  205. LightingTerms_t lightingTerms;
  206. lightingTerms.vDiffuse.rgb = float3(1.0, 1.0, 1.0);
  207. lightingTerms.vSpecular.rgb = float3(0.0, 0.0, 0.0);
  208. lightingTerms.vIndirectDiffuse.rgb = float3(0.0, 0.0, 0.0);
  209. lightingTerms.vIndirectSpecular.rgb = float3(0.0, 0.0, 0.0);
  210. lightingTerms.vTransmissiveSunlight.rgb = float3(0.0, 0.0, 0.0);
  211.  
  212. float flFresnelExponent = 5.0;
  213. float flMetalness = 0.2f;
  214.  
  215. float4 vLightmapUV = float4(0.0, 0.0, 0.0, 0.0);
  216. #if (LIGHTMAP_ON || DYNAMICLIGHTMAP_ON )
  217. vLightmapUV.xy = i.vLightmapUV.xy;
  218. #if ( DYNAMICLIGHTMAP_ON )
  219. vLightmapUV.zw = i.vLightmapUV.zw;
  220. #endif
  221. // Compute lighting
  222. lightingTerms = ComputeLighting(i.vPositionWs.xyz, vNormalWs.xyz, vTangentUWs.xyz, vTangentVWs.xyz, vRoughness.xy, vReflectance.rgb, flFresnelExponent, vLightmapUV.xyzw);
  223.  
  224. #if ( S_OCCLUSION )
  225. float flOcclusion = tex2D(_OcclusionMap, i.vTextureCoords.xy).g;
  226. lightingTerms.vDiffuse.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthDirectDiffuse);
  227. lightingTerms.vSpecular.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthDirectSpecular);
  228. lightingTerms.vIndirectDiffuse.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthIndirectDiffuse);
  229. lightingTerms.vIndirectSpecular.rgb *= LerpOneTo(flOcclusion, _OcclusionStrength * _OcclusionStrengthIndirectSpecular);
  230. #endif
  231. #endif
  232.  
  233. // Diffuse
  234. po.vColor.rgb = (lightingTerms.vDiffuse.rgb + lightingTerms.vIndirectDiffuse.rgb) * vAlbedo.rgb;
  235.  
  236. po.vColor.rgb += lightingTerms.vIndirectSpecular.rgb; // Indirect specular applies its own fresnel in the forward lighting header file
  237.  
  238. //po.vColor.rgb = lightingTerms.vDiffuse.rgb;
  239. po.vColor.a = mixedDiffuse.a;
  240.  
  241. // Emission - Unity just adds the emissive term at the end instead of adding it to the diffuse lighting term. Artists may want both options.
  242. //float3 vEmission = Emission(i.vTextureCoords.xy);
  243. //po.vColor.rgb += vEmission.rgb;
  244. //o.vColor.rgb = ApplyFog(o.vColor.rgb, i.vFogCoords.xy, _FogMultiplier);
  245. // Dither to fix banding artifacts
  246. //po.vColor.rgb = ScreenSpaceDither(i.vPositionPs.xy);
  247.  
  248. return po;
  249. }
  250. ENDCG
  251. }
  252.  
  253. }
  254. Fallback "Nature/Terrain/Diffuse"
  255. }

Nature/Terrain/Standard

  地形中的树开始很奇怪,为啥没有投射阴影,在RenderShadowBuffer时调用m_shadowCamera.RenderWithShader时,在Frame Debug中发现并没有把树加进来,后面把渲染树的shader找到看了下,发现RenderType都不是Opaque,那么一是改变相应树的shader,使RenderType为Opaque,二是直接在RenderWithShader第二个参数填string.Empty就行,这样会有一个问题,会把啥透明的都渲染进来。

  其中vr_standard.shader与Standard-FirstPass.shader针对地形的混合,只是能看到阴影,如果想用,肯定还是要针对性的修改才行。

给The Lab Renderer for Unity中地形添加阴影的更多相关文章

  1. GJM : 【技术干货】给The Lab Renderer for Unity中地形添加阴影

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  2. 关于Unity中地形的创建

    地形创建 Raw图片格式是Unity可以导出的图片格式 Unity很强大,可以直接使用psd文件 地形创建实例 1.创建Unity工程和文件目录1:创建一个地形Terrain: GameObject- ...

  3. 【unity shaders】:Unity中的Shader及其基本框架

    shader和Material的基本关系 Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出.绘图单元可以依据这个输出来将图 ...

  4. Unity中Mesh分解与边缘高亮加上深度检测

    一个比较简单的需求,不过遇到些坑,记录下. 房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMe ...

  5. 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则

    作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...

  6. Unity中的GC以及优化

    [简介] 常见的 Unity GC 知识点总结出来的思维导图 Unity 官方文档,正巧在博客园发现了已经有位大神(zblade)把原文翻译出来了,而且质量很高~,译文地址 在这里.下面我就可耻地把译 ...

  7. 骨骼动画的原理及在Unity中的使用

    制作骨骼动画 我们看看这几步操作后,我们得到了那些数据: 1.每个皮肤顶点的初始世界坐标. 2.每个骨骼关节顶点的初始世界坐标. 3.每个顶点被骨骼顶点的影响信息. 4.骨骼如何移动. 骨骼动画原理 ...

  8. Unity中的内存泄漏

    在对内存泄漏有一个基本印象之后,我们再来看一下在特定环境——Unity下的内存泄漏.大家都知道,游戏程序由代码和资源两部分组成,Unity下的内存泄漏也主要分为代码侧的泄漏和资源侧的泄漏,当然,资源侧 ...

  9. 浅谈Unity中的GC以及优化

    介绍: 在游戏运行的时候,数据主要存储在内存中,当游戏的数据不在需要的时候,存储当前数据的内存就可以被回收再次使用.内存垃圾是指当前废弃数据所占用的内存,垃圾回收(GC)是指将废弃的内存重新回收再次使 ...

随机推荐

  1. 捉BUG记(To Catch a Bug)

    大约有一年整没有写一篇博客了,由于各种原(jia)因(ban)导致闲暇时间要么拿着IPad看岛国奇怪的片(dong)子(hua).要么拿着kindle看各种各样的资(xiao)料(shuo).本来想写 ...

  2. 用SQLSERVER里的bcp命令或者bulkinsert命令也可以把dat文件导入数据表

    用SQLSERVER里的bcp命令或者bulkinsert命令也可以把dat文件导入数据表 下面的内容的实验环境我是在SQLSERVER2005上面做的 之前在园子里看到两篇文章<C# 读取纯真 ...

  3. js promise 风格编程

    使用q 这种方式,极大的避免了回调地狱的情况产生,以后打算长久用这种方式. 再写Nodejs,再也不担心这个问题了. 以下实例,作为连接数据库的公共方法. /** * Created by Think ...

  4. Java Config 下的Spring Test方式

    用了三种方式: 1.纯手动取bean: package com.wang.test; import com.marsmother.commission.core.config.MapperConfig ...

  5. Xaml/Xml 实现对象与存储分离

    刚开始用xml存储东西的时候都是不断的在xml文件里面添加或者修改xml的节点,这个是很常见的做法,这方面的博客也很多我也就不介绍了.但其实在小批量存储的时候我们可以直接将对象存进xml/xaml,使 ...

  6. [MFC] MFC 仿 Flappy bird PC桌面版

    http://www.cr173.com/ 前些日子发现朋友都在玩flappy bird这款虐心的小游戏,网上也炒得很火,于是俺也想下一个玩玩.可是矮穷挫至今还没配上高端的智能机,于是去网上搜了一下, ...

  7. 访问IIS元数据库失败解决方法

    问题:访问元数据失败 详细信息 访问 IIS 元数据库失败. 说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信 ...

  8. 再谈this

    不管学习什么知识,习惯于把自己所学习的知识列成一个list,会有助于我们理清思路,是一个很好的学习方法.强烈推荐. 以下篇幅有点长,希望读者耐心阅读. 以下内容会分为如下部分: 1.涵义 1.1:th ...

  9. Why we need model on Django ?

    step01: create a database name as (django_db) on mysql ... step02: configure your django to use the ...

  10. EXCEL VBA入门篇之代码应用基础