Textures don't reach image resolution when rendered

Maxon Cinema 4D (Export script developed by abstrax, Integrated Plugin developed by aoktar)

Moderators: ChrisHekman, aoktar

User avatar
slepy8
Licensed Customer
Posts: 377
Joined: Sun Jul 14, 2013 10:53 am

It appears, rendered images are not as sharp as base textures.
It has been posted on this forum several times but never with an explanation from devs.

Here are two examples.
Filter size: 1.0
no DoF
image is a png16 file from Image Texture node.
Comparison is made between the texture and the rendered plane with this texture applied.
Camera has been tweaked to leave zero distortion.

Is there any solution to this? Or any explanation?
Attachments
Screenshot_1.jpg
Screenshot_4.jpg
frankmci
Licensed Customer
Posts: 917
Joined: Fri May 26, 2017 2:00 pm
Location: Washington DC

As far as I know, the only way you are going to get a 1:1 perfect texture is by using a Background Object or equivalent. No matter what, your 2D textures applied to objects in 3D space are going through an insanely complex set of samplings and transformations including all the algorithms describing the interaction of light with a surface, a lens, etc, before being sampled back down to 2D. There is going to be resampling and image quality loss. The old rule of thumb I still use is that a texture should be at least 1.5x the resolution you expect to see it rendered on screen. Even better, 2x.
Animation Technical Director - Washington DC
User avatar
slepy8
Licensed Customer
Posts: 377
Joined: Sun Jul 14, 2013 10:53 am

Hi Frank

Thanks for your reply.

I made a test with 2X texture and it looks better, but still is slightly blurry.

I'd still like devs to take part in discussion.
User avatar
aoktar
Octane Plugin Developer
Posts: 16066
Joined: Tue Mar 23, 2010 8:28 pm
Location: Türkiye
Contact:

It's not a matter of plugins. You may ask in general forum to Otoy devs.
Octane For Cinema 4D developer / 3d generalist

3930k / 16gb / 780ti + 1070/1080 / psu 1600w / numerous hw
milanm
Licensed Customer
Posts: 261
Joined: Tue Apr 30, 2013 7:23 pm

Hi

There's no mystery here. Resolution of textures in Octane is perfectly fine. Texture filtering is absolutely necessary in computer graphics and it's partly the reason why your textures seem smoother.

Think of your textures as 3D models, not as images. If you want to see 'pixel for pixel' accuracy you would have to model the pixels. Trivial thing to do in OSL.

A 5 min. search led me to this cool OSL shader. I adapted it and... voila:
pixelated UV.PNG
You could get the resolution from the texture map automatically and use the code above for UVs. I've no time to put this together now but why should I even bother, you don't seem to care about any of this since I'm not a core developer. Why am I even wasting my god damn time here? :roll:

Regards
Milan
Colorist / VFX artist / Motion Designer
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
milanm
Licensed Customer
Posts: 261
Joined: Tue Apr 30, 2013 7:23 pm

Ah, what the heck, here you go, this was too easy. 8-)
hashtag nofilter.JPG
UnfilteredTextures.zip
(912 KiB) Downloaded 1328 times
Hashtag nofilter.

Cheers
Milan
Colorist / VFX artist / Motion Designer
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
User avatar
slepy8
Licensed Customer
Posts: 377
Joined: Sun Jul 14, 2013 10:53 am

milanm wrote:you don't seem to care about any of this since I'm not a core developer. Why am I even wasting my god damn time here?
Hey Milan
No need for this kind of tone.

I thought devs would explain this whole matter the best way since they know exactly what's inside.

Thanks for your explanation. It makes sense. I admit I did not do any research on this, but to be honest I didn't even know what to look for.

Thanks again. I see I'll have to do a deep dive into OSL now. :)

Thanks again.
Have a good day.
milanm
Licensed Customer
Posts: 261
Joined: Tue Apr 30, 2013 7:23 pm

Hi, apologies for the tone.

Edit: Removed the melodrama.

I'm pretty sure they just wanted to avoid renders from Octane looking like Wolfeinstein game from '92. :)

Anyway, yesterday I took an hour to improve the code a bit and ended up with my own ImageTexture node, haha. :shock:.
So you don't need to dive into OSL if you don't want to. But i recommend it!

In addition to filtering, It has support for proper sRGB IEC 61966-2-1 colorspace plus an option to set order of operation for inversion. To my knowledge, It's only missing texture wrap modes and 'Power' option. Feel free to reuse, adapt and learn from it. I made a C4D preset too so using OSL in C4D comes down to drag and drop. No need for coding.

Good luck getting responses from core devs and I hope this sparks a bigger conversation, not just about texture filtering but also about color spaces and proper color management.
osl imagetexture lib4d.zip
(19.54 KiB) Downloaded 420 times
ImageTextureNode.JPG

Code: Select all

// Proof of concept ImageTexture node for OctaneRender.
// Code that 'disables filtering' is based on a method from Image2Screen shader by François GASTALDO.
// sRGB response calculation is based on the OCIO python source codes by Haarm-Pieter Duiker.
// Feel free to reuse and adapt.
//
// Cheers
// milanm.

shader mm_ImageTexture(
	string File = "1",
	int ToneResponse = 0
	[[
  	string widget = "mapper",
  	string options = "sRGB (IEC 61966-2-1):0|Gamma 2.2:2|Linear:3|Custom Gamma:4"
	]],
	int InversionOrder = 1
	[[
  	string widget = "mapper",
  	string options = "Before Linearizing:0|After Linearizing (classic):1"
	]],
	float Gamma = 2.2 [[ float min=0.01, float max=10 ]],
	int Filtering = 1 [[string widget = "checkBox"]],
	int Invert = 0 [[string widget = "checkBox"]],
	point Projection = P,
	output color pixeltex = color ( 1.0 , 1.0 , 1.0 ),
	)

{
	// get resolution of the texture as integer
	int res[2];
	gettextureinfo(File, "resolution", res);
	
	// Convert res to float so that we can
	// find the size of one half of pixel
	float resX = res[0];
	float resY = res[1];
	
	// Half pixel offset as float
	float oX = (1/resX)/2 ;
	float oY = (1/resY)/2 ;

	// Pixelate the UVs if filtering is disabled
	point pixelateduv = color ( 0.0 , 0.0 , 0.0 ) ;

	if (Filtering==0) {	
	pixelateduv[0] = ( trunc( Projection[0] * (res[0]) ) ) / (res[0]) ;
	pixelateduv[1] = ( trunc( Projection[1] * (res[1]) ) ) / (res[1]) ;}
	else {pixelateduv[0] = Projection[0]; pixelateduv[1] = Projection[1];}
	
	// lookup the colors from texture file + add half pixel offset to UVs if filtering is disabled
	color col;

	if (Filtering==0) {
	col = texture( File, pixelateduv[0]+oX, pixelateduv[1]+oY );
	}
	else {
	col = texture( File, pixelateduv[0], pixelateduv[1] );
	}	

	if (Invert==1&&InversionOrder==0) {col = 1-col;}
	
	color lin;

	// sRGB (IEC 61966-2-1)

	if (ToneResponse==0)
	{
		float a = 1.055;
		float b = 0.04045;
		float d = 12.92;
		float g = 2.4;
		
		if (col[0] < b) {lin[0] = col[0] / d;}
		else {lin[0] = pow(((col[0] + (a - 1)) / a), g);}

		if (col[1] < b) {lin[1] = col[1] / d;}
		else {lin[1] = pow(((col[1] + (a - 1)) / a), g);}

		if (col[2] < b) {lin[2] = col[2] / d;}
		else {lin[2] = pow(((col[2] + (a - 1)) / a), g);}
	}
	
	// Gamma 2.2
	
	else if (ToneResponse==2)	{lin = pow(col, 2.2);}
	
	// Linear
	
	else if (ToneResponse==3)	{lin = col;}
	
	// Custom gamma
	
	else	{lin = pow(col, Gamma);}
	
	if (Invert==1&&InversionOrder==1) {lin = 1-lin;}
	
	pixeltex = lin;

}
Cheers
Milan
Last edited by milanm on Wed Jan 16, 2019 4:18 pm, edited 1 time in total.
Colorist / VFX artist / Motion Designer
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
User avatar
slepy8
Licensed Customer
Posts: 377
Joined: Sun Jul 14, 2013 10:53 am

The last thing I wanted to to is generating shitstorm in this thread :)
But according to my recent posts I understand your reaction ;)

I just wanted to get some knowledge on the issue or the workaround. And I see you developed the second one which I really appreciate (and to be honest didn't expect).
I'll give it a try straight away.

Thanks again!
I have a bit more knowledge now :)
milanm
Licensed Customer
Posts: 261
Joined: Tue Apr 30, 2013 7:23 pm

slepy8 wrote:But according to my recent posts I understand your reaction ;)
Oh no, no, not those posts. There are far, far worse examples from other users than your recent posts. :)

I should have mentioned that everything that frankmci said still stands and I agree with that. So for sharpest (1:1) results you'll also have to adjust filter in the Camera Imager to minimum. It's just almost theoretically impossible (IMHO) to have the size of pixels in the textures to always perfectly mach the size of pixels in the render with all of the perspective projection, dof, antialiasing and 'RGB-to-spectral-and-back' calculations. Uprezing textures is still a superior method. The lower the resolution of your textures, the more they will be affected by texture filtering. Hopefully, you'll be able to see that for yourself with that OSL node.

Correction: Having textures with resolution higher than the final render resolution is a superior method. Upscaling textures with low resolution will just blur them out even more.

Regards
Milan
Colorist / VFX artist / Motion Designer
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
Post Reply

Return to “Maxon Cinema 4D”