Custom Camera

On 29/04/2014 at 15:33, xxxxxxxx wrote:

User Information:
Cinema 4D Version:    
Language(s) :

Hi all,

I'm trying to create a custom camera using VideoPostData, overriding CreateExtendedRay and setting GetRenderInfo to return VIDEOPOSTINFO_CUSTOMLENS_EXTENDED.

I've got the plugin registered, and it appears in the list of effects in render settings and I can apply it, but it seems to make no difference to the render and may not even be getting called (Nothing shows up when I add GePrint statements within the create ray function).

There's a whole bunch of questions which occur, so apologies if there's too much, but I'm not at all familiar with Cinema4D.

First is, is this even the correct type of plugin in order to make a custom camera (where I control the ray direction)? It was hard to tell as the examples say VideoPostData plugins are called after rendering in the comments at the top (which makes the idea of controlling ray direction in one seem like it wouldn't work, but there's an API for it, so I figured it should).

How do I get access to the camera and render settings from within the Create*Ray functions? At the moment I'm only using extended in order to know the range of x and y.

What space is the created ray in? If it's not in the camera's local space, how can I grab the transform matrix from camera space to whatever space the ray is expected in? (This kinda ties into the last question)

Is the renderer linked into the executable? i.e. is the cinema4d executable what I should be attaching my debugger to in order to debug shaders?



On 02/05/2014 at 06:36, xxxxxxxx wrote:

Hi Alan,

did you register your VideoPostData plugin with VIDEOPOSTINFO_CUSTOMLENS_EXTENDED, since
you say you only used the "extended version" of the function? (aka CreateExtendedRay()).

The VideoPost concept is a bit confusing. They can do a lot of different stuff, not just processing the
final image of the render.


On 02/05/2014 at 13:00, xxxxxxxx wrote:

Hi Niklas,

Thanks for the reply. Yes, I did that in GetRenderInfo, is that correct? Here's the class declaration (which also includes the definition of GetRenderInfo).



class SphericalCamera : public VideoPostData
		static NodeData *Alloc(void) { return gNew SphericalCamera; }
		virtual Bool RenderEngineCheck(BaseVideoPost *node, LONG id);
		virtual VIDEOPOSTINFO GetRenderInfo(BaseVideoPost *node) { return VIDEOPOSTINFO_CUSTOMLENS_EXTENDED; }
		virtual void CreateExtendedRay(Ray *dst, Real x, Real y, Real lensx, Real lensy, Real time);

On 05/05/2014 at 11:12, xxxxxxxx wrote:

Hi again,

So I have gotten a little further. If I use CreateRay and change it to VIDEOPOST_INFO_CUSTOMLENS instead, then it gets called. I've now got it rendering, and it seems that the ray is in world space.

Now, I just need to get the transform from camera to world space to apply to my rays and find out how to get the image resolution. At the moment I've just hard coded it in order to get it working.

Any pointers on how to grab that info would be great.



On 05/05/2014 at 14:37, xxxxxxxx wrote:

Alrighty, so I've now got something that works. Though I'm not sure it's the correct way for some aspects.

One bit that surprized me, is the _api project needs to modify the resource/_api_lib directory to put your api lib to link against.

As far as camera transform, I GetActiveDocument, then GetRenderBaseDraw, then GetSceneCamera. This seems unlikely to be correct, as Render View does not change to reflect the camera being used. Render to Picture Viewer does always reflect the camera in the perspective view, though.

There is a similar issue with resolution, which I'm getting via GetActiveRenderData from the ActiveDocument, then calling GetParameter for RDATA_XRES and RDATA_YRES. These values always reflect the render settings (used when rendering to picture view) and the resolution rendered in Render View.

What's the correct way to get the render information so that it always reflects what the renderer is requesting?



On 05/05/2014 at 15:23, xxxxxxxx wrote:

Okay, I got that figured out too now.

For anyone else trying something similar. You need to first override Execute. Then, during VIDEOPOSTCALL_RENDER (check vps->vp to know when this call is occuring), grab the values you need and cache them in your object. For me, it was the resolution and the matrix.

The resolution is

BaseContainer renderData = vps->render->GetRenderData();
xRes = renderData.GetReal(RDATA_XRES);
yRes = renderData.GetReal(RDATA_YRES);

Then for the camera's transform matrix.

RayCamera * rayCamera = vps->vd->GetRayCamera();
if (rayCamera)
	cameraToWorld = rayCamera->m;

I didn't include null checks in the first one's code snippet, but make sure you do.

I'm not certain all of this is the intended way to use this, but it works.



On 06/05/2014 at 10:13, xxxxxxxx wrote:

BTW, I couldn't find any details about multi-threading. This hasn't broken yet, so either the renderer is not multi-threading, is creating an instance of my class per thread, or I'm lucky and somehow the timing has worked such that one thread is not trampling the values another set before the other used it.

I'm also not sure if there's a better way to get the camera matrix. As vd is only non-null for VIDEOPOSTCALL_RENDER and VIDEOPOSTCALL_INNER, I am fetching the matrix for every sample, whereas I really should be able to do it per frame. (Well, unless we have varied time per samples and it evaluates the camera's position at the moment in time for the sample, in which case I'd need every sample for motion blur to work correctly).

Anyway - lots of open questions, but works so far for the basic case.