让我们考虑一下这个mcve:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import textwrap
from string import Template
def compile(shader_type, source):
identifier = glCreateShader(shader_type)
glShaderSource(identifier, source)
glCompileShader(identifier)
if not glGetShaderiv(identifier, GL_COMPILE_STATUS):
for i, l in enumerate(source.splitlines()):
print(f"{i+1}: {l}")
raise Exception(glGetShaderInfoLog(identifier).decode("utf-8"))
return identifier
def create_program(vs, fs):
vs_identifier = compile(GL_VERTEX_SHADER, vs)
fs_identifier = compile(GL_FRAGMENT_SHADER, fs)
program = glCreateProgram()
glAttachShader(program, vs_identifier)
glAttachShader(program, fs_identifier)
glLinkProgram(program)
if not glGetProgramiv(program, GL_LINK_STATUS):
raise RuntimeError(glGetProgramInfoLog(program))
return program
def set_uniform1f(prog, name, v0):
# print("set_uniform1f", name, glGetUniformLocation(prog, name))
glUniform1f(glGetUniformLocation(prog, name), v0)
def set_uniform1i(prog, name, v0):
# print("set_uniform1i", name, glGetUniformLocation(prog, name))
glUniform1i(glGetUniformLocation(prog, name), v0)
def set_uniform2f(prog, name, v0, v1):
# print("set_uniform2f", name, glGetUniformLocation(prog, name))
glUniform2f(glGetUniformLocation(prog, name), v0, v1)
class Window:
def __init__(self, w, h):
glutInit()
# glutInitContextVersion(3,2) # at least 3.2 is required, you can use a higer version when needed
# glutInitContextProfile(GLUT_CORE_PROFILE)
# glutInitContextFlags(GLUT_FORWARD_COMPATIBLE)
glutSetOption(GLUT_MULTISAMPLE, 16)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE)
glutInitWindowSize(w, h)
glutCreateWindow('Mcve uniforms')
glutReshapeFunc(self.reshape)
glutKeyboardFunc(self.keyboard_func)
glutKeyboardUpFunc(self.keyboard_up_func)
glutDisplayFunc(self.display)
glutIdleFunc(self.idle_func)
self.keys = {chr(i): False for i in range(256)}
# -------- Conflicting shader exposing bug --------
self.MAGIC_CONSTANT = 635
vs_code = textwrap.dedent("""\
void main()
{
gl_Position = ftransform();
}
""")
text = """\
#pragma optimize (off)
uniform vec2 resolution;
$block_declaration
vec3 f(vec2 x) {
x = sin(abs(x * 0.5));
float cs = cos(float($var_name) * 10037.5);
float ss = sin(float($var_name) * 12.5) * 0.09;
float t = sin(float($var_name)) * 0.5 + 0.5;
float d = sin(10. * length(x - vec2(cs, ss)) + mix(8., 10., t));
vec3 color = mix(vec3(0.8,0.86,0.85), vec3(0.52,0.72,0.79), sin(t) * 0.5);
return color*pow(d, 2.) / 5.;
}
void main() {
vec2 uv = (gl_FragCoord.xy / resolution.xy) * 2.0 - 1.0;
uv.x *= (resolution.x / resolution.y);
vec3 col = f(uv);
gl_FragColor = vec4(col*5.0, 1.0);
}
"""
VAR_NAME = "my_time"
fs_code0 = textwrap.dedent(Template(text).substitute(
block_declaration=f"int {VAR_NAME} = {self.MAGIC_CONSTANT};",
var_name=VAR_NAME
))
fs_code1 = textwrap.dedent(Template(text).substitute(
block_declaration=f"uniform int {VAR_NAME};",
var_name=VAR_NAME
))
print("SHADER0".center(80, '-'))
print(fs_code0)
print("SHADER1".center(80, '-'))
print(fs_code1)
# -------- Shader using time uniform --------
self.program0 = create_program(vs_code, fs_code0)
self.program1 = create_program(vs_code, fs_code1)
# -------- Setup --------
s = 1.0
glClearColor(1, 1, 1, 1)
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
glOrtho(-s, s, -s, s, -s, s)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def keyboard_func(self, *args):
self.keys[args[0].decode("utf8")] = True
def keyboard_up_func(self, *args):
self.keys[args[0].decode("utf8")] = False
def display(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
if self.keys['w']:
# Case a) Using uniform
glUseProgram(self.program0)
set_uniform2f(self.program0, "resolution", self.width, self.height)
else:
# Case b) Using constant with same value than uniform
glUseProgram(self.program1)
set_uniform1i(self.program1, "my_time", self.MAGIC_CONSTANT)
set_uniform2f(self.program1, "resolution", self.width, self.height)
s = 0.5
glBegin(GL_QUADS)
glVertex3f(-s, -s, 0)
glVertex3f(s, -s, 0)
glVertex3f(s, s, 0)
glVertex3f(-s, s, 0)
glEnd()
glutSwapBuffers()
def run(self):
glutMainLoop()
def idle_func(self):
glutPostRedisplay()
def reshape(self, w, h):
glViewport(0, 0, w, h)
self.width = w
self.height = h
if __name__ == '__main__':
Window(800, 600).run()
运行后,您会看到生成了这两个片段着色器(您可以通过按“ w”键在它们之间切换):
------------------------------------SHADER0-------------------------------------
#pragma optimize (off)
uniform vec2 resolution;
int my_time = 635;
vec3 f(vec2 x) {
x = sin(abs(x * 0.5));
float cs = cos(float(my_time) * 10037.5);
float ss = sin(float(my_time) * 12.5) * 0.09;
float t = sin(float(my_time)) * 0.5 + 0.5;
float d = sin(10. * length(x - vec2(cs, ss)) + mix(8., 10., t));
vec3 color = mix(vec3(0.8,0.86,0.85), vec3(0.52,0.72,0.79), sin(t) * 0.5);
return color*pow(d, 2.) / 5.;
}
void main() {
vec2 uv = (gl_FragCoord.xy / resolution.xy) * 2.0 - 1.0;
uv.x *= (resolution.x / resolution.y);
vec3 col = f(uv);
gl_FragColor = vec4(col*5.0, 1.0);
}
------------------------------------SHADER1-------------------------------------
#pragma optimize (off)
uniform vec2 resolution;
uniform int my_time;
vec3 f(vec2 x) {
x = sin(abs(x * 0.5));
float cs = cos(float(my_time) * 10037.5);
float ss = sin(float(my_time) * 12.5) * 0.09;
float t = sin(float(my_time)) * 0.5 + 0.5;
float d = sin(10. * length(x - vec2(cs, ss)) + mix(8., 10., t));
vec3 color = mix(vec3(0.8,0.86,0.85), vec3(0.52,0.72,0.79), sin(t) * 0.5);
return color*pow(d, 2.) / 5.;
}
void main() {
vec2 uv = (gl_FragCoord.xy / resolution.xy) * 2.0 - 1.0;
uv.x *= (resolution.x / resolution.y);
vec3 col = f(uv);
gl_FragColor = vec4(col*5.0, 1.0);
}
人们希望两个着色器都给出完全相同的输出。不幸的是,事实并非如此,如果运行这段代码,您将看到两者看起来真的不同:
问题:
主要原因是我想在调整着色器后将统一变量作为着色器中的硬编码值,而不会得到任何不同的结果。
说明可以重现该错误的地方
说明不会显示错误的地方