I have created a C++ class and used it to render. The system is quite similar to Render inside python threads . However there is a difference that the C++ class is generated as a object in the main python function, then the render process is called inside threading.Thread().
when instead of threading.Thread() if I render normally, I get the results correctly, But when I render inside thread Panda3D gives following error :
:display:egldisplay(error): Failed to call eglMakeCurrent: EGL_BAD_ACCESS
Most probably the problem is about
If context
is current to some other thread, or if either draw
or read
are bound to contexts in another thread, an EGL_BAD_ACCESS
error is generated.
as explained here: eglMakeCurrent - EGL Reference Pages
Any suggestions?
here is c++ render class:
#include <stdint.h>
#include "pandaFramework.h"
#include "pandaSystem.h"
#include "load_prc_file.h"
#include "displayRegion.h"
#include "genericAsyncTask.h"
#include "asyncTaskManager.h"
#include "eventHandler.h"
#include "buttonThrower.h"
#include "bulletWorld.h"
#include "bulletTriangleMesh.h"
#include "bulletTriangleMeshShape.h"
#include "bulletRigidBodyNode.h"
#include "texture.h"
#include "frameBufferProperties.h"
#include "graphicsOutput.h"
#include "graphicsEngine.h"
#include "graphicsPipe.h"
#include "graphicsPipeSelection.h"
#include "camera.h"
#include "windowProperties.h"
#include "transformState.h"
#include "nodePath.h"
#include "geomNode.h"
#include "pandaNode.h"
#include "perspectiveLens.h"
#include "loader.h"
#include "math.h"
#include "bulletClosestHitRayResult.h"
using namespace std;
class cpp_Render{
public:
PT(GraphicsOutput) mybuffer;
PT(Texture) mytexture;
PT(Camera) mycamera;
PT(DisplayRegion) region;
NodePath mycameraNP;
FrameBufferProperties fb_prop;
PT(GraphicsPipe) pipe;
PT(GraphicsEngine) engine;
WindowProperties win_prop;
PerspectiveLens lens;
NodePath altRender = NodePath("render");
NodePath npm;
PT(BulletWorld) world;
PT(BulletTriangleMesh) mesh;
NodePathCollection npc;
PT(GeomNode) geomNode;
PT(BulletTriangleMeshShape) shape;
PT(BulletRigidBodyNode) floor;
PT(Loader) loader;
NodePath floorNP;
cpp_Render(char * model_path);
void * cpp_render(float * camera_values);
};
cpp_Render::cpp_Render(char * model_path){
// getting global pointers and setting environment
load_prc_file_data("", "gl-debug true");
//load_prc_file_data("", "gl-check-errors true");
engine = GraphicsEngine::get_global_ptr();
pipe = GraphicsPipeSelection::get_global_ptr()->make_module_pipe("pandagl");
loader = Loader::get_global_ptr();
// frame buffer properties
fb_prop.set_rgb_color(true);
fb_prop.set_rgba_bits(8, 8, 8, 8);
fb_prop.set_depth_bits(8);
win_prop.set_size(1920,1080);
// camera properties
mycamera = new Camera("new_camera");
mycameraNP = NodePath(mycamera) ;
mycameraNP.reparent_to(altRender);
mycamera->get_lens()->set_film_size( 1.0,0.5625 );
mycamera->get_lens()->set_focal_length(0.555555);
mycameraNP.set_pos(-2.17,5.269,2.8359);
mycameraNP.set_hpr(172.5,-23.99,0.00);
// creating buffer
int flags = pipe->BF_refuse_window;
mybuffer = engine->make_output(pipe, "buffer", -100, fb_prop, win_prop, flags);
mybuffer->set_clear_color_active(true);
mybuffer->set_clear_depth_active(true);
mybuffer->set_clear_depth(1.0);
mybuffer->set_clear_color(LColor(0,0,0,0));
mybuffer->add_render_texture(mytexture, GraphicsOutput::RTM_copy_ram);
// loading model
npm = NodePath(loader->load_sync(model_path));
npm.flatten_light();
npm.reparent_to(altRender);
region = mybuffer->make_display_region();
region->set_camera(mycameraNP);
// model -> world
world = new BulletWorld();
mesh = new BulletTriangleMesh();
npc = npm.find_all_matches("**/+GeomNode");
for (size_t i = 0; i < npc.get_num_paths(); i++) {
geomNode = DCAST(GeomNode, npc.get_path(i).node());
for (size_t j = 0; j<geomNode->get_num_geoms();j++){
mesh->add_geom(geomNode->get_geom(j),npc.get_path(i).get_transform());
}
}
shape = new BulletTriangleMeshShape(mesh,false);
floor = new BulletRigidBodyNode("floor");
floor->add_shape(shape);
floorNP = altRender.attach_new_node(floor);
floorNP.set_pos(0,0,0);
floorNP.set_collide_mask(BitMask32::all_on());
world->attach_rigid_body(floor);
mycamera->get_lens()->set_focal_length(0.555555);
mycameraNP.set_pos(-2.17,5.269,2.8359);
mycameraNP.set_hpr(172.5,-23.99,0.00);
// initiliaze the system by getting some renders
for (int i = 0; i<10; i++){
mybuffer->get_engine()->render_frame();
mytexture = mybuffer->get_texture();
}
};
void * cpp_Render::cpp_render(float * camera_values){
mycamera->get_lens()->set_focal_length(*camera_values);
mycameraNP.set_pos(*(camera_values+1),*(camera_values+2),*(camera_values+3));
mycameraNP.set_hpr(*(camera_values+4),*(camera_values+5),*(camera_values+6));
mybuffer->get_engine()->render_frame();
mytexture = mybuffer->get_texture();
CPTA_uchar data = mytexture->get_ram_image();
void *_ptr = (void*)data.p();
return _ptr;
};
extern "C" {
cpp_Render* Render(char * model_path){ return new cpp_Render(model_path); }
void * RenderRender(cpp_Render* Render, float* camera_values ){ return Render -> cpp_render(camera_values); }
}
}
here is Python class that uses c++ class
from ctypes import cdll
import time
import datetime
import numpy as np
import matplotlib.pyplot as plt
import ctypes
#import threading
from direct.stdpy import threading2 as threading
import cv2
import os
class RenderCpp:
def __init__(self):
render_model_path = "./model.egg"
self.renderlib = ctypes.cdll.LoadLibrary('./librender.so')
self.renderlib.RenderRender.restype = ctypes.c_void_p
self.renderlib.RenderRender.argtypes = [ctypes.c_void_p,ctypes.c_void_p]
self.renderlib.Render.argtypes = [ctypes.c_char_p]
self.renderlib.Render.restype = ctypes.c_void_p
encoded_model_path = render_model_path.encode('utf-8')
self.render = self.renderlib.Render(encoded_model_path)
def render_image(self,i):
camera_values = np.array([0.5555,-2.17,5.269,2.8359,172.5,-23.99,5*i],np.float32)
elma = self.renderlib.RenderRender(self.render,camera_values.ctypes)
buffer_as_ctypes_array = ctypes.cast(elma, ctypes.POINTER(ctypes.c_void_p*(int(1920*1080*4/8))))[0]
image_anim = np.frombuffer(buffer_as_ctypes_array, np.uint8).reshape(1080,1920,4)
image_anim = np.flipud(image_anim)
cv2.imwrite("render_res"+str(i)+".png",image_anim)
return image_anim
# the threading and parallelization code:
def process_render_cpp():
is_parallel = True
# getting the class
rend = RenderCpp()
if is_parallel:
processes = []
tic = time.time()
for i in range (10):
processes.append(threading.Thread(target=rend.render_image,args=(i,)))
for i in range(len(processes)):
processes[i].start()
time.sleep(0.1)
for i in range(len(processes)):
processes[i].join()
toc = time.time()
else:
for i in range(10):
rend.render_image(i)
if __name__ == "__main__":
process_render_cpp()