Python ShaderData/ChannelData problem [SOLVED]

On 16/12/2014 at 00:43, xxxxxxxx wrote:

Hi,

this topic is also somehow related to another one by me in the C++ section of this forum:
Custom Tile Shader problem with previews

I tried to translate my test shader that you can find in the link above to Python.
Just because it makes prototyping such stuff more comfortable that you can simply reload registered Python plugins in C4D after source code changes.

But unfortunately I run into a problem here too.

Any manipulations I try to make to "cd.p" are ignored.

Here is the source code:

  
#############################################################  
## CINEMA 4D Python Tile Shader Test                       ##  
#############################################################  
## by Thomas Chen (2014)                                   ##  
#############################################################  
## Py-TileShaderTest.pyp                                   ##  
#############################################################  
  
import c4d  
from c4d import plugins  
  
  
#warning Please obtain your own plugin ID from http://www.plugincafe.com  
PLUGIN_ID = 1000010  
  
  
class TileShaderTest(plugins.ShaderData) :  
  
  tiles = 1  
  texture = None  
  
  
  def __init__(self) :  
      #if a Python exception occurs during the calculation  
      #of a pixel colorize this one in red for debugging purposes  
      self.SetExceptionColor(c4d.Vector(1.0, 0.0, 0.0))  
  
  
  def Init(self, node) :  
      #Called when a new instance of the node plugin has been allocated.  
  
      node[c4d.TILESHADERTEST_TILES] = self.tiles  
      node[c4d.TILESHADERTEST_TEXTURE] = self.texture  
  
      return True  
  
  
  def InitRender(self, sh, irs) :  
      #Precalculate any data for rendering.  
  
      self.tiles = sh[c4d.TILESHADERTEST_TILES]  
        
      self.texture = sh[c4d.TILESHADERTEST_TEXTURE]  
      if self.texture:  
          self.texture.InitRender(irs)  
   
      return 0  
  
  
  def FreeRender(self, sh) :  
      #Free any resources used for the precalculated data from InitRender()  
        
      if (self.texture) :  
          self.texture.FreeRender()  
        
      self.texture = None  
  
  
  def Output(self, sh, cd) :  
      #Called for each point of the visible surface of a shaded object. Here you should calculate and return the channel color for the point cd.p.  
  
      cd.p.x = cd.p.x * self.tiles  
      cd.p.y = cd.p.y * self.tiles  
        
      col = c4d.Vector(0.0, 0.0, 0.0)  
        
      if self.texture:  
          col = self.texture.Sample(cd)  
   
      return col  
  
  
def RegisterTileShaderTest() :  
    
  return plugins.RegisterShaderPlugin(PLUGIN_ID, "Py-TileShaderTest", 0, TileShaderTest, "xtileshadertest", 0)  
  
if __name__ == '__main__':  
  RegisterTileShaderTest()  
  

That seams to have no effect at all:

        cd.p.x = cd.p.x \* self.tiles  
      cd.p.y = cd.p.y \* self.tiles

I also tried to hardcode different values for "tiles" and to assign different formulas and hardcoded values to "cd.p" too.

The output is always the complete texture at the whole uv area when I return:

        self.texture.Sample(cd)

Any idea what I miss here?

Kind regards,
Tom

On 16/12/2014 at 11:54, xxxxxxxx wrote:

Hello Tom,

just assign cd.p to a variable first, like:

  
  def Output(self, sh, cd) :  
        
      x = cd.p.x *1.8  
      y = cd.p.y *1.8  
      z = cd.p.z  
      cd.p = c4d.Vector(x,y,z)  
  
      col = c4d.Vector(0.0, 0.0, 0.0)  
  
      if self.texture:  
          col = self.texture.Sample(cd)  
      return col  

Best wishes
Martin

On 16/12/2014 at 12:22, xxxxxxxx wrote:

again,

I´ve just read your c++ post more closely.

for the other issues you can set some texflags.

cd.texflag= 0
or
cd.texflag= c4d.TEX_TILE

Hope this helps?

Best wishes
Martin

On 16/12/2014 at 13:41, xxxxxxxx wrote:

Hi Martin,

thank you very much for your replies!
I'll try that immediately. 😉

But just for my understanding can you explain to me why this extra step with additional variables is necessary at all to assign new values to cd.p?
That would be really nice from you .
I just can't see the logic behind it but I want to grok what I have to do and why.

~~And for the other thing with  ~~

 ~~     cd.texflag = c4d.TEX_TILE~~

~~or
~~

 ~~     cd.texflag = 0~~

I have still tried that myself before (at least the first version) but unfortunately I can't see any effect at all. Do you also have tried that yourself and it really worked for you?

Kind regards,
Tom

Edit:
I now implemented your tip with the extra variables and of course it works! Smile
Though I still don't understand why but nevertheless, thank you again for that valuable hint.

Edit 2:
Strange, meanwhile I also had success with cd.texflag = c4d.TEX_TILE.
Maybe the refresh hadn't worked as I tried that the first time or I don't know what the problem was.
At least it works partly in a way that all the previews and the tiling behave as expected but the mirroring is prohibited completely and the mix with no mirroring internally but the option with seamless mirroring of the shader output as a whole didn't work that way.
(Like this: or this: )

Only for the editor preview but not for the rendering.
But that would just be the cherry on the cake and I can deal with the current result too if no one knows the perfect solution.

Know I just have to implemenrt that in my C++ version in a similar way. 😉
But I have to check that out tomorrow.

On 17/12/2014 at 03:15, xxxxxxxx wrote:

Hi Tom,

I´m glad it is working for you!
to edit 2:
sometimes you need to delete the shader and open another one to make your script changes happen
after you´ve reloaded python shader plugin.
I´ve no experiences with this, but I guess you´ve allready tried _the   c4d.TEX_MIRROR flag?
_Please let me know if you found out about the cherry.
For further explanations why we need a variable, please ask the support team.

Best wishes
Martin

On 17/12/2014 at 15:56, xxxxxxxx wrote:

Hi Tom,

Although I'm not a Python expert, apparently the *= operator exists in Python, just like in C/C++.  Why not try that out?

Example:

  
cd.p.x *= self.tiles  
cd.p.y *= self.tiles  

BTW, there should be no reason to have to use intermediate variables.  The only reason off the top of my head is type mismatch or a close equivalent.  Specifying that it's a Vector() is the only notable difference with monkeytack's working code.

I hope that helps,

Joey Gaspe
SDK Support Engineer

On 17/12/2014 at 16:28, xxxxxxxx wrote:

Hello Joey,

your example wont work.
Please give it a try.
As your are much more a programmer than me, it would be nice to understand what´s going on.

Best wishes
Martin

On 18/12/2014 at 02:47, xxxxxxxx wrote:

Hi Joey,

Martin is right that makes no difference.
And how should it as [ _ a *= b_ ] is the same as [ _ a = a * b_ ]?

But I figured out that it just don't work if you try to assign the single components of the vector seperately (what isn't really necessary for my simple example here but it might be for more complex ones)

So the following works:

cd.p *= self.tiles

as well as:

cd.p = cd.p * self.tiles

But as mentioned above it doesn't work with cd.p.x , cd.p.y and cd.p.z.

And as I said, I have no idea why that is.
(But I'd still like to understand! 😉)

Kind regards,
Tom

On 18/12/2014 at 07:18, xxxxxxxx wrote:

Hi guys,

You have a point, and it's on our side, not Python itself.  I found out that this is actually a known issue in Cinema 4D's own Vector Python code, and so will be logged as a defect.

In the mean time, you'll have to use the workaround you've found, so I'll close the topic.

Thanks,

Joey Gaspe
SDK Support Engineer