RenderableComponent not being drawn... why?


#1

I have a custom component which derives from RenderableComponent, very similar to the RenderableCopyMeshComponent in the demo/copystamp example.

No compiler or runtime errors happen, but the meshes I’m creating internally (I do a number of calls to createRenderableMesh in init and add these to a vector) are never drawn.

What’s more curious is that if I place a breakpoint in my virtual void update(double deltaTime) override; method then it is definitely called, but if I place a breakpoint in my onDraw method, it is never called. (My method is defined as protected: virtual void onDraw(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) override;

I’m assuming that the render service thinks there is nothing to render here? In the documentation for RenderableComponentInstance.ondraw(), it states:

This method won’t be called if the mesh isn’t visible!

What defines “visible” here, though? I have a vector of RenderableMesh instances that are ready to go! The component is added to the scene and my main application is not picky about which RenderableComponents should get rendered.

Any ideas why the render service would not even try to call my onDraw method?


#2

You need to render objects explicitly using the render service, similar to rendering meshes. See the many demos for an example. onDraw() is called by the render service when you decide you want to render something.

NAP doesn’t assume you want to render something, it doesn’t know where to render it to. So you, somewhere in onDraw() of your app need to render the object. See documentation:

https://www.napframework.com/doxygen/dd/d9b/rendering.html

Also, the copystamp demo defines a custom renderable mesh component that is drawn using the render service. Might be the best place to start looking when trying to create your own renderable component.

The visibility flag is used by the render service to skip rendering of certain components. onDraw() is called by the render service when the visibility flag is set to true. This is useful when you want to render many components at once and skip certain ones.


#3

Hi @cklosters what you’re saying makes perfect sense, and is how I already understood the situation. However, I’m still not sure why nothing gets drawn.

In my main application I am not excluding anything from render:

`mRenderService->renderObjects(mRenderWindow->getBackbuffer(), *mCameras.at(mCameraIndex));`

This version of renderObjects does not take a list of RenderableComponents, so my assumption is that everything which is renderable in the Scene is therefore going to be rendered? Does the render service step through the Scene tree and find instances that derive from RenderableComponent or is there some other mechanism I need to be aware of?

I am trying to draw something in my onDraw method, but since the program never even calls this function, it’s difficult to say whether I’m doing this correctly.

First step: I need to understand why the RenderService is not even trying to draw my component?


#4

Heya,

I quickly looked into the function that is called in the render service:

	// Render all objects in scene graph using specified camera
void RenderService::renderObjects(opengl::RenderTarget& renderTarget, CameraComponentInstance& camera, const SortFunction& sortFunction)
{
	// Get all render components
	std::vector<nap::RenderableComponentInstance*> render_comps;

	SceneService* scene_service = getCore().getService<SceneService>();
	for (Scene* scene : scene_service->getScenes())
		for (EntityInstance* entity : scene->getEntities())
			entity->getComponentsOfType<nap::RenderableComponentInstance>(render_comps);

	// Render these objects
	renderObjects(renderTarget, camera, render_comps, sortFunction);
}

When calling the generic render all function the default sorter is used and all renderable component instances are accepted. The render function is called after finding all the accepted renderable component instances.

In that render call a component is rendered when it is visible (isVisible()) and the camera it wants to render the component with is considered valid (isSupported(camera)). Some components cannot be rendered with a perspective camera for example (2D text). By default a component is visible and all cameras are accepted.

To verify that your onDraw() method is called you could try to explicitly render that component. Try to fetch it from your entity and call renderObjects(buffer, camera, components). If the on draw call is still not called it means the onDraw() call is not overridden correctly.

From what I know others have successfully implemented their own renderable components without any problems. It is worth having a look at the copystamp demo. Although that one explicitly renders all components it does work. If that works and your explicit call to render your object calls into onDraw() there is something wrong with the render all function.

Cheers Coen


#5

Yup, this is the exact one I was using as a reference for my own project, so this is why it’s curious that it doesn’t seem to be working (yet).

As you say, I will try to explicitly render my component, and see what happens.


#6

Indeed, when I tell the render service to explicitly render that component, then onDraw is called as expected.

Does this mean there is a bug in the version of the function that is meant to render “all” components?


#7

Hey,

Looks like something is indeed wrong with the generic render all method. Although it does look like the call internally queries all derived renderable mesh components it fails to pick up yours. I’ll try to repro it on my end commit a fix.

I personally never use that render function because I tend to render things explicitly into their respective targets. Also to ensure things are rendered together to the right target.

Cheers Coen


#8

Looks like I found the culprit:

class NAPAPI RenderableCopyMeshComponentInstance : public RenderableComponentInstance
{
RTTI_ENABLE(ComponentInstance)

should be:

class NAPAPI RenderableCopyMeshComponentInstance : public RenderableComponentInstance
{
RTTI_ENABLE(RenderableComponentInstance)

The instance in the copy stamp demo is not rtti declared to be derived from RenderableComponentInstance, but from ComponenInstance, when I change the RTTI_ENABLE macro to:

RTTI_ENABLE(RenderableComponentInstance)

Everything works as expected. Can you make sure you derive your custom component from RenderableComponentInstance and rtti declare it as such?

By declaring it to be a default component the render service skips it when it tries to find all valid components to draw.

Cheers Coen!


#9

Thanks @coen this will be a good fix!