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

170 lines
5.0 KiB
Python

# OpenGL/Metal rendering test: render a textured spinning cube
import sys
sys.path.append('python')
import nanogui
from nanogui import Shader, Texture, RenderPass, Screen, Matrix4f
from nanogui import glfw
import numpy as np
from PIL import Image
import os
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 vec2 uv;
out vec2 uv_frag;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
uv_frag = uv;
}
'''
fragment_program = '''
#version 330
in vec2 uv_frag;
out vec4 fragColor;
uniform sampler2D albedo_texture;
void main() {
fragColor = texture(albedo_texture, uv_frag);
}
'''
elif nanogui.api == 'metal':
vertex_program = '''
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 uv;
};
vertex VertexOut vertex_main(const device packed_float3 *position,
const device float2 *uv,
constant float4x4 &mvp,
uint id [[vertex_id]]) {
VertexOut vert;
vert.position = mvp * float4(position[id], 1.f);
vert.uv = uv[id];
return vert;
}
'''
fragment_program = '''
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 uv;
};
fragment float4 fragment_main(VertexOut vert [[stage_in]],
texture2d<float, access::sample> albedo_texture,
sampler albedo_sampler) {
return albedo_texture.sample(albedo_sampler, vert.uv);
}
'''
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
image_fname = os.path.join(base_dir, "resources/icons/icon1.png")
image = np.array(Image.open(image_fname))
self.albedo_texture = Texture(
pixel_format=Texture.PixelFormat.RGBA,
component_format=Texture.ComponentFormat.UInt8,
size=image.shape[:2]
)
self.albedo_texture.upload(image)
self.render_pass = RenderPass(
color_targets=[self]
)
self.shader = Shader(
self.render_pass,
"test_shader",
vertex_program,
fragment_program
)
p = np.array([
[-1, -1, 0], [1, -1, 0],
[1, 1, 0], [-1, 1, 0]],
dtype=np.float32
)
uv = np.array([
[1, 1], [0, 1],
[0, 0], [1, 0]],
dtype=np.float32
)
indices = np.array([
0, 2, 1, 3, 2, 0],
dtype=np.uint32
)
self.shader.set_buffer("position", p)
self.shader.set_buffer("uv", uv)
self.shader.set_buffer("indices", indices)
self.shader.set_texture("albedo_texture", self.albedo_texture)
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() * 0.01
)
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, 6, 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()