-
Notifications
You must be signed in to change notification settings - Fork 1.7k
第9章第2节疑似代码错误 #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
亲爱滴你真是好学,其实这一节的确有需要完善的地方,第9章是我写的最最痛苦的一章,没有之一,就是因为Unity的光照计算基本是黑盒的,全靠猜和自己看代码。但问题是,要在一本入门书里面讲清楚原原本本怎么计算的很复杂,对初学者来说反而不易于打基础(我认为的……),而且我不敢保证我的分析一定对,于是这一节我就简化了……简……化……了……我本来是想引出后面9.4.4节,告诉大家,“嗯,自己处理很麻烦的哦,而且一不小心就错了哦,所以大家都来用自带的函数和宏计算吧!”但我没有写的这么明白…… 其实这个报错当时我发现了,掩面(/ω╲)我错了……我再解释一下,之后想办法补充到书里面吧。 我们都知道Unity写shader处理一些光照很方便(当然前提是我们知道怎么处理。),但这显然不是免费的午餐,Unity在背后做了很多工作。在光照方面,一个最简单的问题就是,Unity凭什么知道当前的光源类型、有没有使用lightmap、有没有开启阴影这些条件呢? 想象一下我们自己写shader的话会怎么办,我们肯定会根据不同的条件来使用不同的shader,其实Unity也是这么做的,它依靠的就是shader program variants。shader program variants其实就是shader变种,简单说就是由一个Unity Shader可以衍生出了许多真正的shader program,我们会根据条件来判断到底把哪个shader program发送给GPU。那么,我们明明只写了一个Unity Shader啊,衍生出来的shader program哪里来的?这就是通过multi_compile指令。 还记得我们要求在Forward Base和Forward Add里面比如要加#pragma multi_compile_fwdbase或者#pragma multi_compile_fwdadd这样的代码吗?这些指令其实就是Unity预定义的multi_compile指令,一旦声明了这些指令,Unity就会为ForwardBase和ForwardAdd生成大量的shader program以及对应的keyword。如果你不理解的话,我们可以举个例子。你看我们的代码里经常会通过#ifdef来判断一些状态有没有开启。我们随便粘贴AutoLight.cginc最开头的一段代码:
上面的SHADOWS_SCREEN、UNITY_NO_SCREENSPACE_SHADOWS、SHADOWS_NATIVE等这些都是Unity生成的keyword(对,就在你写下#pragma multi_compile_fwdbase这些话的时候Unity背后就干了这么多的事情。),Unity靠这些keyword来判断当前使用哪些代码。而且这不同于分支语句,Unity其实是真的生成了非常多的shader program,这你可以通过Unity Shader导入面板的Compile and show code来看到,比如我们粘贴一段:
后面太长我就不粘贴了。这个shader program就对应了"DIRECTIONAL" "SHADOWS_SCREEN" "SHADOWS_NATIVE" "LIGHTMAP_OFF" "DIRLIGHTMAP_OFF" "DYNAMICLIGHTMAP_OFF"这些keyword开启时的代码。 当然,我们自己也可以定义keyword,来生成自己的shader program变种,可以参考我的博客。 说了这么多,不知道你有没有晕掉。其实上面就是想说明,Unity是如何来处理不同的光照条件、执行不同的代码的。嗯,就是shader program variants + 很多的keyword。那么回到我们的问题,为什么书里面的这个代码报错了。 答案就是我们的keyword判断条件有问题,导致_LightTexture0这张纹理并没有被定义。你可以将原来的代码替换成下面的代码:
应该就不会再出错了。你对比就会发现,其实就是更加精确的判断了keyword条件,保证只在正确的时候执行那段访问纹理的代码。_LightTexture0这张纹理只在某些条件下会被定义,例如在开启了POINT、SPOT、POINT_COOKIE、DIRECTIONAL_COOKIE等,具体你可以在AutoLight.cginc里面找到。但因为原来的代码里没有进行严格判断,在发布的时候由于Unity会严格编译Unity Shader根据不同的keyword生成对应的shader program,此时它就会发现我们的错误了。那么为什么编辑器里没有报错呢?大概是Unity编辑器状态下并没有严格编译(这段是我自己猜的哈……) 最后我再补充下,书里面的这些代码都是怎么写出来,可不是我自己歪歪写的。这都是跑到自带的cginc文件里面,一行行看它们的代码是怎么写的,然后删减掉不必要的部分。如果以后有遇到类似问题,可以也直接看它们的逻辑和判断是怎么写的,尤其是遇到这些keyword的时候! 我啰嗦了这么多,是不是可以理解我为什么没有把这一段放到书里 (⊙﹏⊙)b |
小脸一红=^^= 此外还有一处报错,我在网上找到解决的代码,这个错误也是只在发布的时候会报,编辑器模式下可能看不到(也可能会有黄色提示),总之加上后,所有红色的黄色的都没了(世界终于干净了……)
加上UNITY_INITIALIZE_OUTPUT宏就对了。
上面的注释大约就是告诉你初始化值,并且在……情况下不被支持(E文差就是这种结局)。 |
我的代码在报这个错。主要是因为单个Pass的Shader都不会报错,2个Pass就报错,让人觉得比较难理解。 |
额这种还是因为自己写代码不严谨造成的,无论几个Pass还是都应该初始化所有变量。 哈哈书里面有很多那种第一次看起来不重要、第二次看就发现很重要的点…… |
问个问题, 这句话如何理解的: max(dist > (shadowCoord.z/shadowCoord.w), lightShadowDataX); |
作者你好。
前次给你发了一个邮件说发布PC包的Shader不被支持的问题。
根据我逐个计算模块的排查,以及直接使用你的工程里面第9章第2节的“Forward Rendering”的源码,基本可以确定是以下代码引发错误:
上面注释的两句代码,是我误以为d3d11不支持.rr的写法,就换了一个写法,但不管用。
报错是:
Shader error in 'Forward Rendering': 'tex2D': no matching 2 parameter intrinsic function; Possible intrinsic functions are:……
后面是Unity给出的tex2D函数格式建议。
此错误在编辑器模式下不会报,且可以正确计算衰减,但如果打包至win平台,则会报上述错误。
如将此段代码注释,一切正常。
此错误会导致Shader无法被执行,两个Pass被移除,并寻找备胎。
备胎代码:
FallBack "Specular"
无法正常执行。
下面是Unity的output_log记录:
The text was updated successfully, but these errors were encountered: