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?
Textures don't reach image resolution when rendered
Moderators: ChrisHekman, aoktar
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
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
3930k / 16gb / 780ti + 1070/1080 / psu 1600w / numerous hw
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: 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?
Regards
Milan
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: 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?

Regards
Milan
Colorist / VFX artist / Motion Designer
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
Hey Milanmilanm 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?
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.
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.
.
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.
Cheers
Milan
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.

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.
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;
}
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
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780
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

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

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

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
macOS - Windows 7 - Cinema 4D R19.068 - GTX1070TI - GTX780