
从游戏中逆向出来的着色器,作用的将256*1像素颜色查找表的颜色还原到灰度贴图上。
调用的 Python 代码是:
import numpy as np from PIL import Image from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * # Load the two input images main_tex = Image.open("main_tex.png") clut = Image.open("clut.png") # Convert the images to numpy arrays and flip the y-axis main_tex_data = np.flip(np.array(main_tex), 0) clut_data = np.flip(np.array(clut), 0) # Create the output image output_image = Image.new("RGB", main_tex.size) output_data = np.array(output_image) # Create the OpenGL window and set up the viewport glutInit(sys.argv) glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) glutInitWindowSize(main_tex.size[0], main_tex.size[1]) glutCreateWindow(b"Shader") glutReshapeFunc(lambda w, h: glViewport(0, 0, w, h)) # Create the texture objects for the input images main_tex_id = glGenTextures(1) clut_id = glGenTextures(1) # Set up the main texture glBindTexture(GL_TEXTURE_2D, main_tex_id) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, main_tex.size[0], main_tex.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, main_tex_data) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) # Set up the CLUT texture glBindTexture(GL_TEXTURE_2D, clut_id) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, clut.size[0], clut.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, clut_data) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) # Create the shader program program_id = glCreateProgram() # Compile the vertex shader vertex_shader = """ #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; } """ vertex_shader_id = glCreateShader(GL_VERTEX_SHADER) glShaderSource(vertex_shader_id, vertex_shader) glCompileShader(vertex_shader_id) # Compile the fragment shader fragment_shader = """ #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(_Mainex, 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; } """ fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER) glShaderSource(fragment_shader_id, fragment_shader) glCompileShader(fragment_shader_id) if vertex_shader_id == 0: print("Error creating vertex shader object") else: # Set the vertex shader source code glShaderSource(vertex_shader_id, vertex_shader) # Compile the vertex shader glCompileShader(vertex_shader_id) # Check if the vertex shader was successfully compiled vertex_compile_status = glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS) if vertex_compile_status != GL_TRUE: # Print the compile log if the vertex shader failed to compile vertex_compile_log = glGetShaderInfoLog(vertex_shader_id) print("Error compiling vertex shader:") print(vertex_compile_log) else: # Create the fragment shader object fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER) # Check if the fragment shader object is valid if fragment_shader_id == 0: print("Error creating fragment shader object") else: # Set the fragment shader source code glShaderSource(fragment_shader_id, fragment_shader) # Compile the fragment shader glCompileShader(fragment_shader_id) # Check if the fragment shader was successfully compiled fragment_compile_status = glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS) if fragment_compile_status != GL_TRUE: # Print the compile log if the fragment shader failed to compile fragment_compile_log = glGetShaderInfoLog(fragment_shader_id) print("Error compiling fragment shader:") print(fragment_compile_log) # else: # # Attach the shaders to the program # glAttachShader(program_id, vertex_shader_id) # glAttachShader(program_id, fragment_shader_id) # Link the program glLinkProgram(program_id) # Create the vertex data vertices = np.array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0], np.float32) tex_coords = np.array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0], np.float32) # Create the vertex buffer object vbo = glGenBuffers(1) # Bind the VBO and upload the vertex data glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW) # Create the texture coordinate buffer object tex_coord_vbo = glGenBuffers(1) # Bind the tex coord VBO and upload the texture coordinate data glBindBuffer(GL_ARRAY_BUFFER, tex_coord_vbo) glBufferData(GL_ARRAY_BUFFER, tex_coords.nbytes, tex_coords, GL_STATIC_DRAW) # Set up the vertex attribute pointers glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, None) glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, None) # Enable the vertex attribute arrays glEnableVertexAttribArray(0) glEnableVertexAttribArray(1) # Bind the main texture to texture unit 0 glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, main_tex_id) # Bind the CLUT texture to texture unit 1 glActiveTexture(GL_TEXTURE1) glBindTexture(GL_TEXTURE_2D, clut_id) # # Set the CLUT texel size uniform # clut_texel_size = np.array([1.0 / clut.size[0], 1.0 / clut.size[1], 1.0 / clut.size[0], 1.0 / clut.size[1]], np.float32) # glUniform4fv(glGetUniformLocation(program_id, "_CLUT_TexelSize"), 1, clut_texel_size) # Compile the shaders glCompileShader(vertex_shader_id) glCompileShader(fragment_shader_id) # Check if the shaders were successfully compiled vertex_compile_status = glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS) fragment_compile_status = glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS) if vertex_compile_status != GL_TRUE or fragment_compile_status != GL_TRUE: # Print the compile logs if the shaders failed to compile vertex_compile_log = glGetShaderInfoLog(vertex_shader_id) fragment_compile_log = glGetShaderInfoLog(fragment_shader_id) print("Error compiling shaders:") print(vertex_compile_log) print(fragment_compile_log) else: # Attach the shaders to the program glAttachShader(program_id, vertex_shader_id) glAttachShader(program_id, fragment_shader_id) # Link the program glLinkProgram(program_id) # Check if the program was successfully linked link_status = glGetProgramiv(program_id, GL_LINK_STATUS) if link_status != GL_TRUE: # Print the link log if the program failed to link link_log = glGetProgramInfoLog(program_id) print("Error linking program:") print(link_log) else: # Activate the program glUseProgram(program_id) # Set the CLUT texel size uniform clut_texel_size = np.array([1.0 / clut.size[0], 1.0 / clut.size[1], 1.0 / clut.size[0], 1.0 / clut.size[1]], np.float32) # Get the uniform location clut_texel_size_loc = glGetUniformLocation(program_id, "_CLUT_TexelSize") # Set the uniform value glUniform4fv(clut_texel_size_loc, 1, clut_texel_size) # Draw the quad glClearColor(0.0, 0.0, 0.0, 1.0) glClear(GL_COLOR_BUFFER_BIT) glUseProgram(program_id) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) # Read back the framebuffer data width = main_tex.width height = main_tex.height # Set the format and type of the pixel data format = GL_RGBA type = GL_UNSIGNED_BYTE # Allocate a buffer to store the pixel data pixels = ctypes.create_string_buffer(width * height * 4) # Read the pixels from the framebuffer glReadPixels(0, 0, width, height, format, type, pixels) # Convert the pixel data to a Python bytearray output_data = bytearray(pixels) # Convert the bytearray to a NumPy array output_data = np.frombuffer(output_data, np.uint8) # Reshape the array to the desired dimensions output_data = output_data.reshape((height, width, 4)) # Create the output image from the NumPy array output_image = Image.fromarray(output_data) # Save the output image as a PNG file output_image.save("output.png") 1 edis0n0 OP 不用了,chatgpt 给我写了个能用的版本 |