You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
connecting_the_dots/renderer/cyrender.pyx

201 lines
6.0 KiB

6 years ago
cimport cython
import numpy as np
cimport numpy as np
from libc.stdlib cimport free, malloc
from libcpp cimport bool
from cpython cimport PyObject, Py_INCREF
CREATE_INIT = True # workaround, so cython builds a init function
np.import_array()
ctypedef unsigned char uint8_t
cdef extern from "render/render.h":
cdef cppclass Camera[T]:
const T fx;
const T fy;
const T px;
const T py;
const T R0, R1, R2, R3, R4, R5, R6, R7, R8;
const T t0, t1, t2;
const T C0, C1, C2;
const int height;
const int width;
Camera(const T fx, const T fy, const T px, const T py, const T* R, const T* t, int width, int height)
cdef cppclass RenderInput[T]:
T* verts;
T* radii;
T* colors;
T* normals;
int n_verts;
int* faces;
int n_faces;
T* tex_coords;
T* tex;
int tex_height;
int tex_width;
int tex_channels;
RenderInput();
cdef cppclass Buffer[T]:
T* depth;
T* color;
T* normal;
Buffer();
cdef cppclass Shader[T]:
const T ka;
const T kd;
const T ks;
const T alpha;
Shader(T ka, T kd, T ks, T alpha)
cdef cppclass BaseRenderer[T]:
const Camera[T] cam;
const Shader[T] shader;
Buffer[T] buffer;
BaseRenderer(const Camera[T] cam, const Shader[T] shader, Buffer[T] buffer)
void render_mesh(const RenderInput[T] input);
void render_mesh_proj(const RenderInput[T] input, const Camera[T] proj, const float* pattern, float d_alpha, float d_beta);
cdef extern from "render/render_cpu.h":
cdef cppclass RendererCpu[T](BaseRenderer[T]):
RendererCpu(const Camera[T] cam, const Shader[T] shader, Buffer[T] buffer, int n_threads)
void render_mesh(const RenderInput[T] input);
void render_mesh_proj(const RenderInput[T] input, const Camera[T] proj, const float* pattern, float d_alpha, float d_beta);
cdef extern from "render/render_gpu.h":
cdef cppclass RendererGpu[T](BaseRenderer[T]):
RendererGpu(const Camera[T] cam, const Shader[T] shader, Buffer[T] buffer)
void render_mesh(const RenderInput[T] input);
void render_mesh_proj(const RenderInput[T] input, const Camera[T] proj, const float* pattern, float d_alpha, float d_beta);
cdef class PyCamera:
cdef Camera[float]* cam;
def __cinit__(self, float fx, float fy, float px, float py, float[:,::1] R, float[::1] t, int width, int height):
if R.shape[0] != 3 or R.shape[1] != 3:
raise Exception('invalid R matrix')
if t.shape[0] != 3:
raise Exception('invalid t vector')
self.cam = new Camera[float](fx,fy, px,py, &R[0,0], &t[0], width, height)
def __dealloc__(self):
del self.cam
cdef class PyRenderInput:
cdef RenderInput[float] input;
cdef verts
cdef colors
cdef normals
cdef faces
def __cinit__(self, float[:,::1] verts=None, float[:,::1] colors=None, float[:,::1] normals=None, int[:,::1] faces=None):
self.input = RenderInput[float]()
if verts is not None:
self.set_verts(verts)
if normals is not None:
self.set_normals(normals)
if colors is not None:
self.set_colors(colors)
if faces is not None:
self.set_faces(faces)
def set_verts(self, float[:,::1] verts):
if verts.shape[1] != 3:
raise Exception('verts has to be a Nx3 matrix')
self.verts = verts
cdef float[:,::1] verts_view = self.verts
self.input.verts = &verts_view[0,0]
self.input.n_verts = self.verts.shape[0]
def set_colors(self, float[:,::1] colors):
if colors.shape[1] != 3:
raise Exception('colors has to be a Nx3 matrix')
self.colors = colors
cdef float[:,::1] colors_view = self.colors
self.input.colors = &colors_view[0,0]
def set_normals(self, float[:,::1] normals):
if normals.shape[1] != 3:
raise Exception('normals has to be a Nx3 matrix')
self.normals = normals
cdef float[:,::1] normals_view = self.normals
self.input.normals = &normals_view[0,0]
def set_faces(self, int[:,::1] faces):
if faces.shape[1] != 3:
raise Exception('faces has to be a Nx3 matrix')
self.faces = faces
cdef int[:,::1] faces_view = self.faces
self.input.faces = &faces_view[0,0]
self.input.n_faces = self.faces.shape[0]
cdef class PyShader:
cdef Shader[float]* shader
def __cinit__(self, float ka, float kd, float ks, float alpha):
self.shader = new Shader[float](ka, kd, ks, alpha)
def __dealloc__(self):
del self.shader
cdef class PyRenderer:
cdef BaseRenderer[float]* renderer
cdef Buffer[float] buffer
cdef depth_buffer
cdef color_buffer
cdef normal_buffer
def depth(self):
return self.depth_buffer
def color(self):
return self.color_buffer
def normal(self):
return self.normal_buffer
def __cinit__(self, PyCamera cam, PyShader shader, engine='cpu', int n_threads=1):
self.depth_buffer = np.empty((cam.cam[0].height, cam.cam[0].width), dtype=np.float32)
self.color_buffer = np.empty((cam.cam[0].height, cam.cam[0].width, 3), dtype=np.float32)
self.normal_buffer = np.empty((cam.cam[0].height, cam.cam[0].width, 3), dtype=np.float32)
cdef float[:,::1] dbv = self.depth_buffer
cdef float[:,:,::1] cbv = self.color_buffer
cdef float[:,:,::1] nbv = self.normal_buffer
self.buffer.depth = &dbv[0,0]
self.buffer.color = &cbv[0,0,0]
self.buffer.normal = &nbv[0,0,0]
if engine == 'cpu':
self.renderer = new RendererCpu[float](cam.cam[0], shader.shader[0], self.buffer, n_threads)
elif engine == 'gpu':
self.renderer = new RendererGpu[float](cam.cam[0], shader.shader[0], self.buffer)
else:
raise Exception('invalid engine')
def __dealloc__(self):
del self.renderer
def mesh(self, PyRenderInput input):
self.renderer.render_mesh(input.input)
def mesh_proj(self, PyRenderInput input, PyCamera proj, float[:,:,::1] pattern, float d_alpha=1, float d_beta=0):
if pattern.shape[0] != proj.cam[0].height or pattern.shape[1] != proj.cam[0].width or pattern.shape[2] != 3:
raise Exception(f'pattern has to be a {proj.cam[0].height}x{proj.cam[0].width}x3 tensor')
self.renderer.render_mesh_proj(input.input, proj.cam[0], &pattern[0,0,0], d_alpha, d_beta)