十字军之王吧 关注:171,819贴子:4,657,635

【长期不定期更新】CK2图像算法修改教程——如何DIY地图美化

只看楼主收藏回复



RT。InheavenGraphic大概是最近比较火的一个地图美化MOD,但我个人对他地图缩小以后的效果不是很满意。在把他移植到自定义地图有MOD时顺便研究了下他的算法,并做了些改进。这个地图还没有完成所以对乱码别太在意,这篇帖子的重点是图像效果而不是地图,有机会的话关于地图绘制会新开帖。2L和楼中楼为索引目录请勿回复。
以下正文
-------------------------------------------------------------------------------------------------------------------------------------------------------
【0】文件系统
所有涉及图像算法的文件在gfx/FX目录文夹下,有两种格式
*.fxh-定义常数和一些基本算法的函数。
*.lua-具体的图像生成脚本
具体的命名简单明了,比如river.lua, portrait.lua分别是处理河流和人物头像的
本教程(至少前几张)将主要关注standardfuncsgfx.fxhs——大量的基本函数,pdxmap.lua地图算法


IP属地:美国1楼2018-12-28 23:36回复
    2L目录见楼中楼


    IP属地:美国2楼2018-12-28 23:37
    收起回复
      你这镇楼图跟细胞一样,绝了


      IP属地:四川来自Android客户端3楼2018-12-28 23:49
      回复
        你们又残害密恐人士


        IP属地:广东4楼2018-12-28 23:58
        回复
          【0】-2 续上文
          【1】什么是图形混合算法,如何增加图形算法。
          CK2除了地形地图外的任何模式都是由一张颜色图和地形图叠加而成的。
          以我这地图为例,两张图单独看分别是这样

          地形图

          政治地图,由于MOD还没做完暂时都是一地伯爵。(这个是改了算法刷出来的100%基本色)
          为了让两场图生成我们要的界面,CK2会调用一个可编辑的脚本。但我们还没讨论到那。类比的话这个脚本可以看作是一条生产线,通过一大段工序把两张图合在一起,而每个工序就是一个函数。
          CK2 原版的最终输出脚本是这样的(节选)
          sample.rgb = GetOverlay( sample.rgb,TerrainColor,0.5f);
          float2 vBlend = float2(0.4f,0.45f);
          vOut = ( dot(sample.rgb, GREYIFY) *vBlend.x + terrain_color.rgb * vBlend.y );
          如果你看不懂这一坨,没关系。只要注意到第一行有一个GetOverlay(xx,xx,xx) 这就是一个基本算法—叠加(用过PS的都知道)。
          由于P社是著名的蠢驴,sample.rgb实际上是地形,TerrainColor,反而是颜色图
          GetOverlay( sample.rgb, TerrainColor,0.5f)就是在sample上以50%的透明度叠加TerrainColor
          如果只是简单的(100%,不做其他处理)叠加,效果是这样。具体算法这里不展开讨论

          另一个常用的算法是简单的Blend,效果相当于在一个图像上直接半透明地覆盖上另一张图。可以看到在上述脚本最后一行也出现了 简单的Blend效果如下图(相当于PS图层不透明度)

          在利用这些“工序”编出一个生产流程前,如果你觉得“这不够,我还想其他高级的选择”,比如PS里的“滤色”,“柔光”等,那就要手动定义新的函数了。
          这些函数的定义在standardfuncsgfx.FXH里
          我们可以找到这些行:
          float3 GetOverlay( float3 vColor, float3vOverlay, float vOverlayPercent )
          {
          float3res;
          res.r= vOverlay.r < .5 ? (2 * vOverlay.r * vColor.r) : (1 - 2 * (1 - vOverlay.r) *(1 - vColor.r));
          res.g= vOverlay.g < .5 ? (2 * vOverlay.g * vColor.g) : (1 - 2 * (1 - vOverlay.g)* (1 - vColor.g));
          res.b= vOverlay.b < .5 ? (2 * vOverlay.b * vColor.b) : (1 - 2 * (1 - vOverlay.b)* (1 - vColor.b));
          returnlerp( vColor, res, vOverlayPercent );
          }
          这是关于叠加的定义, 简化来说就是
          两张图A,B叠加,结果为C,对于某一像素
          B<=0.5: C=2*A*B
          B>0.5: C=1-2*(1-A)*(1-B)
          为了给后续工作做准备,这里lz把PS常用的滤色和柔光算法加上
          百度得算法为
          滤色
          C=1-(1-A)*(1-B)
          柔光
          A<=0.5:C=(2*A-1)*(B-B*B)+B
          A>0.5: C=(2*A-1)*(sqrt(B)-B)+B
          按照上面格式照抄,就有了
          float3 GetsFilter( float3 vColorA, float3vColorB, float vOverlayPercent )
          {
          float3res;//定义一个由三个浮点数组成的变量res
          res.r= 1-(1-vColorA.r)*(1-vColorB.r);
          res.g= 1-(1-vColorA.g)*(1-vColorB.g);
          res.b= 1-(1-vColorA.b)*(1-vColorB.b);
          //根据滤色算法对RGB通道分别处理图像,并给res赋值,这样res就是处理过后的图像
          returnlerp( vColorA, res, vOverlayPercent );//lerp是图像的简单混合,这里是把res按照vOverlayPercent的透明的覆盖到原图上,用来控制滤色混合的强度
          }
          对于柔光:
          float3 GetsSoftlight( float3 vColorA,float3 vColorB, float vOverlayPercent )
          {
          float3res;
          res.r=vColorA.r < .5 ?( (2*vColorA.r-1)*(vColorB.r-vColorB.r*vColorB.r)+vColorB.r):((2*vColorA.r-1)*(sqrt(vColorB.r)-vColorB.r)+vColorB.r);
          res.g=vColorA.g < .5 ?((2*vColorA.g-1)*(vColorB.g-vColorB.g*vColorB.g)+vColorB.g):((2*vColorA.g-1)*(sqrt(vColorB.g)-vColorB.g)+vColorB.g);
          res.b=vColorA.b < .5 ?( (2*vColorA.b-1)*(vColorB.b-vColorB.b*vColorB.b)+vColorB.b):((2*vColorA.b-1)*(sqrt(vColorB.b)-vColorB.b)+vColorB.b);
          returnlerp( vColorA, res, vOverlayPercent );
          }
          这时候我们就可以在脚本里和自带的Overlay一样调用了,如
          vOut =GetsFilter(sample.rgb,terrain_color.rgb,1.0f);//100%滤色

          或者vOut = GetsSoftlight(sample.rgb,terrain_color.rgb,1.0f);//100%柔光
          可以说顾名思义就是柔和版的Overlay。

          和Overlay(下图对比)

          想要其他叠加效果的可以依此类推,算法网上可以找到。
          ---------------------------------------------【1】完


          IP属地:美国5楼2018-12-29 00:34
          回复(2)
            厉害,完全看不懂


            IP属地:山东来自Android客户端6楼2018-12-29 00:41
            回复
              所以说你考虑出一个改善InHeaven的mod吗?我相信有很多人需要。


              IP属地:上海来自iPhone客户端7楼2018-12-29 16:21
              回复
                【2】 图像混合脚本

                一直等到地图画完了再更新,密恐患者可以不用害怕了。
                地图的混合脚本如上文所说在pdxmap.lua, 相当于一个“工序描述”把上面定义的一连串函数进行组合。
                游戏生成两张图后,就会按照这个脚本将颜色叠加到基础的地形图上。
                Inheavn 原本的最终输出脚本是这样, 我加了注释方便理解
                float testCam = ( ( vCamPos.y - WATER_HEIGHT ) * .004f );
                //获取摄像机相对睡眠高度,*0.004后定义为变量TestCam
                float colorRange = 1.0f;
                //定义变量colorRange为1.0
                if ( testCam < 1.0f )
                {
                colorRange = testCam ;
                }
                //如果testCam小于1.0,则把其数值传递给colorRange.
                //这一段简而言之就是作者想要通过摄像机的高度来算出颜色混合的强度,但又不想让颜色太过所以设置了1.0的上限。
                colorRange = .4f * colorRange + .05f;
                //对colorRange进行处理(*0.4后+0.5)这是为了防止摄像机太低颜色太淡,这样就把原来0-1的值按比例变换到0.5-0.9
                float2 vBlend = float2( .95f - colorRange , colorRange);
                vOut = sample.rgb*vBlend.x+terrain_color.rgb*vBlend.y
                //把颜色按算出来的透明度叠上去。
                理论上这样的结果是:
                1.颜色叠加的强度根据摄像机高度变化,越低图像越接近纯地形图,越高越接近纯颜色图
                2.这种变化有50%的下限和90%的上限,保证摄像机最低也能看出国家颜色,最高也能看到一定的地形。
                然而这时候我们可以发现一些问题
                1.由于图像没有用上混合算法,只是简单的覆盖,导致摄像机过高时候地形图几乎不存在
                2.图像结果受国家颜色影响太大,随机世界或者随机世界生成器可能会翻车
                理想很美好,但是现实:

                显然这种算法并不能很好的处理过暗的颜色,注意在原版的问题是颜色过亮,因此不同地图改的方法不一样。这里我要调亮些,修改后代码入下
                float filterCam = ( ( vCamPos.y+200 - WATER_HEIGHT ) * .001f );
                //在获取摄像机相对睡眠高度时直接给他加了200,直接省去颜色范围变换的麻烦
                //同时*0.004改为了0.001,这样颜色强度对摄像机变化更为敏感
                if ( filterCam > 0.85f )
                {
                filterCam= 0.85f ;
                }
                if ( filterCam < 0.25f )
                {
                filterCam= 0.25f ;
                }
                //简单的掐头去尾操作,上限85%,下限25%
                vOut = GetsFilter(sample.rgb,terrain_color.rgb,filterCam);
                //采用我们上面增加的滤色算法,他的好处是由于而不是简单的叠加, 即使100%也能看到地形图的影响。此外这种算法类似于把彩色的光打到地形图上,所以颜色肯定亮些




                想要处理原版过量的问题,用类似的方法调低亮度即可
                【2】完


                IP属地:美国8楼2019-01-03 00:02
                回复
                  标记一下,很有趣的东西


                  IP属地:山西10楼2019-06-23 17:51
                  回复
                    这个坟我怎么没见过


                    IP属地:云南来自iPhone客户端11楼2019-06-23 18:31
                    回复
                      大佬厉害了,学习了下,我开始想把这个mod移植到eu4上,可惜standard文件我完全看不懂,目前只把水面效果成功移植到eu4里面了。


                      IP属地:江苏来自iPhone客户端12楼2019-08-20 19:51
                      回复
                        楼主的想法我明白了,你是想修正原版地图的颜色和地形显示效果,想让两者结合,在正治地图模式,能看到不是很刺眼的颜色区分,又能看到地形地貌,放大后又不会因为地形地势清晰导致颜色模糊。


                        IP属地:北京来自iPhone客户端13楼2019-09-12 20:01
                        回复
                          6666坐等发布


                          IP属地:广东14楼2019-09-12 21:32
                          回复
                            懒人社做CK3(X)
                            自己做CK3(√)


                            15楼2019-09-12 22:03
                            回复