【问题标题】:Converting pygame 2d water ripple to pyOpenGL将 pygame 2d 水波纹转换为 pyOpenGL
【发布时间】:2020-12-23 05:27:24
【问题描述】:

我有一个 2d pygame 水模拟东西,我按照教程制作。我还找到了这个问题的答案来解决教程中的问题:Pygame water physics not working as intended

从那以后,我一直在尝试将这个程序转换为使用 pyopengl 来渲染东西。但是,我一直在努力: A:画水多边形 B:使用平铺纹理纹理水多边形

这是我(相当糟糕的)将此代码转换为 pyopengl 的尝试。

import pygame, random
import math as m

from pygame import *
from OpenGL import *
from OpenGL.GLU import *
from OpenGL.GL import *

pygame.init()

WINDOW_SIZE = (854, 480)
 
screen = pygame.display.set_mode(WINDOW_SIZE,0,32,DOUBLEBUF|OPENGL) # initiate the window

clock = pygame.time.Clock()


def draw_polygon(polygon_points):
    glBegin(GL_POLYGON);
    for i in polygon_points:
        glVertex3fv(i)
    #glEnd()
    
class surface_water_particle():
    
    def __init__(self, x,y):
        self.x_pos = x
        self.y_pos = y
        self.target_y = y
        self.velocity = 0
        self.k = 0.04  
        self.d = 0.08
        self.time = 1

    def update(self):
        x =  self.y_pos - self.target_y
        a = -(self.k * x + self.d * self.velocity)

        if self.y_pos > self.target_y:
            self.y_pos -= 0.1
        if self.y_pos < self.target_y:
            self.y_pos += 0.1
        self.velocity = round(self.velocity)

        self.y_pos += self.velocity
        self.velocity += a

        self.time += 1

class water_tile():
    def __init__(self, x_start, x_end, y_start, y_end, segment_length):
        self.springs = []
        self.x_start = x_start
        self.y_start = y_start
        self.x_end = x_end
        self.y_end = y_end - 10
        for i in range(abs(x_end - x_start) // segment_length):
            self.springs.append(surface_water_particle(i * segment_length + x_start, y_end))

    def update(self, spread):
        passes = 4  # more passes = more splash spreading
        for i in range(len(self.springs)):
            self.springs[i].update() 

        leftDeltas = [0] * len(self.springs)
        rightDeltas = [0] * len(self.springs)
        for p in range(passes):  
            for i in range(0, len(self.springs)):
                if i > 0:  
                    leftDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i - 1].y_pos)
                    self.springs[i - 1].velocity += leftDeltas[i]
                if i < len(self.springs):
                    rightDeltas[i] = spread * (self.springs[i].y_pos - self.springs[(i + 1)%len(self.springs)].y_pos)
                    self.springs[(i + 1)%len(self.springs)].velocity += rightDeltas[i]

            for i in range(0, len(self.springs)):
                if round (leftDeltas[i],12) == 0 or round (rightDeltas[i],12) == 0:
                    self.springs[i - 1].y_pos = self.y_end+10
                if i > 0:
                    self.springs[i - 1].y_pos += leftDeltas[i]  # you were updating velocity here!
                if i < len(self.springs):
                    self.springs[(i + 1)%len(self.springs)].y_pos += rightDeltas[i]
                
    def splash(self, index, speed):
        if index >= 0 and index < len(self.springs):
            self.springs[index].velocity = speed 

    def draw(self):
        water_surface = pygame.Surface((abs(self.x_end-self.x_start), abs(self.y_start - self.y_end)), depth=8).convert_alpha()
        polygon_points = []
        polygon_points.append((self.x_start, self.y_start,0))
        for spring in range(len(self.springs)):
            polygon_points.append((self.springs[spring].x_pos, self.springs[spring].y_pos,0))
        polygon_points.append((self.springs[len(self.springs) - 1].x_pos, self.y_start,0))

        draw_polygon(polygon_points)
        
        return water_surface

class water_object:
    def __init__(self, x_start, x_end, y_start, y_end, segment_length, x_pos, y_pos):
        self.water = water_tile(x_start,x_end,y_start,y_end,segment_length)
        self.image = self.water.draw()
        self.rect = self.image.get_rect()
        self.rect.x = x_pos
        self.rect.y = y_pos

    def update(self):
        self.water.update(0.1)
        self.image = self.water.draw()
        
water_list = [water_object(0,276+16,64,0,16,0,20)]

while True:
    screen.fill((0,0,0))
    for water in water_list:
        gluPerspective(45, (WINDOW_SIZE[0]/WINDOW_SIZE[1]), 0.1, 50.0)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        water.update()
        #screen.blit(water.image, (water.rect.x,water.rect.y))
        #water_test.x_start = water_test.x_start + 1
        
        #if random.randint(0,8) == 1:
            #water_test.splash(random.randint(0, len(water_test.springs) - 1),2)
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
            if event.type == MOUSEBUTTONDOWN:
                print (len(water.water.springs))
                water.water.splash(random.randint(0, len(water.water.springs) - 1),50)

    pygame.display.update()

    clock.tick(60)

但是,尽管我尝试过,但我根本无法在屏幕上显示任何内容。我该如何解决这个问题/我如何才能实现我一直在努力解决的两件事?

【问题讨论】:

    标签: python opengl pygame physics pyopengl


    【解决方案1】:

    您不能将 OpenGL primitive 绘制到 pygame.Surface。无论如何,没有必要这样做。 为获得最佳性能,请直接绘制到默认帧缓冲区(窗口)。

    既然要画线,就必须使用Line primitive 类型。 GL_POLYGON 将绘制一个已归档的凸多边形。使用原始类型GL_LINE_STRIP

    def draw_polygon(polygon_points):
        glBegin(GL_LINE_STRIP)
        for pt in polygon_points:
            glVertex2f(*pt)
        glEnd()
    

    在画线之前,将当前颜色通过glColor

    glColor3f(0, 0, 1)
    draw_polygon(polygon_points)
    

    谎言的顶点坐标在窗口空间中指定。因此,您必须设置Orthographic projection 而不是Perspective projection。用[glMatrixMode]指定当前矩阵,用glOrtho设置投影矩阵。由于矩阵运算不设置矩阵,而是将当前矩阵乘以指定矩阵,所以我建议在之前加载单位矩阵(glLoadIdentity):

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, WINDOW_SIZE[0], WINDOW_SIZE[1], 0, -1, 1)
    
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    

    在画线之前,您必须通过glClear 清除帧缓冲区。清晰的颜色可以由glClearColor定义:

    glClearColor(1, 1, 1, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    

    完整示例:

    import pygame, random
    import math as m
    
    from pygame import *
    from OpenGL import *
    from OpenGL.GLU import *
    from OpenGL.GL import *
    
    pygame.init()
    
    WINDOW_SIZE = (854, 480)
     
    screen = pygame.display.set_mode(WINDOW_SIZE, flags=DOUBLEBUF|OPENGL, depth=32, display=0) # initiate the window
    clock = pygame.time.Clock()
    
    def draw_polygon(polygon_points):
        glBegin(GL_LINE_STRIP)
        for pt in polygon_points:
            glVertex2f(*pt)
        glEnd()
        
    class surface_water_particle():
        
        def __init__(self, x,y):
            self.x_pos = x
            self.y_pos = y
            self.target_y = y
            self.velocity = 0
            self.k = 0.04  
            self.d = 0.08
            self.time = 1
    
        def update(self):
            x =  self.y_pos - self.target_y
            a = -(self.k * x + self.d * self.velocity)
    
            if self.y_pos > self.target_y:
                self.y_pos -= 0.1
            if self.y_pos < self.target_y:
                self.y_pos += 0.1
            self.velocity = round(self.velocity)
    
            self.y_pos += self.velocity
            self.velocity += a
    
            self.time += 1
    
    class water():
        
        def __init__(self, x_start, x_end, y_start, y_end, segment_length):
            self.springs = []
            self.x_start = x_start
            self.y_start = y_start
            self.x_end = x_end
            self.y_end = y_end - 10
            for i in range(abs(x_end - x_start) // segment_length):
                self.springs.append(surface_water_particle(i * segment_length + x_start, y_end))
    
        def update(self, spread):
            passes = 4  # more passes = more splash spreading
            for i in range(len(self.springs)):
                self.springs[i].update() 
    
            leftDeltas = [0] * len(self.springs)
            rightDeltas = [0] * len(self.springs)
            for p in range(passes):  
                for i in range(0, len(self.springs) -1 ):
                    if i > 0:  
                        leftDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i - 1].y_pos)
                        self.springs[i - 1].velocity += leftDeltas[i]
                    if i < len(self.springs) - 1:
                        rightDeltas[i] = spread * (self.springs[i].y_pos - self.springs[i + 1].y_pos)
                        self.springs[i + 1].velocity += rightDeltas[i]
    
                for i in range(0, len(self.springs) -1):
                    if i > 0:
                        self.springs[i - 1].y_pos += leftDeltas[i]  # you were updating velocity here!
                    if i < len(self.springs) - 1:
                        self.springs[i + 1].y_pos += rightDeltas[i]
    
                   
                    
        def splash(self, index, speed):
            if index > 0 and index < len(self.springs) :
                self.springs[index].velocity = speed
                    
        def draw(self):
            water_surface = pygame.Surface((abs(self.x_start - self.x_end), abs(self.y_start - self.y_end))).convert_alpha()
            water_surface.fill((0,0,0,0))
            water_surface.set_colorkey((0,0,0,0))
            polygon_points = []
            polygon_points.append((self.x_start, self.y_start))
            for spring in range(len(self.springs)):
                polygon_points.append((self.springs[spring].x_pos, self.springs[spring].y_pos))
            polygon_points.append((self.springs[len(self.springs) - 1].x_pos, self.y_start))
    
            glColor3f(0, 0, 1)
            draw_polygon(polygon_points)
            
    water_test = water(0,800,200,200, 3)
    
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, WINDOW_SIZE[0], WINDOW_SIZE[1], 0, -1, 1)
    
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    
    glClearColor(1, 1, 1, 1)
    
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
            if event.type == MOUSEBUTTONDOWN:
                water_test.splash(50, 100)
        
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        
        water_test.update(0.025)
        water_test.draw()
    
        pygame.display.flip()
        clock.tick(60)
    

    【讨论】:

      猜你喜欢
      • 2011-11-30
      • 2019-04-23
      • 2015-06-29
      • 2013-09-16
      • 1970-01-01
      • 2020-06-05
      • 2020-08-17
      • 2019-06-14
      • 1970-01-01
      相关资源
      最近更新 更多