【问题标题】:Python OpenGL does not render every Triangle in a QuadrilateralPython OpenGL 不会渲染四边形中的每个三角形
【发布时间】:2019-08-21 19:43:23
【问题描述】:

我有一些代码可以在 OpenGL 中渲染一个带有纹理的平面。相同的框架让我可以渲染立方体,但平面似乎可以渲染三个连接在正方形中间的三角形。效果似乎是一个信封形状。

我已经更改了纹理图像。我尝试使用 3 个通道而不是 4 个通道加载图像。相同的框架可以毫无问题地渲染多维数据集。

我可以再次渲染同一个正方形并旋转它,或者改用三角形,但我更愿意理解这个问题。

## Python 3.7

## OpenGL objectsare visualised in pygame

from OpenGL.GL import *
from OpenGL.GLU import *
import pygame
from pygame.locals import *
import sys
import numpy as np
import cv2

cwd = 'C:/Users/berta/Desktop/Python/Open GL/'

coords = np.array([
[0.,1.],
[1.,1.],
[1.,0.],
[0.,0.]
])

graphic_names = [
    'ground'
]

ground_vertices = np.array([
    [-10, -1.5, 10],
    [10, -1.5, 10],
    [-10, -1.5, -300],
    [10, -1.5, -300]
], dtype = np.float64)

def loadGraphics(graphic_names):
    output_dict = {}
    for f in graphic_names:
        img = cv2.imread(cwd + 'Images/' + f + '.png', cv2.IMREAD_UNCHANGED)
        if img.shape[2] == 3:
            alpha = np.uint8(np.ones(img.shape[:2])*255)
            img = np.dstack((img,alpha))
        textureSurface = pygame.Surface(img.shape[:2], pygame.SRCALPHA)
        bv = textureSurface.get_buffer()
        bv.write(img.tostring(), 0)
        textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
        width = textureSurface.get_width()
        height = textureSurface.get_height()
        output_dict[f] = (textureData, width, height)
    return output_dict

graphics = loadGraphics(graphic_names)

def loadTexture(textureData, width, height):
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    glEnable(GL_TEXTURE_2D)

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
                    0, GL_RGBA, GL_UNSIGNED_BYTE, textureData)

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    return

class FlatSurface:

    def __init__(self, texture_name, input_vertices, n_x, n_z):
        self.texture_name = texture_name
        self.vertices = input_vertices
        # Determines the flat plane and creates tiled squares
        flat_dim_found = False
        for i in range(3):
            if np.all(self.vertices[:,i] == self.vertices[0,i]):
                flat_dim_found = True
                self.flat_dim = i
                break
        if not(flat_dim_found):
            print('No flat dimension has been found!')
            self.flat_dim = 1
        self.y_const = np.mean(self.vertices[:,self.flat_dim])
        x_not_done = True
        for i in range(3):
            if i != self.flat_dim:
                if x_not_done:
                    self.min_x = np.min(self.vertices[:,i])
                    max_x = np.max(self.vertices[:,i])
                    self.x_dim = i
                    x_not_done = False
                else:
                    self.min_z = np.min(self.vertices[:,i])
                    max_z = np.max(self.vertices[:,i])
                    self.z_dim = i
        self.tiles = []
        self.tile_x_width = float(max_x-self.min_x)/float(n_x)
        self.tile_z_width = float(max_z-self.min_z)/float(n_z)
        for x in range(n_x):
            for z in range(n_z):
                self.tiles.append(self.make_tile(x,z))
        self.tiles = np.array(self.tiles, dtype = np.float64)
        print(self.tiles)

    def make_tile(self,x,z):
        # Creates a square tile for a certain index in the bounded shape
        surf = []
        tile = np.array([0,0,0])
        tile[self.flat_dim] = self.y_const
        tile[self.x_dim] = self.min_x + x*self.tile_x_width
        tile[self.z_dim] = self.min_z + z*self.tile_z_width
        surf.append(tile.copy())
        tile[self.z_dim] += self.tile_z_width
        surf.append(tile.copy())
        tile[self.x_dim] += self.tile_x_width
        tile[self.z_dim] -= self.tile_z_width
        surf.append(tile.copy())
        tile[self.z_dim] += self.tile_z_width
        surf.append(tile.copy())
        return surf

    def draw(self):
        # loads texture and draws each square
        loadTexture(*graphics[self.texture_name])
        glBegin(GL_QUADS)
        for surf in self.tiles:
            for vertex, coord in zip(surf, coords):
                glTexCoord2f(*coord)
                glVertex3fv(vertex)
            ## A shameful hack to stop envelopes appearing
            #for vertex, coord in zip(surf[::-1], coords):
            #   glTexCoord2f(*coord)
            #   glVertex3fv(vertex)
        glEnd()


def main():
    pygame.init()
    display = (1200,800)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL|OPENGLBLIT)
    gluPerspective(45, (display[0]/display[1]), 0.99 , 20.0)
    glTranslatef( 0., 0., -10. )
    glRotate(0, 0, 0, 0)
    x_move = 0
    z_move = 0
    speed = 0.01

    ground = FlatSurface('ground', ground_vertices, 4, 62)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        m = glGetDoublev(GL_MODELVIEW_MATRIX) # perspective matrix

        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        ground.draw()
        glTranslate(x_move,0,z_move+speed)
        pygame.display.flip()
        pygame.time.wait(10)


main()

四边形的坐标是这样的,和预期的一样:

[[   5.   -1.   -5.]
[   5.   -1.    0.]
[  10.   -1.   -5.]
[  10.   -1.    0.]]

[[   5.   -1.    0.]
[   5.   -1.    5.]
[  10.   -1.    0.]
[  10.   -1.    5.]]

[[   5.   -1.    5.]
[   5.   -1.   10.]
[  10.   -1.    5.]
[  10.   -1.   10.]]]

屏幕截图中显示了输出。

【问题讨论】:

    标签: python python-3.x opengl pygame


    【解决方案1】:

    问题是FlatSurface 类中的方法make_tile,它以错误的顺序为Quad primitive 创建顶点。
    顶点必须以围绕四边形的循环顺序排列。例如:

               1         2
           z    +--------+
           ^    |        |
           |    |        |
           |    |        |
                +--------+
    min (x, z) 0          3
                 -----> x
    

    必须是:

    class FlatSurface
    
        # [...]
    
        def make_tile(self,x,z):
            # Creates a square tile for a certain index in the bounded shape
            surf = []
            tile = np.array([0,0,0])
            tile[self.flat_dim] = self.y_const
            tile[self.x_dim] = self.min_x + x*self.tile_x_width
            tile[self.z_dim] = self.min_z + z*self.tile_z_width
            surf.append(tile.copy())
            tile[self.z_dim] += self.tile_z_width
            surf.append(tile.copy())
            tile[self.x_dim] += self.tile_x_width
            surf.append(tile.copy())
            tile[self.z_dim] -= self.tile_z_width
            surf.append(tile.copy())
            return surf
    

    【讨论】:

    • 这很棒。谢谢!
    【解决方案2】:

    您的顶点顺序错误。

    您对每个四边形使用了以下顺序:

    1---2
    |   |
    3---4
    

    但它应该是:

    1---2
    |   |
    4---3
    

    【讨论】:

    • 我明白了。所以我认为open GL在GL_QUAD中给出的每对顶点之间绘制一个等腰三角形,因此顶点需要以正确的顺序表示正方形的每一边。酷。
    猜你喜欢
    • 1970-01-01
    • 2017-02-04
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 2020-04-05
    • 2021-06-29
    • 1970-01-01
    相关资源
    最近更新 更多