Dev:2.8/Source/Viewport/EngineAPI

提供: wiki
移動先: 案内検索

Engine API

This API aims to provide a simple way to create a whole Opengl/Vulkan rendering pipeline inside Blender. The Engine is in charge of rendering to a buffer that will be composited with all Blender specific Overlays on top of it.

Drawing Pipeline

The viewport drawing function would look like this (pseudo C code):

// This function pretty much dispatch object lists to passes
void draw_viewport(RenderEngine *re, View3D *v3d){
	
	// Setup Color and Depth buffer (always)
	// Create optional Framebuffers needed by the render engine
	// Store them in View3D
	setup_buffers(re, v3d);

	if (use_probes)
		update_probes(re);
	if (use_shadows)
		update_shadows(re);

	if (is_realtime_engine) {
		re->type->view_realtime(); // <- here we plug our render pipeline
	}
	else {
		re->type->view_draw();
	}

	// Draw wire for objects that needs it
	wire_pass();

	// Draw anything Mode-related
	switch(mode){
		case OBJECT:
			object_pass();
		case EDIT:
			edit_pass();
		...
	}

	region_info();
}

It's pretty straight forward. What we will expose to Render engines is the view_realtime() function. This function will have to make draw calls to fill the color buffers that will be composited with the rest of the passes.

Engine API

In short what a RenderEngine do is :

  • Define glsl shaders
  • Define needed screen buffers
  • Create a view_realtime method that renders a frame to the viewport
  • Create a render_ogl method that outputs a frame as final render

In order to support a large range of techniques, the API must allow us to :

  • Draw Geometry in batches with different states
  • Create our own utility Shaders
  • Get Shader from Materials Nodes
  • Bind framebuffers

To achieve this, we propose the following DRW module which is a wrapper of all blender's GPU modules. It will be fairly high level and concise. Preferably all of what the engine can do is in this DRW module. It will obviously be extended and adjusted as the engines development progresses.

// DRW_engines.h

struct DRWBatch{
	DRWBatch *next, *prev;    // Linked list
	GPUGeometry *geometry;    // List with all objects and transform
	GPUShader *shader;        // Shader to bind
	GPUInterface *interface;  // Uniforms values
};

// Create custom shader to store in RenderEngineType
GPUShader *DRW_shader_create(char *vs_glsl, char *gs_glsl, char *fs_glsl);

// Main draw function everything else is shortcut functions
// Draw a batch by switching the less resources possible
// flags for things like backfacecull, depth test...
static void DRW_draw_batch(DRWBatch *batch, int flags, ...);

// Draw batches in order to avoid state changes
void DRW_draw_batch_list(ListBase *blist);
void DRW_draw_fullscreen(GPUShader *shader, GPUInterface *interface);
void DRW_draw_depth(DRWBatch *batch);

// Frame buffer operations (for deffered rendering or other effects (DOF))
void DRW_bind_framebuffer(GPUFramebuffer *fb);
void DRW_unbind_framebuffer(GPUFramebuffer *fb);

// Shortcut functions to draw background
void DRW_background_world(Scene *scene);
void DRW_background_default();

// Shortcut function to batch surfaces by material (can be reused by engines that use materials)
ListBase *DRW_create_material_batches(ListBase *ob);
// RE_engine.h
struct RenderEngineType {
	...
	void (*render_realtime)(struct RenderEngine *engine, struct Scene *scene);
	void (*view_realtime)(struct RenderEngine *engine, const struct bContext *context);

	ListBase *gpushaders; // Allocated GPUShaders to draw with
	ListBase *gpufbdescs; // Describe each FBO to generate for this RE.
	...
}

Ideally each overlay passes (wire/overlays) should be composited on top of the render pass using different buffers. As it may decrease performance and add code complexity we will try to render overlay passes to the same color buffer.

How to expose this API through Python is still under discussion.

Clay Engine

First example using this API is the Clay Engine.

From the user persperctive :

  • Not compatible with nodetree (grey nodes)
  • Matcap is defined at Material Level with Layer override and (maybe) object override
  • Material Panel Reflect this

From the Engine perspective :

  • Define matcap property inside RNA
  • Define only one shader
  • Optimize drawing as much as possible
void view_realtime(RenderEngine *re, ListBase *objs){
	ListBase *batches;

	DRW_background_default(gradient);

	// Depth Prepass performance boost depends on shading complexity and overdraw
	// So it might not be needed in all cases
	if (ao)
		DRW_draw_depth();

	// Matcap rendering
	if (!re->gpushader) {
		DRW_shader_create(matcap_vert_glsl, NULL, matcap_frag_glsl);
	}
	
	batches = Batch_by_matcap(objs); // Make Batches

	// Draw Meshes
	DRW_draw_batch_list(batches);

	// Post Processes
	DRW_fullscreen(dof_shader);
}

Workbench Engine

  • Reuse basically the same API that the Clay Engine is using
  • Draw floor plan with drawing command
  • Uses Custom Shadows


Eevee Engine

This one is far more complex. What will be required:

  • Getting Nodetree Materials (With new PyNode GLSL API)
  • Transparency rendering
  • Probe rendering
  • Lamps Shadows


At this stage, we expect the Engine API to grow big enough to support all sort of fancy rendering this engine will support.