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.
 
 
 
 
 
 

200 lines
6.0 KiB

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)