参考资料:
大叔博客提及的多重编译开关
https://blog.csdn.net/qq18052887/article/details/80389506
多重编译入门
https://www.jianshu.com/p/f34d896dde5d
变体多了,发布卡和包体大问题
https://www.jianshu.com/p/08877fb0fceb
(没完全理解,也看了下《天涯明月刀》自制Shader编译和加载的资料,暂时没需要,没深究)
之前乱说的
由于真的开始着手,之前头疼的问题,改人家的代码:
之前我会觉得最好的办法是不要用宏,因为看过太多惨剧。
会觉得一是不负责任的“资深”程序员,或者是“初出茅庐”的实习生才会用的
但要是真的想升格为“高级”程序员,宏定义还是必要的
其实真没那么高大上,很多“程序员‘自以为看了2本书,就觉得自己很牛,这里就是要扒开他们的不堪
Unity Shader的案例是这样的
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
用的时候
#ifndef LIGHTMAP_OFF
o.uvLM.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
下面会展开说,就算,只要你只有一点点”程序“经验,应该也能看下去:
这时候,网上大部分都会这么说,有双下划线写法:
//#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
//可以这么写,减少宏变量,有个数限制
#pragma multi_compile __ LIGHTMAP_ON
哥有点lua语言经验,知道下划线 在L编程里能 _替代空变量,这么理解这里的双下划线就容易很多了。。。虽然他们是不同语言
例如 lua遍历可以这么写:
for _,v in pairs(tb) do
--...
end
只是Shader 这里用了双下划线 __替代空的宏定义,lua只是题外话,那的shader的问题来了
multi_compile __ xxx 是什么意思呢
multi_compile xxx __ 这么写又行不行呢
明显的,作为程序员,我们的直觉告诉我们,这 multi_compile 是一个语法,xxx 和 __ 都是他的参数,有一定的写法,有一定作用的,这不是废话吗??
是有点废,我的意思是:
1.你自然而然就会写空格 ,而且必然是 multi_compile空格[1]空格 [2] 这样的结构(具体公式格式我不会写)
2.少写一个参数应该肯定不行的,这2参数必然是一对的
3.默认会选第一个参数,也就是multi_compile xxx __ 是绝对不行的。。。。
怎么理解上面这3个规则呢(不需要理解,这是程序员的逻辑)
不理解不重要,先看看测试结果
有一个石头,有点黄昏的光照
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#ifndef LIGHTMAP_OFF
fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
finalColor.rgb *= lm;
#endif
写法一,发光
//#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#ifndef LIGHTMAP_OFF
fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
finalColor.rgb *= lm;
#endif
写法二,TM还是发光
#ifndef LIGHTMAP_ON
fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
finalColor.rgb *= lm;
//return fixed4(1, 1, 1, 1);
#endif
写法三,泪流某个海,感觉他应该还是会发光,结果暗了
事实证明,逻辑分析后:
定义与否,你写不写multi_compile ,一点P用没有
这就是很多文章,谬误的地方,问题的重点是,你写不写都没用,然后人家第一句上来就说这个怎么用
你:我想知道怎么用
他:这个这么用,还可以这么写
你:为什么没用
他:你这都不会用,你是不是程序员??可以这么写的
你:但这明明没用啊、、??
他:都说这么用咯。。。。你是不是蠢??
你:。。。。。
所以,作为真正的程序员,更多的时候需要走自己的路,所以搞清楚,并且用好宏定义,是很多程序员晋升的必经之路。
还是回到上面的问题,既然写法三,不发光(生效了)
必然满足2个条件:
1.定义了LIGHTMAP_ON (Unity在某个不知名的地方定义了)
2.某个程序员”大牛“ 这么写,#ifndef LIGHTMAP_ON(是的,字可能太小,这个大牛用了ndef
我被坑了一下午才发现问题,现在知道程序员有多不堪吧,写宏定义害死人,写ndef的更害死人
这时候,如果你没点经验,就会觉得,写成
#ifdef LIGHTMAP_ON
#endif
不是万事无忧咯,这么写的程序员更加不堪。。。。
事实是关于lightmap,关于unityshader宏,这这个例子中,这么一个特例下:
#ifndef LIGHTMAP_OFF
fixed3 lm = DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));
finalColor.rgb *= lm;
#endif
才是最佳实践
如何理解最佳实践
如果后面有时间会补充说明这个最佳实践
希望大家看完这个文章,能明白
程序员要写好程序,而不是坑人的程序,并不是背2行书,抄点,懂点逻辑,结果就能写出好的程序
基本上好的逻辑都是可以反推的。也就是所谓的逻辑反转
这个例子就是最好的证明
并不是我需要定义宏,然后写ifndef
而是我需要这个Shader由一个灯光开光,被逼要定义宏,
一是没有更好的写法(编程就是这么龌蹉,宏就是那么不堪)
二是这个开光怎么写还是取决于程序员(你自己,做个好人,还是随便做人,其实几率一半一半)
基本上这个Shader代码必须,从下(发光逻辑)写回到上(宏定义)的。。
关于Shader的课题,关于宏定义的课题,关于lightmap太多综合知识了,所以没法在这里详细讲,也可以说,编程已经是一个很综合的学科,而3d编程更加复杂(底层,基础理论很简单),就变的入门门槛很高
不想吐槽那些“知名博主”了
希望大家能对宏定义,由一个概念,并找到解决方法
最后:
(整个文章的Shader我隱藏了一部分代碼,是關於邏輯推理的,真的程序员应该能更好理解这个宏的作用,但又太長太乱,也不是宏定义的关键代码,取舍过后,还是删掉了,干净点)
完整的宏定义的测试例子这个哥们有:
https://blog.csdn.net/ak47007tiger/article/details/100007655