Skip to content
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

关于混合纹理Shader及lightmap的问题 #40

Closed
JOKULLIU opened this issue Sep 7, 2016 · 1 comment
Closed

关于混合纹理Shader及lightmap的问题 #40

JOKULLIU opened this issue Sep 7, 2016 · 1 comment

Comments

@JOKULLIU
Copy link

JOKULLIU commented Sep 7, 2016

作者你好!我又来麻烦你了,这回又有2个问题。
你还记的Unity Shaders and Effects Cookbook这本书第2章第4节的混合纹理吗?我用片元着色器改写之后,用在项目中,前天出了个新问题。
这个场景在iPhone和三星的Pad上都运行正常,但在小米note3上运行,会报错:
09-05 11:31:18.441 25728-25754/com.seawar.i4 I/Adreno: ERROR: 0:116: 'phase0_gl_Position' : undeclared identifier
ERROR: 0:116: 'x' : field selection requires structure, vector, or matrix on left hand side
ERROR: 0:117: 'y' : field selection requires structure, vector, or matrix on left hand side
ERROR: 0:118: 'z' : field selection requires structure, vector, or matrix on left hand side
ERROR: 0:119: 'w' : field selection requires structure, vector, or matrix on left hand side
ERROR: 5 compilation errors. No code generated.
我查了下,发现Shader被编译后的phase0_gl_Position变量没被定义。为了弄清楚到底是哪一行代码引起的,我逐行注释打包,最后发现是v2f结构体中的这两句:
half4 uv0 : TEXCOORD0;
half4 uv1 : TEXCOORD1;
这个多出来的uv1导致编译的代码多了一部分,其中就包含了phase0_gl_Position。
我单独把这个场景打包为apk文件,发现在note3上是正常的!也就是说,同样的Shader,在项目中打包apk,运行会报错;单独打包,运行正常!
这个问题我一时无解,所以只好写个备胎,只使用一张材质了事。(有可能需要使用 target 3.0 来指定,我还没尝试)
这里我觉得有必要补充一个小知识点,我反复翻阅了,确定你在书中没有说^-^,在使用FallBack时,主纹理变量应尽量保持与备胎Shader相同的命名,因为如果当前Shader不被支持时,使用Unity自带的Shader作为备胎(相信多数人都是),如果主纹理变量命名不一样,有可能导致纹理丢失,备胎也就失去意义了。

第二个问题是,场景的lightmap丢失了。
我的程序员给我的反馈如下(也是网上查的):

unity5在某些设备上,对于这种动态加载的物体,无论你是否设置它的renderer的 lightmapIndex和 lightmapScaleOffset, 它都不会为其shader设置LIGHTMAP_ON这个关键字,如果看一下unity 支持light map的shader的源码,可以发现这个 LIGHTMAP_ON是控制显示烘培图的关键,但是这种情况unity5不会设置,并且你自己手动设置也不行。这里有一个方法,就是修改这个shader,自己加一组关键字,比如叫做DYNAMIC_LIGHTMAP_ON,就算没有定义LIGHTMAP_ON,定义了DYNAMIC_LIGHTMAP_ON也会触发lightmap的贴图,然后在代码里加载完毕动态场景后,设置这个keyword就行了

我仿佛记得你在书中的某个地方提到过烘培的事情,但想不起在哪,也找不到了,但是我还没尝试DYNAMIC_LIGHTMAP_ON是否真的起作用,想请教下作者这里的处理办法。
另:
今天的尝试是用自己写Shader烘培,是没得效果的,具体表现就是一团黑。
一定要烘培才能看得出来,设置为Baked GI,不用Realtime GI
为稳当期间也使用了书上第9章第2节你的源码,同样无法烘培。
如果使用Unity自带的Mobile/Diffuse则无问题。
查阅Mobile/Diffuse的源代码发现其中并无处理lightmap的内容,而是在Mobile/VertexLit中有两段Pass专门处理lightmap,这也好理解,想必是当前Shader不支持,则向上追溯。
但是在自己的Shader,或是在作者的Shader中添加FallBack "Mobile/VertexLit"并无任何作用。
昨天去github上说这个问题,作者没有回复,可能这段时间比较忙吧。
书我只看到第十章开始点点,不知道后面有没有说这个问题。

@JOKULLIU
Copy link
Author

JOKULLIU commented Sep 12, 2016

烘培已解决,代码这样写(好押韵):
这是根据网上的一个例子改写过来的。
在Pass开始地方添加
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
(然而我并不懂这是什么意思。)
在a2v结构体中添加
half2 uv1 : TEXCOORD1;
个人猜测是用来接收lightmap坐标的。(废话)
在v2f中写上

#ifdef LIGHTMAP_ON
    half2 uvLM : TEXCOORD6;
#endif

网上例子的原文是#ifndef LIGHTMAP_OFF,如果没有定义LIGHTMAP_OFF,为啥要用双重否定这么拗口的文义呢,我改了。
在vert函数里面写

#ifdef LIGHTMAP_ON
    o.uvLM = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;  
#endif 

原文同样是#ifndef LIGHTMAP_OFF,被我改了,下面都是这种情况就不赘述了。这段代码倒是很简单。
在frag里面写

half4 finalColor;
#ifdef LIGHTMAP_ON
    finalColor.rgb = diff.rgb;
#else
    finalColor.rgb = diff.rgb * _LightColor0.rgb * _MainTint.rgb * halfLambert + ambient;
    finalColor.rgb *= atten;
    #if UNITY_SHOULD_SAMPLE_SH
        finalColor.rgb += i.sh;
    #endif
#endif  

这段代码意思我理解是如果光照图已经存在了,那么只需要主纹理就行了,如果光照图不存在,那么主光源、环境光、Lambert光、sh光统统给我加上去……(烘培后这些信息都保存在光照图里面了)。
最后一段代码非常重要,感觉很多人都在这里出错了。

#ifdef LIGHTMAP_ON
    fixed3 lm = DecodeLightmap (UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uvLM.xy));  
    finalColor.rgb *= lm;  
#endif 
return finalColor;

对光照图进行采样后,乘到finalColor上去。采样的函数不是tex2D()这点很重要。
我直接return lm看了光照图到底保存了哪些信息,这样更加深刻理解了光照图的好处。
以上代码亲测可用,而且和Unity自带的diffuse shader做了对比差异几乎看不出。
只在basepass上添加即可,addpass不用管。
至于DecodeLightmap容我再查查是什么含义。
Decode……看文义好像是解码……
我来填坑了。
DecodeLightmap是定义在UnityCG.cginc中的一个函数,它的作用是解码从lightmap中采样出的颜色。Unity使用了两种编码方式来存储lightmap:
1、doubleLDR,需要一张rgb24贴图
2、RGBM,需要一张rgba32贴图
在移动设备上使用doubleLDR格式,可以获得更快的计算速度。它只用到了lightmap的RGB通道。
PC上则使用RGBM格式,可以获得更广的亮度范围,而牺牲一点速度。它使用了贴图的RGBA通道,而A通道是用来做乘法,所以称为RGBM格式。
这两种格式的差异就是导致不同平台下lightmap表现不同的原因,当然Unity会在切换平台时帮我们对贴图进行转换,而不需要太关心这个差异。
那么,什么是RGBM呢?就是把[0,1]扩展到[0,8]以表现更高的亮度范围的画面效果,乘数存储在A通道里面,所以RGBM是一种更大范围的颜色编码方式。
接下来很多字不想打了。
………………
坑越填越多……
到此为止,不填了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants