2022-04-07 18:46:57 +02:00

180 lines
5.2 KiB
Python

# OpenGL/Metal rendering test: render a spinning cube with MSAA
import sys
sys.path.append('python')
import nanogui
from nanogui import Shader, Texture, RenderPass, Screen, Matrix4f
from nanogui import glfw
import numpy as np
class MyScreen(Screen):
def __init__(self):
Screen.__init__(self,
size=[512, 512],
caption="Unnamed"
)
if nanogui.api == 'opengl':
vertex_program = '''
#version 330
in vec3 position;
in vec4 color;
out vec4 color_frag;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
color_frag = color;
}
'''
fragment_program = '''
#version 330
in vec4 color_frag;
out vec4 fragColor;
void main() {
fragColor = color_frag;
}
'''
elif nanogui.api == 'metal':
vertex_program = '''
using namespace metal;
struct VertexOut {
float4 position [[position]];
float4 color;
};
vertex VertexOut vertex_main(const device packed_float3 *position,
const device float4 *color,
constant float4x4 &mvp,
uint id [[vertex_id]]) {
VertexOut vert;
vert.position = mvp * float4(position[id], 1.f);
vert.color = color[id];
return vert;
}
'''
fragment_program = '''
using namespace metal;
struct VertexOut {
float4 position [[position]];
float4 color;
};
fragment float4 fragment_main(VertexOut vert [[stage_in]]) {
return vert.color;
}
'''
self.color_target = Texture(
pixel_format=self.pixel_format(),
component_format=self.component_format(),
size=self.framebuffer_size(),
flags=Texture.TextureFlags.RenderTarget,
samples=8
)
self.depth_target = Texture(
pixel_format=Texture.PixelFormat.Depth,
component_format=Texture.ComponentFormat.Float32,
size=self.framebuffer_size(),
flags=Texture.TextureFlags.RenderTarget,
samples=8
)
self.render_pass = RenderPass(
color_targets=[self.color_target],
depth_target=self.depth_target,
blit_target=self
)
self.shader = Shader(
self.render_pass,
"test_shader",
vertex_program,
fragment_program
)
p = np.array([
[-1, 1, 1], [-1, -1, 1],
[1, -1, 1], [1, 1, 1],
[-1, 1, -1], [-1, -1, -1],
[1, -1, -1], [1, 1, -1]],
dtype=np.float32
)
color = np.array([
[0, 1, 1, 1], [0, 0, 1, 1],
[1, 0, 1, 1], [1, 1, 1, 1],
[0, 1, 0, 1], [0, 0, 0, 1],
[1, 0, 0, 1], [1, 1, 0, 1]],
dtype=np.float32
)
indices = np.array([
3, 2, 6, 6, 7, 3,
4, 5, 1, 1, 0, 4,
4, 0, 3, 3, 7, 4,
1, 5, 6, 6, 2, 1,
0, 1, 2, 2, 3, 0,
7, 6, 5, 5, 4, 7],
dtype=np.uint32
)
self.shader.set_buffer("position", p)
self.shader.set_buffer("color", color)
self.shader.set_buffer("indices", indices)
def draw_contents(self):
with self.render_pass:
view = Matrix4f.look_at(
origin=[0, -2, -10],
target=[0, 0, 0],
up=[0, 1, 0]
)
model = Matrix4f.rotate(
[0, 1, 0],
glfw.getTime()
)
fbsize = self.framebuffer_size()
proj = Matrix4f.perspective(
fov=25 * np.pi / 180,
near=0.1,
far=20,
aspect=fbsize[0] / float(fbsize[1])
)
mvp = proj @ view @ model
self.shader.set_buffer("mvp", np.float32(mvp).T)
with self.shader:
self.shader.draw_array(Shader.PrimitiveType.Triangle,
0, 36, indexed=True)
def keyboard_event(self, key, scancode, action, modifiers):
if super(MyScreen, self).keyboard_event(key, scancode,
action, modifiers):
return True
if key == glfw.KEY_ESCAPE and action == glfw.PRESS:
self.set_visible(False)
return True
return False
def resize_event(self, size):
self.render_pass.resize(self.framebuffer_size())
super(MyScreen, self).resize_event(size)
return True
nanogui.init()
s = MyScreen()
s.set_visible(True)
nanogui.mainloop(1 / 60.0 * 1000)
nanogui.shutdown()