V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Game Engines
Unreal Engine
MyCryENGINE
edis0n0
V2EX  ›  游戏开发

拆包一游戏的时候发现大部分贴图都是灰度+1~2 张 256*1 像素的颜色查找表,用了名为 ZanLib/ClutBiliniar 的着色器,一点资料都没找到,想写一个 Python 脚本把它转换成彩色, ChatGPT 教了我一晚上没成功

  •  
  •   edis0n0 · 2022-12-24 02:45:21 +08:00 · 2802 次点击
    这是一个创建于 700 天前的主题,其中的信息可能已经有所发展或是发生改变。

    着色器 ZanLib/ClutBiliniar 的其中一个 SubProgram:

    SubProgram "gles hw_tier00 " {
    Keywords { "_TRANSPARENT_OFF" "_DITHERALPHA_OFF" "_VERTEXCOLOR_OFF" "_BLENDFACTOR_OFF" }
    "#ifdef VERTEX
    #version 100
    
    uniform 	vec4 hlslcc_mtx4x4unity_ObjectToWorld[4];
    uniform 	vec4 hlslcc_mtx4x4unity_MatrixVP[4];
    uniform 	vec4 _MainTex_ST;
    uniform 	vec4 _MainTex_TexelSize;
    attribute highp vec4 in_POSITION0;
    attribute highp vec4 in_TEXCOORD0;
    varying mediump vec2 vs_TEXCOORD0;
    varying mediump vec2 vs_TEXCOORD1;
    varying mediump vec2 vs_TEXCOORD2;
    varying mediump vec2 vs_TEXCOORD3;
    varying highp vec2 vs_TEXCOORD4;
    vec4 u_xlat0;
    vec4 u_xlat1;
    vec2 u_xlat4;
    void main()
    {
        u_xlat0 = in_POSITION0.yyyy * hlslcc_mtx4x4unity_ObjectToWorld[1];
        u_xlat0 = hlslcc_mtx4x4unity_ObjectToWorld[0] * in_POSITION0.xxxx + u_xlat0;
        u_xlat0 = hlslcc_mtx4x4unity_ObjectToWorld[2] * in_POSITION0.zzzz + u_xlat0;
        u_xlat0 = u_xlat0 + hlslcc_mtx4x4unity_ObjectToWorld[3];
        u_xlat1 = u_xlat0.yyyy * hlslcc_mtx4x4unity_MatrixVP[1];
        u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[0] * u_xlat0.xxxx + u_xlat1;
        u_xlat1 = hlslcc_mtx4x4unity_MatrixVP[2] * u_xlat0.zzzz + u_xlat1;
        gl_Position = hlslcc_mtx4x4unity_MatrixVP[3] * u_xlat0.wwww + u_xlat1;
        u_xlat4.x = 0.0;
        u_xlat4.y = _MainTex_TexelSize.y;
        u_xlat0.xy = in_TEXCOORD0.xy * _MainTex_ST.xy + _MainTex_ST.zw;
        u_xlat0.xy = (-_MainTex_TexelSize.xy) * vec2(0.5, 0.5) + u_xlat0.xy;
        vs_TEXCOORD1.xy = u_xlat4.xy + u_xlat0.xy;
        vs_TEXCOORD0.xy = u_xlat0.xy;
        u_xlat1.x = _MainTex_TexelSize.x;
        u_xlat1.y = 0.0;
        vs_TEXCOORD2.xy = u_xlat0.xy + u_xlat1.xy;
        vs_TEXCOORD3.xy = u_xlat0.xy + _MainTex_TexelSize.xy;
        vs_TEXCOORD4.xy = u_xlat0.xy * _MainTex_TexelSize.zw;
        return;
    }
    
    #endif
    #ifdef FRAGMENT
    #version 100
    
    #ifdef GL_FRAGMENT_PRECISION_HIGH
        precision highp float;
    #else
        precision mediump float;
    #endif
    precision highp int;
    uniform 	vec4 _CLUT_TexelSize;
    uniform lowp sampler2D _MainTex;
    uniform lowp sampler2D _CLUT;
    varying mediump vec2 vs_TEXCOORD0;
    varying mediump vec2 vs_TEXCOORD1;
    varying mediump vec2 vs_TEXCOORD2;
    varying mediump vec2 vs_TEXCOORD3;
    varying highp vec2 vs_TEXCOORD4;
    #define SV_Target0 gl_FragData[0]
    vec4 u_xlat0;
    lowp float u_xlat10_0;
    vec4 u_xlat1;
    mediump vec4 u_xlat16_1;
    lowp vec4 u_xlat10_1;
    vec4 u_xlat2;
    mediump vec4 u_xlat16_2;
    lowp vec4 u_xlat10_2;
    float u_xlat3;
    lowp vec4 u_xlat10_3;
    vec2 u_xlat8;
    vec2 u_xlat10;
    void main()
    {
        u_xlat10_0 = texture2D(_MainTex, vs_TEXCOORD3.xy).w;
        u_xlat0.x = u_xlat10_0 * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x);
        u_xlat0.x = u_xlat0.x / _CLUT_TexelSize.z;
        u_xlat0.y = float(0.0);
        u_xlat8.y = float(0.0);
        u_xlat10_1 = texture2D(_CLUT, u_xlat0.xy);
        u_xlat10_0 = texture2D(_MainTex, vs_TEXCOORD1.xy).w;
        u_xlat0.x = u_xlat10_0 * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x);
        u_xlat2.x = u_xlat0.x / _CLUT_TexelSize.z;
        u_xlat2.y = float(0.0);
        u_xlat10.y = float(0.0);
        u_xlat10_3 = texture2D(_CLUT, u_xlat2.xy);
        u_xlat16_1 = u_xlat10_1 + (-u_xlat10_3);
        u_xlat0.xy = fract(vs_TEXCOORD4.xy);
        u_xlat1 = u_xlat0.xxxx * u_xlat16_1 + u_xlat10_3;
        u_xlat10_2.x = texture2D(_MainTex, vs_TEXCOORD2.xy).w;
        u_xlat2.x = u_xlat10_2.x * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x);
        u_xlat10.x = u_xlat2.x / _CLUT_TexelSize.z;
        u_xlat10_2 = texture2D(_CLUT, u_xlat10.xy);
        u_xlat10_3.x = texture2D(_MainTex, vs_TEXCOORD0.xy).w;
        u_xlat3 = u_xlat10_3.x * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x);
        u_xlat8.x = u_xlat3 / _CLUT_TexelSize.z;
        u_xlat10_3 = texture2D(_CLUT, u_xlat8.xy);
        u_xlat16_2 = u_xlat10_2 + (-u_xlat10_3);
        u_xlat2 = u_xlat0.xxxx * u_xlat16_2 + u_xlat10_3;
        u_xlat1 = u_xlat1 + (-u_xlat2);
        u_xlat0 = u_xlat0.yyyy * u_xlat1 + u_xlat2;
        SV_Target0.w = ceil(u_xlat0.w);
        SV_Target0.xyz = u_xlat0.xyz;
        return;
    }
    
    #endif
    "
    }
    

    图形学零基础,会写一点 Python 但完全没用过 NumPy ,有 V 友能帮帮忙么?

    附上 ChatGPT 的聊天记录:

    不知道正确率有多少,但能胡编出这么多看起来相关的内容也挺厉害了

    19 条回复    2022-12-26 13:37:46 +08:00
    edis0n0
        1
    edis0n0  
    OP
       2022-12-24 02:47:49 +08:00
    这是我照着 ChatGPT 的指点瞎写的: https://pastebin.com/QEshP61s
    HuPu
        2
    HuPu  
       2022-12-24 08:14:10 +08:00
    挺有意思 如何跟 chatgpt 说话是门学问啊 我感觉我就不太会
    beijiaoff
        3
    beijiaoff  
       2022-12-24 09:27:11 +08:00
    观望一下,感觉目前做不到吧
    musi
        4
    musi  
       2022-12-24 11:03:33 +08:00
    我觉得这你要是 google 你已经写完了
    edis0n0
        5
    edis0n0  
    OP
       2022-12-24 11:17:51 +08:00
    @musi #4 google 了两天,没有找到一点点资料,全是这个公司自己搞的
    ruanimal
        6
    ruanimal  
       2022-12-24 18:15:05 +08:00
    真的有人信 chatGPT 能教人写代码?
    edis0n0
        7
    edis0n0  
    OP
       2022-12-25 11:33:57 +08:00
    @ruanimal #6 还真别说,刚才换了个问法它真写出来能用的了
    edis0n0
        8
    edis0n0  
    OP
       2022-12-25 11:35:59 +08:00
    @HuPu
    @beijiaoff 主要的问题是 chatgpt 输入长度有限,给它太多信息的时候会有一大部分被它忘掉
    c0t
        9
    c0t  
       2022-12-25 13:06:40 +08:00 via Android   ❤️ 1
    贴出来的代码没什么难度啊...很字面意思,voxel 类的游戏全是这样的贴图
    c0t
        10
    c0t  
       2022-12-25 13:10:44 +08:00 via Android   ❤️ 1
    @c0t 不过你可能首先得知道比如 unity 里的 texelsize 这种语义里惯例存的是啥,不知道 chatgpt 有这种知识没有
    edis0n0
        11
    edis0n0  
    OP
       2022-12-25 13:26:17 +08:00
    @c0t #10 我 google 了一下 texelsize 存的应该是 (1/width, 1/height, width, height),所以 chatgpt 输出的有点错了

    它说的逻辑我简化了下貌似就是根据 index 图的 alpha 值去 clut 取对应点颜色,自己写了一遍:

    import numpy as np
    from skimage import io

    index_image = io.imread('index.png')
    clut_image = io.imread('clut.png')
    x_coord = index_image[:, :, 3]
    y_coord = np.zeros_like(x_coord)
    clut_colors = clut_image[y_coord.astype(int), x_coord.astype(int), :]
    io.imsave('output.png', clut_colors)

    貌似输出结果还很正常,不知道有没有漏了什么东西
    edis0n0
        12
    edis0n0  
    OP
       2022-12-25 13:32:48 +08:00
    @c0t #10 google 到的那贴子说的是 1/width 是从 unity 源码看到的,那-_CLUT_TexelSize.x 应该是一个接近 0 的值,因为我看后面是根据它的值去对应位置取数据,那应该是按 int 处理,小数部分没有意义,那我就直接按 0 处理了。不知道为什么原始的 GL 代码会这么长,总觉得我简化逻辑的时候搞错了什么,一直没看出来,请大佬再帮忙分析下。
    c0t
        13
    c0t  
       2022-12-25 18:15:32 +08:00   ❤️ 1
    @edis0n0
    因为采样了四个像素(大概这么理解就好)吧?不过不用模型 uv 的话,loop main texture 解码出来的结果可能没啥意义?可能是很多个模型公用了一张 main texture 。

    上一半 vertex shader 里输出到 frag shader 里的东西:

    // four pixel
    // 0 2
    // 1 3
    varying mediump vec2 vs_TEXCOORD0; // texture sample position
    varying mediump vec2 vs_TEXCOORD1; // texture sample position + (0,1/height), pixel below
    varying mediump vec2 vs_TEXCOORD2; // texture sample positin + (1/width,0), next pixel
    varying mediump vec2 vs_TEXCOORD3; // texture sample position + (1/width,1/height),
    varying highp vec2 vs_TEXCOORD4; // texture sample position in pixel
    c0t
        14
    c0t  
       2022-12-25 18:24:15 +08:00   ❤️ 1
    @edis0n0
    然后 frag shader 里,从四个 alpha 值得到四个像素颜色,然后做一次 bilinear interpolation ,大概就是这样
    c0t
        15
    c0t  
       2022-12-25 18:26:21 +08:00   ❤️ 1
    @c0t ClutBiliniar 这个名字就是 color lookup bilinear 的意思吧
    c0t
        16
    c0t  
       2022-12-25 18:56:33 +08:00   ❤️ 1
    @edis0n0
    texture2D 是用 uv 坐标采样的,所以不是整数

    (-_CLUT_TexelSize.x); 这个不太好说,主要是看 main texture 里存的到底是什么?可能和生成图片方式有关系吧?不过好像确实有点奇怪:

    u_xlat10_0 = texture2D(_MainTex, vs_TEXCOORD1.xy).w;
    u_xlat0.x = u_xlat10_0 * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x);
    u_xlat2.x = u_xlat0.x / _CLUT_TexelSize.z;
    u_xlat2.y = float(0.0);
    u_xlat10_3 = texture2D(_CLUT, u_xlat2.xy);

    没搞懂意义,u_xlat10_0 * _CLUT_TexelSize.z + (-_CLUT_TexelSize.x); 照理来说,这个式子两边都不是一个单位的啊,u_xlat10_0 * _CLUT_TexelSize.z 单位是 pixel ,(-_CLUT_TexelSize.x); 这个是 1/pixel ,最终除一个 _CLUT_TexelSize.z 之后,这个部分也几乎没作用了
    edis0n0
        17
    edis0n0  
    OP
       2022-12-25 19:53:38 +08:00
    @c0t 谢谢大佬指点。刚 google 了下插值算法一般用于放大图片,请问这个 bilinear interpolation 是还有放大图片的作用么? main texture 存的是一张只有 alpha 通道有数据的游戏背景图,vertex shader 中没看出还有放大的代码以及倍数一类的信息。如果倍数是 1.0 的话是不是相当于可以不用考虑?它和 opencv 的 cv2.resize()插值效果有差异么?
    c0t
        18
    c0t  
       2022-12-25 20:13:15 +08:00
    @edis0n0
    嗯嗯,背景图的话就是单纯的放大的时候,平滑像素用的了,不会有一块一块的情况。比例一样就无所谓了。你上面代码应该直接用就好。

    那这个功能就是为了节约存储空间,原本图形硬件上是自带插值的,分了两张贴图没法用了

    看了 cv2.resize() 的说明,默认就是线性插值,应该没有差异
    cherryas
        19
    cherryas  
       2022-12-26 13:37:46 +08:00
    小心 chatgpt 投毒.

    我问了个 vits 模型怎么写,给我编的有模有样的,怎么导包,方法名是什么.都像那回事.

    折腾了一会我发现 python 根本没 vits 这个包.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2915 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 08:02 · PVG 16:02 · LAX 00:02 · JFK 03:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.