如何解决如何加快pyglet渲染速度?
下面是渲染代码。我只渲染了约300个块,但速度很慢
async def render(self):
time_start = time.time()
self.batch = pyglet.graphics.Batch()
for block in self.blocks_to_be_rendered:
self.draw_block(block)
print("Time to render 1 chunk " + str(time_start-time.time()))
def Create_chunk(cx,cz):
thr = threading.Thread(target=_Create_chunk,args=(cx,cz))
thr.start()
thr.join()
asyncio.run(Chunks[cx][cz].render())
def draw_block(self,block):
position = (block.x,block.y,block.z)
if block._type == "grass":
block = Grass
else:
print("HOLD ON A SEC")
block = Grass
vertices = get_vertices(*position)
faces = ("left","right","top","bottom","front","back")
for vertex,face in zip(vertices,faces):
self.batch.add(
4,gl.GL_QUADS,block.textures[face],("v3f/static",vertex),("t2f/static",(0,1,1)),
我尝试将“ render”作为异步函数运行,因为渲染每个块需要0.3秒!!!! 这意味着fps接近0
任何对优化/关键缺陷的帮助将不胜感激!
编辑:这段代码可能没有意义,因为我将它与主要代码拼接起来会很长,但是这里只是以防万一:
import pyglet
from pyglet.gl import *
from pyglet.window import key
from pyglet import gl,window
import math
import numpy as np
import random
import noise
import threading
import asyncio
from multiprocessing import Pool
import time
#AVOID FROM KEEPING GL FUNCTIONS IN CLASS BLOCK AND CLASS CHUNK BECAUSE THESE WILL BE EXECUTED FROM A DIFFERENT THREAD
def get_tex(file):
tex = pyglet.image.load(file).get_texture()
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST)
return pyglet.graphics.TextureGroup(tex)
def make_textures(textures):
result = {}
base = "imgs/"
faces = ("left","back")
for face in faces:
file_name = textures.get(face,textures.get("side"))
result[face] = get_tex(base + file_name)
return result
def get_vertices(x,y,z):
dx,dy,dz = x + 1,y + 1,z + 1
return [
(x,z,x,dz,z),# side
(dx,dx,dz),# side
(x,# top
(x,# bottom
(dx,# side
]
class Grass:
textures = make_textures({"side": "grass_side.png","top": "grass_top.png","bottom": "dirt.png"})
class Block():
def __init__(self,z):
#for testing sake _type = dirt
self._type = "grass"
self.x = x
self.y = y
self.z = z
self.width = 1
self.height = 1
self.length = 1
np.seed = random.randint(1,10000)
Chunks = {-1:{},0:{},1:{}}
class Chunk():
def prepare_for_rendering(self):
#Im too lazy to do actual faces so i will only render the nesecary blocks
#MUST BE DONE IN A DIFFERENT THREAD OR FPS = -1
time_start = time.time()
self.blocks_to_be_rendered = []
for x in range(0,16):
for z in range(0,16):
#Gives us an unspecified length dictionary
for key in self.Chunk_blocks[x][z].keys():
#key is an integer
#block is Chunk_blocks[x][z][key]
try:
if self.Chunk_blocks[x-1][z][key] and self.Chunk_blocks[x+1][z][key] and self.Chunk_blocks[x][z+1][key] and self.Chunk_blocks[x][z-1][key] and self.Chunk_blocks[x][z][key+1] and self.Chunk_blocks[x][z][key-1]:
pass
except:
self.blocks_to_be_rendered.append(self.Chunk_blocks[x][z][key])
print(time_start-time.time())
def draw_block(self,block):
position = (block.x,block.z)
if block._type == "grass":
block = Grass
else:
print("HOLD ON A SEC")
block = Grass
vertices = get_vertices(*position)
faces = ("left","back")
for vertex,faces):
self.batch.add(
4,)
def __init__(self,Cx,Cz):
#C means chunk x and chunk y aka top left
self.Chunk_blocks = {}
self.batch = pyglet.graphics.Batch()
self.blocks_to_be_rendered = []
x =0
z=0
for x in range(0,16):
Chunk_row ={}
for z in range(0,16):
top_y = round(noise.pnoise2((Cx*16+x)/16,(Cz*16+z)/16)*10)
Chunk_collumn = {}
Chunk_collumn[top_y] = Block(Cx*16+x,top_y,Cz*16+z)
#print(top_y)
for y in range(-top_y,30):
Chunk_collumn[top_y-y-1] = Block(Cx*16+x,top_y-y-1,Cz*16+z)
Chunk_row[z]= Chunk_collumn
self.Chunk_blocks[x] = Chunk_row
thr = threading.Thread(target=self.prepare_for_rendering)
thr.start()
async def render(self):
time_start = time.time()
self.batch = pyglet.graphics.Batch()
for block in self.blocks_to_be_rendered:
self.draw_block(block)
print("Time to render 1 chunk " + str(time_start-time.time()))
def Create_chunk(cx,cz))
thr.start()
thr.join()
asyncio.run(Chunks[cx][cz].render())
def _Create_chunk(cx,cz):
time_start = time.time()
if cx in Chunks.keys():
Chunks[cx][cz] = Chunk(cx,cz)
else:
Chunks[cx] = {cz:Chunk(cx,cz)}
print(time_start-time.time())
#THIS IS WHERE THE PYGLET/GL SEGMENT STARTS
#I AM TRYING TO SPERATE THIS SO WE CAN MUTLI TRHEAD
#WITHOUT ACCIDENTILY CALLING GL FUNCTIONS IN A SEPERATE THREAD OTHER THEN THE MAIN THREAD
#
Create_chunk(0,0)
class Player:
def __init__(self,position=(8,8),rotation=(0,0)):
self.position = position
self.rotation = rotation
self.strafe = [0,0] # forward,up,left
def mouse_motion(self,dy):
x,y = self.rotation
sensitivity = 0.15
x += dx * sensitivity
y += dy * sensitivity
y = max(-90,min(90,y))
self.rotation = x % 360,y
def update(self,dt):
motion_vector = self.get_motion_vector()
speed = dt * 5
self.position = [x + y * speed for x,y in zip(self.position,motion_vector)]
def get_motion_vector(self):
x,z = self.strafe
if x or z:
strafe = math.degrees(math.atan2(x,z))
yaw = self.rotation[0]
x_angle = math.radians(yaw + strafe)
x = math.cos(x_angle)
z = math.sin(x_angle)
return x,z
def draw_camera(position,rotation):
yaw,pitch = rotation
gl.glrotatef(yaw,0)
gl.glrotatef(-pitch,math.cos(math.radians(yaw)),math.sin(math.radians(yaw)))
x,z = position
gl.glTranslatef(-x,-y,-z)
def set_3d(width,height):
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.gluPerspective(65,width / height,0.1,60)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
class Window(pyglet.window.Window):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.player = Player()
self.set_exclusive_mouse(True)
pyglet.clock.schedule(self.update)
def on_mouse_motion(self,dy):
self.player.mouse_motion(dx,dy)
def on_key_press(self,symbol,modifiers):
if symbol == window.key.ESCAPE:
self.close()
speed = 1
if symbol == window.key.W:
self.player.strafe[0] = -speed
elif symbol == window.key.S:
self.player.strafe[0] = speed
elif symbol == window.key.A:
self.player.strafe[2] = -speed
elif symbol == window.key.D:
self.player.strafe[2] = speed
elif symbol == window.key.SPACE:
self.player.strafe[1] = speed
elif symbol == window.key.LSHIFT:
self.player.strafe[1] = -speed
def on_key_release(self,modifiers):
if symbol == window.key.W:
self.player.strafe[0] = 0
elif symbol == window.key.S:
self.player.strafe[0] = 0
elif symbol == window.key.A:
self.player.strafe[2] = 0
elif symbol == window.key.D:
self.player.strafe[2] = 0
elif symbol == window.key.SPACE:
self.player.strafe[1] = 0
elif symbol == window.key.LSHIFT:
self.player.strafe[1] = 0
def update(self,dt):
self.player.update(dt)
chunk_x_player = round(self.player.position[0]/16)
chunk_z_player = round(self.player.position[2]/16)
for x in range(-2,2):
for z in range(-2,2):
try:
if Chunks[chunk_x_player+x][chunk_z_player+z]:
pass
except:
Create_chunk(chunk_x_player+x,chunk_z_player+z)
def on_draw(self):
self.clear()
time_start = time.time()
set_3d(*self.get_size())
draw_camera(self.player.position,self.player.rotation)
#for block in self.model.blocks_to_be_rendered:
# self.model.draw_block(block)
chunk_x_player = round(self.player.position[0]/16)
chunk_z_player = round(self.player.position[2]/16)
for x in range(-2,2):
try:
Chunks[chunk_x_player+x][chunk_z_player+z].batch.draw()
except:
print("ERROR")
pass
print(time_start-time.time())
if __name__ == "__main__":
Window(width=800,height=480,resizable=True)
gl.glClearColor(0.5,0.7,1) # sky color
pyglet.app.run()
解决方法
到目前为止,这还不是一个完整的答案,但是要发表评论太久了,它可能包含一些有用的信息。我建议您尝试避免使用线程,并避免使用异步。主要是因为将其正确设置可能很棘手,并且asyncio
和pyglet
都有自己的主事件循环。您可以 创建自己的事件循环,所以这并非不可能-但也许在这种情况下,它正在尝试解决可以用更少的代码解决的问题-而不是更多。
您还每次render
迭代,或者至少我认为尽可能多的每次render
调用都替换批次(我认为)。 / p>
class Chunk():
def __init__(self,Cx,Cz):
self.batch = pyglet.graphics.Batch()
def render(self):
self.batch = pyglet.graphics.Batch()
您还应该在self.blocks_to_be_rendered
函数中创建__init__
,并使其正常运行。除非您习惯于创建材料/对象加载器并创建加载屏幕,或者预先准备好它们并更快地加载它们,否则请跳过它,只将创建部分保留在__init__
部分中。这样就避免了线程,并确保不必每次渲染都这样做:
def render(self):
for block in self.blocks_to_be_rendered:
self.draw_block(block)
翻译为:
def render(self):
# Delete the entire old batch
self.batch = pyglet.graphics.Batch()
# Wait for thread lock in case there is one
# because the resouces is being created out of main thread
for block in self.blocks_to_be_rendered:
position = (block.x,block.y,block.z)
if block._type == "grass":
block = Grass
else:
print("HOLD ON A SEC")
block = Grass
x,y,z = position
dx,dy,dz = x + 1,y + 1,z + 1
vertices = [
(x,z,x,dz,z),# side
(dx,dx,dz),# side
(x,# top
(x,# bottom
(dx,# side
]
faces = ("left","right","top","bottom","front","back")
for vertex,face in zip(vertices,faces):
# Recreating the batch objects again,one by one
self.batch.add(
4,gl.GL_QUADS,block.textures[face],("v3f/static",vertex),("t2f/static",(0,1,1)),)
print("Time to render 1 chunk " + str(time_start-time.time()))
(我扩展了代码,因此您将了解在渲染逻辑中进行的大量调用,循环和逻辑。在图形渲染中,每个时钟周期都很重要)
相反,整个渲染逻辑可以归结为:
def render(self):
self.batch.draw()
假设您改为在__init__
函数中创建批次。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。