从游戏中逆向出来的着色器,作用的将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(_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;
}
"""
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")
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.