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

2022-12-24 02:45:21 +08:00
 edis0n0

着色器 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 的聊天记录:

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

2798 次点击
所在节点    游戏开发
19 条回复
edis0n0
2022-12-24 02:47:49 +08:00
这是我照着 ChatGPT 的指点瞎写的: https://pastebin.com/QEshP61s
HuPu
2022-12-24 08:14:10 +08:00
挺有意思 如何跟 chatgpt 说话是门学问啊 我感觉我就不太会
beijiaoff
2022-12-24 09:27:11 +08:00
观望一下,感觉目前做不到吧
musi
2022-12-24 11:03:33 +08:00
我觉得这你要是 google 你已经写完了
edis0n0
2022-12-24 11:17:51 +08:00
@musi #4 google 了两天,没有找到一点点资料,全是这个公司自己搞的
ruanimal
2022-12-24 18:15:05 +08:00
真的有人信 chatGPT 能教人写代码?
edis0n0
2022-12-25 11:33:57 +08:00
@ruanimal #6 还真别说,刚才换了个问法它真写出来能用的了
edis0n0
2022-12-25 11:35:59 +08:00
@HuPu
@beijiaoff 主要的问题是 chatgpt 输入长度有限,给它太多信息的时候会有一大部分被它忘掉
c0t
2022-12-25 13:06:40 +08:00
贴出来的代码没什么难度啊...很字面意思,voxel 类的游戏全是这样的贴图
c0t
2022-12-25 13:10:44 +08:00
@c0t 不过你可能首先得知道比如 unity 里的 texelsize 这种语义里惯例存的是啥,不知道 chatgpt 有这种知识没有
edis0n0
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
2022-12-25 13:32:48 +08:00
@c0t #10 google 到的那贴子说的是 1/width 是从 unity 源码看到的,那-_CLUT_TexelSize.x 应该是一个接近 0 的值,因为我看后面是根据它的值去对应位置取数据,那应该是按 int 处理,小数部分没有意义,那我就直接按 0 处理了。不知道为什么原始的 GL 代码会这么长,总觉得我简化逻辑的时候搞错了什么,一直没看出来,请大佬再帮忙分析下。
c0t
2022-12-25 18:15:32 +08:00
@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
2022-12-25 18:24:15 +08:00
@edis0n0
然后 frag shader 里,从四个 alpha 值得到四个像素颜色,然后做一次 bilinear interpolation ,大概就是这样
c0t
2022-12-25 18:26:21 +08:00
@c0t ClutBiliniar 这个名字就是 color lookup bilinear 的意思吧
c0t
2022-12-25 18:56:33 +08:00
@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
2022-12-25 19:53:38 +08:00
@c0t 谢谢大佬指点。刚 google 了下插值算法一般用于放大图片,请问这个 bilinear interpolation 是还有放大图片的作用么? main texture 存的是一张只有 alpha 通道有数据的游戏背景图,vertex shader 中没看出还有放大的代码以及倍数一类的信息。如果倍数是 1.0 的话是不是相当于可以不用考虑?它和 opencv 的 cv2.resize()插值效果有差异么?
c0t
2022-12-25 20:13:15 +08:00
@edis0n0
嗯嗯,背景图的话就是单纯的放大的时候,平滑像素用的了,不会有一块一块的情况。比例一样就无所谓了。你上面代码应该直接用就好。

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

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

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

折腾了一会我发现 python 根本没 vits 这个包.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/904401

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX