AI denoiser help

Couldn´t denoising be triggered once the render has finished?

In fact I would love to have that option for the actual blender denoiser, the feeling is that denoising tile by tile is slower.

Cheers.

3 Likes

I also can imagine that the “AI” needs to work on the complete render result to “understand” caustics and other scatterings that produce a lot of noise correctly.

Cheers

1 Like

I also wonder if it is possible to put the Denoiser in a compositing node, so it can be mixed with the noisy render if some noise is desired for the project like for example in a atomic war scene

1 Like

Hey Brecht,

Ive looked today at the session.cpp and session::release_tile

Am I missing something but assumed there would be a system already added to read the buffers needed but couldn’t find anything (could easily be missing something here as dont know blenders code base well and only a learner coder)

So ive added the ability to read out render buffers fron session.cpp

This is what im thinking to add:

blender_session.h

I then added this:

void read_render_tile(RenderTile& rtile);
====================================================

void write_render_result(BL::RenderResult& b_rr,
	                     BL::RenderLayer& b_rlay,
	                     RenderTile& rtile);
void write_render_tile(RenderTile& rtile);
void read_render_tile(RenderTile& rtile);

==================================================== 

then added bool do_read_only:

void do_write_update_render_tile(RenderTile& rtile,
	                             bool do_update_only,
	                             bool do_read_only,
	                             bool highlight);

=====================================================

blender_session.cpp

then added bool do_read_only:

void BlenderSession::do_write_update_render_tile(RenderTile& rtile,
	                                             bool do_update_only,
	                                             bool do_read_only,
	                                             bool highlight)

then added this:

if (do_read_only) {
		/* copy each pass */
		BL::RenderLayer::passes_iterator b_iter;
	
		for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
		BL::RenderPass b_pass(*b_iter);
		
		/* find matching pass type for buffer read *out */
		PassType pass_type = BlenderSync::get_pass_type(b_pass);
		int components = b_pass.channels();
		    
		   /*In original code get_pass_rect we also have exposure, samples, but as were just looking to copy as image */
		   /*i dont think exposure or samples will be needed*/
		   rtile.buffers->read_pass_rect(pass_type, components, (float*)b_pass.rect());	   
	}
		end_render_result(b_engine, b_rr, false, false, false);
}
else if (do_update_only) {

then add:

void BlenderSession::read_render_tile(RenderTile& rtile)
{
	do_write_update_render_tile(rtile, false, true, false);
}

and change:

void BlenderSession::write_render_tile(RenderTile& rtile)
{
	do_write_update_render_tile(rtile, false, false);
}

to:

void BlenderSession::write_render_tile(RenderTile& rtile)
{
	do_write_update_render_tile(rtile, false, false, false);
}

then under BlenderSession::update_render_tile I add:

 	if(!b_engine.is_preview())
		do_write_update_render_tile(rtile, true, false, highlight);
 	else
		do_write_update_render_tile(rtile, false, false, false);
 }

 and then under BlenderSession::render() add this:


 /* set callback to read out render results */
	session->read_render_tile_cb = function_bind(&BlenderSession::read_render_tile, this, _1);

	and then:

	/* clear render buffer read callback */
	session->read_render_tile_cb = function_null;


============================================================================
	
buffers.h

then added:

bool read_pass_rect(PassType type, int components, float *pixels);

============================================================================

buffers.cpp

then added:

bool RenderBuffers::read_pass_rect(PassType type, int components, float *pixels)
{
	if (buffer.data() == NULL) {
		return false;
	}
		int pass_offset = 0;
	
		for (size_t j = 0; j < params.passes.size(); j++) {
		Pass & pass = params.passes[j];
		
			if (pass.type != type) {
			pass_offset += pass.components;
			continue;	
		}

		float *out = buffer.data() + pass_offset;
		int pass_stride = params.get_passes_size();
		/*Not sure if Brecht would want more than just buffer width/height here and maybe the full tile params. NEED FEEDBACK*/
		int size = params.width*params.height;
		
			assert(pass.components == components);
	
			for (int i = 0; i < size; i++, out += pass_stride, pixels += components) {
			for (int j = 0; j < components; j++) {
				 out[j] = pixels[j];
			}
		}
			return true;
	}
		return false;
	}

===========================================================

session.h

add:

function<void(RenderTile&)> read_render_tile_cb;

===========================================================

session.cpp

add:

if(read_render_tile_cb) {
		/* This will read any passes needed as input for render buffer access. */
		read_render_tile_cb(rtile);
		rtile.buffers->buffer.copy_to_device();
	}
	else {
		/* This will tag tile as IN PROGRESS in blender-side render pipeline,
		 * which is needed to highlight currently rendering tile before first
		 * sample was processed for it. */
		update_tile_sample(rtile);
	}

Is this OK, or is adding this functionality over kill. To be honest having a method now to read render buffers seems handy no matter what so thinking of creating a .diff to upload as this could be helpfull for other things lke if people want to build addons that do things to render buffers for post pro etc

1 Like

This is difficult to follow, please use diffs:
https://wiki.blender.org/wiki/Tools/Patches

I have trouble understanding what this code is trying to do, I’m not sure why the Blender session is involved at all.

yep I wasn’t sure at all if this was what i needed. What im trying to do is just access the render buffers for Combined,Normal,Diffcol to pass the buffers into optix denoiser from session.cpp Session::release_tile

when I looked at rendertile_write and update I wasnt sure if there was a way to read those combined,normal,diffcol buffers from within session.cpp so the code above was meant to add read buffer access to do_write_update_render_tile.

I thought that this would then create ouput buffers of all passes requested but with only image data not other settings like exposure,samples.

if (do_read_only) {
/* copy each pass */
BL::RenderLayer::passes_iterator b_iter;

	for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
	BL::RenderPass b_pass(*b_iter);
	
	/* find matching pass type for buffer read *out */
	PassType pass_type = BlenderSync::get_pass_type(b_pass);
	int components = b_pass.channels();
	    
	   /*In original code get_pass_rect we also have exposure, samples, but as were just looking to copy as image */
	   /*i dont think exposure or samples will be needed*/
	   rtile.buffers->read_pass_rect(pass_type, components, (float*)b_pass.rect());	   
}
	end_render_result(b_engine, b_rr, false, false, false);

}

I looked at your update patch for texture baking to do this but applied to renderbuffers

I thought then that would make passing the buffers in session.cpp to the optix denoiser easier, but im guessing thats a mistake.

How would you of passed the combined,normal,diffcol to the optix buffers in session::release_tile? a few lines of code how you would do this would be a great help

Have i just over complicated everything, should it be just as simple as just using rtile.buffers->copy_to_device() ?

1 Like

Do something like this:

float exposure = scene->film->exposure
int sample = rtile.sample;

rtile.buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, pixels, "Combined"):
rtile.buffers->get_pass_rect(PASS_NORMAL, exposure, sample, 3, normal_pixels, "Normal"):
...
2 Likes

yeah I was massively over complicating this, cheers Brecht

Did you get it working? I would be interested to see/test the code.

2 Likes

What’s the status on this? I’m really interested in seeing OptiX as part of 2.8x. If its on a separate branch, how do I access it/is there an up to date diff?

The OptiX denoiser won’t be a part of 2.80 due to license incompatibility.

Are you sure about that?

Yes, I am sure about that.

Well that’s sad :slightly_frowning_face:

I believe Ton’s tweet was about Optix Ray Tracing not the Optix Denoise.

Can it be in a stand-alone program though? Since cycles is not GPL.

Theoretically yes, practically that makes no sense for Blender.

1 Like

But having the OIDN (The Intel denoiser) why do you want Optix?

I mean… optix works only in Nvidia cards, and it’s the same as OIDN with the exception that OIDN works in any CPU and it’s a compositing node, with is cooler :slight_smile:
Also you already have Optix Denoiser as an addon.

Cheers!

Hi, there are pre build binaries including standalone called “denoise”.
It only work with .pfm image files.
A user with python knowledge and imagemagic can easy include it in to any Blender version.

Cheers, mib

1 Like

It is already included, there is a patch by Stefan Werner that implements OIDN in Blender :slight_smile:

EDIT: It’s not yet in master, but it seems it will be