|
''' |
|
MIT License |
|
|
|
Copyright (c) 2019 Shunsuke Saito, Zeng Huang, and Ryota Natsume |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in all |
|
copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
SOFTWARE. |
|
''' |
|
import numpy as np |
|
from OpenGL.GLUT import * |
|
from .framework import * |
|
|
|
_glut_window = None |
|
|
|
class Render: |
|
def __init__(self, width=1600, height=1200, name='GL Renderer', |
|
program_files=['simple.fs', 'simple.vs'], color_size=1, ms_rate=1): |
|
self.width = width |
|
self.height = height |
|
self.name = name |
|
self.display_mode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH |
|
self.use_inverse_depth = False |
|
|
|
global _glut_window |
|
if _glut_window is None: |
|
glutInit() |
|
glutInitDisplayMode(self.display_mode) |
|
glutInitWindowSize(self.width, self.height) |
|
glutInitWindowPosition(0, 0) |
|
_glut_window = glutCreateWindow("My Render.") |
|
|
|
|
|
glEnable(GL_DEPTH_TEST) |
|
|
|
glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE) |
|
glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE) |
|
glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE) |
|
|
|
|
|
shader_list = [] |
|
|
|
for program_file in program_files: |
|
_, ext = os.path.splitext(program_file) |
|
if ext == '.vs': |
|
shader_list.append(loadShader(GL_VERTEX_SHADER, program_file)) |
|
elif ext == '.fs': |
|
shader_list.append(loadShader(GL_FRAGMENT_SHADER, program_file)) |
|
elif ext == '.gs': |
|
shader_list.append(loadShader(GL_GEOMETRY_SHADER, program_file)) |
|
|
|
self.program = createProgram(shader_list) |
|
|
|
for shader in shader_list: |
|
glDeleteShader(shader) |
|
|
|
|
|
self.model_mat_unif = glGetUniformLocation(self.program, 'ModelMat') |
|
self.persp_mat_unif = glGetUniformLocation(self.program, 'PerspMat') |
|
|
|
self.vertex_buffer = glGenBuffers(1) |
|
|
|
|
|
self.quad_program, self.quad_buffer = self.init_quad_program() |
|
|
|
|
|
self.frame_buffer = glGenFramebuffers(1) |
|
glBindFramebuffer(GL_FRAMEBUFFER, self.frame_buffer) |
|
|
|
self.intermediate_fbo = None |
|
if ms_rate > 1: |
|
|
|
self.color_buffer = [] |
|
for i in range(color_size): |
|
color_buffer = glGenTextures(1) |
|
multi_sample_rate = ms_rate |
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color_buffer) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) |
|
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, multi_sample_rate, GL_RGBA32F, self.width, self.height, GL_TRUE) |
|
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0) |
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D_MULTISAMPLE, color_buffer, 0) |
|
self.color_buffer.append(color_buffer) |
|
|
|
self.render_buffer = glGenRenderbuffers(1) |
|
glBindRenderbuffer(GL_RENDERBUFFER, self.render_buffer) |
|
glRenderbufferStorageMultisample(GL_RENDERBUFFER, multi_sample_rate, GL_DEPTH24_STENCIL8, self.width, self.height) |
|
glBindRenderbuffer(GL_RENDERBUFFER, 0) |
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self.render_buffer) |
|
|
|
attachments = [] |
|
for i in range(color_size): |
|
attachments.append(GL_COLOR_ATTACHMENT0 + i) |
|
glDrawBuffers(color_size, attachments) |
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
|
|
self.intermediate_fbo = glGenFramebuffers(1) |
|
glBindFramebuffer(GL_FRAMEBUFFER, self.intermediate_fbo) |
|
|
|
self.screen_texture = [] |
|
for i in range(color_size): |
|
screen_texture = glGenTextures(1) |
|
glBindTexture(GL_TEXTURE_2D, screen_texture) |
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, self.width, self.height, 0, GL_RGBA, GL_FLOAT, None) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) |
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, screen_texture, 0) |
|
self.screen_texture.append(screen_texture) |
|
|
|
glDrawBuffers(color_size, attachments) |
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
else: |
|
self.color_buffer = [] |
|
for i in range(color_size): |
|
color_buffer = glGenTextures(1) |
|
glBindTexture(GL_TEXTURE_2D, color_buffer) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) |
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, self.width, self.height, 0, GL_RGBA, GL_FLOAT, None) |
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, color_buffer, 0) |
|
self.color_buffer.append(color_buffer) |
|
|
|
|
|
self.depth_buffer = glGenTextures(1) |
|
glBindTexture(GL_TEXTURE_2D, self.depth_buffer) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) |
|
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE) |
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL) |
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, self.width, self.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, None) |
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, self.depth_buffer, 0) |
|
|
|
attachments = [] |
|
for i in range(color_size): |
|
attachments.append(GL_COLOR_ATTACHMENT0 + i) |
|
glDrawBuffers(color_size, attachments) |
|
self.screen_texture = self.color_buffer |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
|
|
|
|
|
|
self.render_texture = None |
|
|
|
|
|
|
|
self.render_texture_v2 = {} |
|
|
|
|
|
self.vertex_data = None |
|
self.vertex_dim = None |
|
self.n_vertices = None |
|
|
|
self.model_view_matrix = None |
|
self.projection_matrix = None |
|
|
|
glutDisplayFunc(self.display) |
|
|
|
|
|
def init_quad_program(self): |
|
shader_list = [] |
|
|
|
shader_list.append(loadShader(GL_VERTEX_SHADER, "quad.vs")) |
|
shader_list.append(loadShader(GL_FRAGMENT_SHADER, "quad.fs")) |
|
|
|
the_program = createProgram(shader_list) |
|
|
|
for shader in shader_list: |
|
glDeleteShader(shader) |
|
|
|
|
|
|
|
quad_vertices = np.array( |
|
[-1.0, 1.0, 0.0, 1.0, |
|
-1.0, -1.0, 0.0, 0.0, |
|
1.0, -1.0, 1.0, 0.0, |
|
|
|
-1.0, 1.0, 0.0, 1.0, |
|
1.0, -1.0, 1.0, 0.0, |
|
1.0, 1.0, 1.0, 1.0] |
|
) |
|
|
|
quad_buffer = glGenBuffers(1) |
|
glBindBuffer(GL_ARRAY_BUFFER, quad_buffer) |
|
glBufferData(GL_ARRAY_BUFFER, quad_vertices, GL_STATIC_DRAW) |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0) |
|
|
|
return the_program, quad_buffer |
|
|
|
def set_mesh(self, vertices, faces): |
|
self.vertex_data = vertices[faces.reshape([-1])] |
|
self.vertex_dim = self.vertex_data.shape[1] |
|
self.n_vertices = self.vertex_data.shape[0] |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer) |
|
glBufferData(GL_ARRAY_BUFFER, self.vertex_data, GL_STATIC_DRAW) |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0) |
|
|
|
def set_viewpoint(self, projection, model_view): |
|
self.projection_matrix = projection |
|
self.model_view_matrix = model_view |
|
|
|
def draw_init(self): |
|
glBindFramebuffer(GL_FRAMEBUFFER, self.frame_buffer) |
|
glEnable(GL_DEPTH_TEST) |
|
|
|
|
|
glClearColor(1.0, 1.0, 1.0, 0.0) |
|
|
|
if self.use_inverse_depth: |
|
glDepthFunc(GL_GREATER) |
|
glClearDepth(0.0) |
|
else: |
|
glDepthFunc(GL_LESS) |
|
glClearDepth(1.0) |
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) |
|
|
|
def draw_end(self): |
|
if self.intermediate_fbo is not None: |
|
for i in range(len(self.color_buffer)): |
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, self.frame_buffer) |
|
glReadBuffer(GL_COLOR_ATTACHMENT0 + i) |
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.intermediate_fbo) |
|
glDrawBuffer(GL_COLOR_ATTACHMENT0 + i) |
|
glBlitFramebuffer(0, 0, self.width, self.height, 0, 0, self.width, self.height, GL_COLOR_BUFFER_BIT, GL_NEAREST) |
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
glDepthFunc(GL_LESS) |
|
glClearDepth(1.0) |
|
|
|
def draw(self): |
|
self.draw_init() |
|
|
|
glUseProgram(self.program) |
|
glUniformMatrix4fv(self.model_mat_unif, 1, GL_FALSE, self.model_view_matrix.transpose()) |
|
glUniformMatrix4fv(self.persp_mat_unif, 1, GL_FALSE, self.projection_matrix.transpose()) |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer) |
|
|
|
glEnableVertexAttribArray(0) |
|
glVertexAttribPointer(0, self.vertex_dim, GL_DOUBLE, GL_FALSE, 0, None) |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, self.n_vertices) |
|
|
|
glDisableVertexAttribArray(0) |
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0) |
|
|
|
glUseProgram(0) |
|
|
|
self.draw_end() |
|
|
|
def get_color(self, color_id=0): |
|
glBindFramebuffer(GL_FRAMEBUFFER, self.intermediate_fbo if self.intermediate_fbo is not None else self.frame_buffer) |
|
glReadBuffer(GL_COLOR_ATTACHMENT0 + color_id) |
|
data = glReadPixels(0, 0, self.width, self.height, GL_RGBA, GL_FLOAT, outputType=None) |
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
rgb = data.reshape(self.height, self.width, -1) |
|
rgb = np.flip(rgb, 0) |
|
return rgb |
|
|
|
def get_z_value(self): |
|
glBindFramebuffer(GL_FRAMEBUFFER, self.frame_buffer) |
|
data = glReadPixels(0, 0, self.width, self.height, GL_DEPTH_COMPONENT, GL_FLOAT, outputType=None) |
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
z = data.reshape(self.height, self.width) |
|
z = np.flip(z, 0) |
|
return z |
|
|
|
def display(self): |
|
|
|
|
|
self.draw() |
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0) |
|
|
|
|
|
|
|
glClearColor(1.0, 1.0, 1.0, 0.0) |
|
glClear(GL_COLOR_BUFFER_BIT) |
|
|
|
|
|
glUseProgram(self.quad_program) |
|
glBindBuffer(GL_ARRAY_BUFFER, self.quad_buffer) |
|
|
|
size_of_double = 8 |
|
glEnableVertexAttribArray(0) |
|
glVertexAttribPointer(0, 2, GL_DOUBLE, GL_FALSE, 4 * size_of_double, None) |
|
glEnableVertexAttribArray(1) |
|
glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, 4 * size_of_double, c_void_p(2 * size_of_double)) |
|
|
|
glDisable(GL_DEPTH_TEST) |
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0) |
|
glBindTexture(GL_TEXTURE_2D, self.screen_texture[0]) |
|
glUniform1i(glGetUniformLocation(self.quad_program, 'screenTexture'), 0) |
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6) |
|
|
|
glDisableVertexAttribArray(1) |
|
glDisableVertexAttribArray(0) |
|
|
|
glEnable(GL_DEPTH_TEST) |
|
glBindBuffer(GL_ARRAY_BUFFER, 0) |
|
glUseProgram(0) |
|
|
|
glutSwapBuffers() |
|
glutPostRedisplay() |
|
|
|
def show(self): |
|
glutMainLoop() |
|
|