Pyopengl 纹理渲染不正确,对象填充纯灰色
Pyopengl textures not rendering properly, object filled solid gray
我正在尝试将纹理(png 图像文件)添加到正在渲染的矩形中。但是,无论我使用什么图像,该对象都显示为灰色。我有一种感觉,我缺少与 tetxure 坐标有关的东西。在顶点缓冲区的每一行中,前两个数字代表 x 和 y 坐标,而后两个数字代表纹理坐标。
大多数在线回答表明图像数据传递到纹理中存在问题,或者未正确绑定。
from OpenGL.GL import *
import glfw
import numpy
import sys
from PIL import Image
class Shader:
def readshader(self, Title, filepath):
#reads shader (This works so I have removed it for ease of reading)
def CreateShader(self, filepath):
program = glCreateProgram()
VERT = self.readshader("VERTEX", filepath)
vertShader = glCreateShader(GL_VERTEX_SHADER)
self.Compileshader(vertShader, VERT, program, "Vertex")
FRAG = self.readshader("FRAGMENT", filepath)
fragShader = glCreateShader(GL_FRAGMENT_SHADER)
self.Compileshader(fragShader, FRAG, program, "Fragment")
glLinkProgram(program)
glValidateProgram(program)
glDeleteShader(vertShader)
glDeleteShader(fragShader)
return program
def Compileshader(self, shader, shaderstring, program, type):
glShaderSource(shader, shaderstring)
glCompileShader(shader)
status = glGetShaderiv(shader, GL_COMPILE_STATUS)
if not status:
info = glGetShaderInfoLog(shader)
print("Error in " + type + " Shader:")
print(info.decode("utf-8"))
glDeleteShader(shader)
else:
glAttachShader(program, shader)
class Renderer:
def __init__(self):
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
self.buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
self.ibo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
def AttachTexture(self, NewTexture, Width, Height, Uniform, value):
glEnable(GL_TEXTURE_2D)
self.Texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.Texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NewTexture)
glGenerateMipmap(GL_TEXTURE_2D); ##new
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 16, None) ##new
glEnableVertexAttribArray(2) ##new
glBindTexture(GL_TEXTURE_2D, self.Texture) #new
glActiveTexture(GL_TEXTURE0 + value)
location = glGetUniformLocation(self.program, Uniform)
glUniform1i(location, value)
def AttachShader(self, program):
self.program = program
glUseProgram(self.program)
def GetUniformLocation(self, Uniform, r, g, b):
location = glGetUniformLocation(self.program, Uniform)
glUniform4f(location, r, g, b, 1.0)
def ArrayBufferData(self, positions):
glBufferData(GL_ARRAY_BUFFER, positions, GL_STATIC_DRAW)
def IndexBufferData(self, indices):
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
def Unbind(self):
glBindVertexArray(0)
glUseProgram(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
def Bind(self):
glBindVertexArray(self.vao)
glUseProgram(self.program)
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
def DrawElements(self, length):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glDrawElements(GL_TRIANGLES, length, GL_UNSIGNED_INT, None)
def main():
TextureA = Image.open("Textures\Texture Test 2019.08.12 01.58.png").transpose(Image.FLIP_TOP_BOTTOM)
Texture = numpy.frombuffer(TextureA.tobytes(), numpy.uint8)
Width, Height = TextureA.size
name = "OpenGL Testing"
if not glfw.init():
return
window = glfw.create_window(640, 480, "Hello World", None, None)
if not window:
glfw.terminate()
glfw.make_context_current(window)
glfw.swap_interval(1)
NewShader = Shader()
program = NewShader.CreateShader("Shaders\Complete Shader 2019.08.12 02.41.txt")
NewBuffer = Renderer()
NewBuffer.AttachShader(program)
positions = numpy.array([-0.5, -0.5, 0.0, 0.0\
,0.5, -0.5, 1.0, 0.0\
,0.5, 0.5, 1.0, 1.0\
,-0.5, 0.5, 0.0, 1.0]\
,dtype = 'float32')
indices = numpy.array([0, 1, 2,\
2, 3, 0]\
,dtype = 'int32')
NewBuffer.ArrayBufferData(positions)
NewBuffer.IndexBufferData(indices)
red = 0.0
increment = 0.05
while not glfw.window_should_close(window):
NewBuffer.Bind()
if red > 1.0:
increment = -0.05
elif red < 0.0:
increment = 0.05
red += increment
NewBuffer.GetUniformLocation("u_Color", red, 0.3, 0.8)
NewBuffer.DrawElements(len(indices))
NewBuffer.AttachTexture(Texture, Width, Height, "u_Texture", 0)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
if __name__ == '__main__': main()
#For reference here is the vertex and fragment shader I am using:
"""
@VERTEX
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_TexCoord;
void main()
{
gl_Position = position;
v_TexCoord = texCoord;
};
@FRAGMENT
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform vec4 u_Color;
uniform sampler2D u_Texture;
void main()
{
vec4 texColor = texture(u_Texture, v_TexCoord);
color = texColor;
};
"""
我认为您需要一个偏移量 8 作为第二个 glVertexAttribPointer 的最后一个参数,它定义了纹理坐标。
您使用的是交错数组,其中顶点坐标后跟 tex 坐标,对吗?因此,第一个属性指针将顶点坐标定义为 2 个浮点数,相隔 16 个字节(4 x 浮点数),从缓冲区的字节 0 开始。第二个属性指针将纹理坐标定义为 2 个浮点数,相隔 16 个字节,也 从缓冲区的字节 0 开始。所以顶点坐标被重新用作纹理坐标。
纹理坐标的属性索引为1:
layout(location = 1) in vec2 texCoord;
因此,当您指定并启用通用顶点属性数组时,属性索引也必须为 1。参见 glVertexAttribPointer
respectively glEnableVertexAttribArray
。
绑定命名缓冲区对象时,glVertexAttribPointer
的最后一个参数被视为缓冲区对象数据存储中的字节偏移量。
缓冲区的内容是顶点坐标,然后是2个纹理坐标:
x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2, ...
每个组件的大小为 4(大小为 float
),因此步幅为 16 = 4*4。
顶点坐标的偏移量为0,偏移纹理坐标为8=2*4.
由于 glVertexAttribPointer
is const GLvoid *
you've to cast the parameter to ctypes.c_void_p
的偏移量(最后一个)参数类型:
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, c_void_p(0))
如果偏移量为0,可以用None
代替:
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
在指定通用顶点属性数据数组之前绑定缓冲区,设置适当的属性索引和偏移量:
from ctypes import c_void_p
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16, c_void_p(8))
我正在尝试将纹理(png 图像文件)添加到正在渲染的矩形中。但是,无论我使用什么图像,该对象都显示为灰色。我有一种感觉,我缺少与 tetxure 坐标有关的东西。在顶点缓冲区的每一行中,前两个数字代表 x 和 y 坐标,而后两个数字代表纹理坐标。
大多数在线回答表明图像数据传递到纹理中存在问题,或者未正确绑定。
from OpenGL.GL import *
import glfw
import numpy
import sys
from PIL import Image
class Shader:
def readshader(self, Title, filepath):
#reads shader (This works so I have removed it for ease of reading)
def CreateShader(self, filepath):
program = glCreateProgram()
VERT = self.readshader("VERTEX", filepath)
vertShader = glCreateShader(GL_VERTEX_SHADER)
self.Compileshader(vertShader, VERT, program, "Vertex")
FRAG = self.readshader("FRAGMENT", filepath)
fragShader = glCreateShader(GL_FRAGMENT_SHADER)
self.Compileshader(fragShader, FRAG, program, "Fragment")
glLinkProgram(program)
glValidateProgram(program)
glDeleteShader(vertShader)
glDeleteShader(fragShader)
return program
def Compileshader(self, shader, shaderstring, program, type):
glShaderSource(shader, shaderstring)
glCompileShader(shader)
status = glGetShaderiv(shader, GL_COMPILE_STATUS)
if not status:
info = glGetShaderInfoLog(shader)
print("Error in " + type + " Shader:")
print(info.decode("utf-8"))
glDeleteShader(shader)
else:
glAttachShader(program, shader)
class Renderer:
def __init__(self):
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
self.buffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
self.ibo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
def AttachTexture(self, NewTexture, Width, Height, Uniform, value):
glEnable(GL_TEXTURE_2D)
self.Texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.Texture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NewTexture)
glGenerateMipmap(GL_TEXTURE_2D); ##new
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 16, None) ##new
glEnableVertexAttribArray(2) ##new
glBindTexture(GL_TEXTURE_2D, self.Texture) #new
glActiveTexture(GL_TEXTURE0 + value)
location = glGetUniformLocation(self.program, Uniform)
glUniform1i(location, value)
def AttachShader(self, program):
self.program = program
glUseProgram(self.program)
def GetUniformLocation(self, Uniform, r, g, b):
location = glGetUniformLocation(self.program, Uniform)
glUniform4f(location, r, g, b, 1.0)
def ArrayBufferData(self, positions):
glBufferData(GL_ARRAY_BUFFER, positions, GL_STATIC_DRAW)
def IndexBufferData(self, indices):
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW)
def Unbind(self):
glBindVertexArray(0)
glUseProgram(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
def Bind(self):
glBindVertexArray(self.vao)
glUseProgram(self.program)
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ibo)
def DrawElements(self, length):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glDrawElements(GL_TRIANGLES, length, GL_UNSIGNED_INT, None)
def main():
TextureA = Image.open("Textures\Texture Test 2019.08.12 01.58.png").transpose(Image.FLIP_TOP_BOTTOM)
Texture = numpy.frombuffer(TextureA.tobytes(), numpy.uint8)
Width, Height = TextureA.size
name = "OpenGL Testing"
if not glfw.init():
return
window = glfw.create_window(640, 480, "Hello World", None, None)
if not window:
glfw.terminate()
glfw.make_context_current(window)
glfw.swap_interval(1)
NewShader = Shader()
program = NewShader.CreateShader("Shaders\Complete Shader 2019.08.12 02.41.txt")
NewBuffer = Renderer()
NewBuffer.AttachShader(program)
positions = numpy.array([-0.5, -0.5, 0.0, 0.0\
,0.5, -0.5, 1.0, 0.0\
,0.5, 0.5, 1.0, 1.0\
,-0.5, 0.5, 0.0, 1.0]\
,dtype = 'float32')
indices = numpy.array([0, 1, 2,\
2, 3, 0]\
,dtype = 'int32')
NewBuffer.ArrayBufferData(positions)
NewBuffer.IndexBufferData(indices)
red = 0.0
increment = 0.05
while not glfw.window_should_close(window):
NewBuffer.Bind()
if red > 1.0:
increment = -0.05
elif red < 0.0:
increment = 0.05
red += increment
NewBuffer.GetUniformLocation("u_Color", red, 0.3, 0.8)
NewBuffer.DrawElements(len(indices))
NewBuffer.AttachTexture(Texture, Width, Height, "u_Texture", 0)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
if __name__ == '__main__': main()
#For reference here is the vertex and fragment shader I am using:
"""
@VERTEX
#version 330 core
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_TexCoord;
void main()
{
gl_Position = position;
v_TexCoord = texCoord;
};
@FRAGMENT
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform vec4 u_Color;
uniform sampler2D u_Texture;
void main()
{
vec4 texColor = texture(u_Texture, v_TexCoord);
color = texColor;
};
"""
我认为您需要一个偏移量 8 作为第二个 glVertexAttribPointer 的最后一个参数,它定义了纹理坐标。
您使用的是交错数组,其中顶点坐标后跟 tex 坐标,对吗?因此,第一个属性指针将顶点坐标定义为 2 个浮点数,相隔 16 个字节(4 x 浮点数),从缓冲区的字节 0 开始。第二个属性指针将纹理坐标定义为 2 个浮点数,相隔 16 个字节,也 从缓冲区的字节 0 开始。所以顶点坐标被重新用作纹理坐标。
纹理坐标的属性索引为1:
layout(location = 1) in vec2 texCoord;
因此,当您指定并启用通用顶点属性数组时,属性索引也必须为 1。参见 glVertexAttribPointer
respectively glEnableVertexAttribArray
。
绑定命名缓冲区对象时,glVertexAttribPointer
的最后一个参数被视为缓冲区对象数据存储中的字节偏移量。
缓冲区的内容是顶点坐标,然后是2个纹理坐标:
x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2, ...
每个组件的大小为 4(大小为 float
),因此步幅为 16 = 4*4。
顶点坐标的偏移量为0,偏移纹理坐标为8=2*4.
由于 glVertexAttribPointer
is const GLvoid *
you've to cast the parameter to ctypes.c_void_p
的偏移量(最后一个)参数类型:
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, c_void_p(0))
如果偏移量为0,可以用None
代替:
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
在指定通用顶点属性数据数组之前绑定缓冲区,设置适当的属性索引和偏移量:
from ctypes import c_void_p
glBindBuffer(GL_ARRAY_BUFFER, self.buffer)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 16, None)
glEnableVertexAttribArray(1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 16, c_void_p(8))