Get linear shaders

  • On 14/11/2014 at 18:36, xxxxxxxx wrote:

    Using shader.initRender() I am rendering out a shader, however I can't get the InitRenderStruct() to be linear. In the docs I have found InitRenderStruct.linear_workflow but this feature is read only. how do I set this value to True?

  • On 17/11/2014 at 06:34, xxxxxxxx wrote:


    the Python implementation expects the IRS to be initiated by Cinema. So I'm afraid it is not possible to edit an ad hoc created IRS.

    Best wishes,

  • On 08/01/2015 at 10:35, xxxxxxxx wrote:

    Finally got the chance to pick this project back up. It seems that I may not be facing a linear issue. Here are some examples of output:

    Original (How the cinema shader preview sees it) :
    _<_img src="" height="512" width="512" border="0" /_>_

    This is what I get when I use initRender() :
    <_<_img src="" height="512" width="512" border="0" /_>_" />

    and here is what I get when I add a Gamma correction:_r="0" />

    So as you mentioned before I am guessing the IRS is not respecting the project color-space. Is there a way around this? How is the shader preview being rendered?

  • On 09/01/2015 at 07:23, xxxxxxxx wrote:

    Hi Shawn,

    InitRenderStruct.linear_workflow is passed to InitRender() so that shaders can check if they have to perform some color conversion to InitRenderStruct.document_colorprofile.
    c4d.utils.TransformColor() can then be called to return the expected color from Output().

  • On 09/01/2015 at 08:23, xxxxxxxx wrote:

    I really appreciate the help Yannick, worked like a charm! Thank you.

  • On 09/01/2015 at 12:54, xxxxxxxx wrote:

    Looks like I spoke to soon. The scene I was testing in had the color profile disabled. This is what it looks like in a default scene:

    _<_img src="" height="278" width="633" border="0" /_>_

    <_<_img src="" height="278" width="633" border="0" /_>_" />


    COLORSPACETRANSFORMATION_LINEAR_TO_VIEW_<_img src="" height="278" width="633" border="0" /_>_order="0" />

    COLORSPACETRANSFORMATION_SRGB_TO__<_img src="" height="278" width="633" border="0" /_>_3" border="0" />

    So, I guess I'm Back to the drawing board. Am I missing something?

  • On 09/01/2015 at 12:59, xxxxxxxx wrote:

    This is how I am getting the color:

    s = shader.Sample(cd)
    s = c4d.utils.TransformColor(s,profile)
    r = int(s.x * 255)
    g = int(s.y * 255)
    b = int(s.z * 255)
    bmp.SetPixel(x, y, r, g, b)

  • On 12/01/2015 at 01:39, xxxxxxxx wrote:

    Hi Shawn,

    The Cinema 4D shaders usually transform their input colors (in InitRender()) using irs.TransformColor() that calls the global TransformColor() according to the irs.linear_workflow state and irs.document_colorprofile.
    InitRenderStruct.TransformColor() isn't defined in the Python API but its code is simple and included in the C++ API. Following is its code converted to Python:

    def TransformColor(irs, input) :
      if irs.linear_workflow and irs.document_colorprofile is c4d.DOCUMENT_COLORPROFILE_SRGB:
        return c4d.utils.TransformColor(input, c4d.COLORSPACETRANSFORMATION_SRGB_TO_LINEAR);
      elif not irs.linear_workflow and irs.document_colorprofile is c4d.DOCUMENT_COLORPROFILE_LINEAR:
        return c4d.utils.TransformColor(input, c4d.COLORSPACETRANSFORMATION_LINEAR_TO_SRGB);
      return input;

    You should use this TransformColor() for the color sampled in your shader.
    Note that c4d.utils.TransformColor() expects a COLORSPACETRANSFORMATION value as second parameter, not a DOCUMENT_COLORPROFILE value.
    Also be sure that the bitmap in your shader uses the appropriate color profile.

  • On 12/01/2015 at 14:50, xxxxxxxx wrote:

    I am not sure I follow. Using your code above I get the same result: the output is not the same. So when you say that the bitmap must use the correct profile. Does that mean that the bitmap I am creating must also have a profile attached to it?

    playing with c4d.bitmaps.ColorProfile.GetDefaultLinearRGB() and adding it to the bitmap has no influence on the output.

    here is the code I have for better understanding:

    from __future__ import division
    import c4d,timeit
    from c4d import Vector, bitmaps, gui
    from c4d.bitmaps import ShowBitmap
    from c4d.modules.render import ChannelData, InitRenderStruct
    # Bitmap maker created by Shawn Frueh
    class BasicDialog(gui.GeDialog) :
        RENDER = 10000
        SHADERLINK = 10001
        GROUP_SIZE = 10002
        WIDTH_TEXT = 10003
        WIDTH = 10004
        HEIGHT_TEXT = 10005
        HEIGHT = 10006
        GROUPFIT = 10007
        PROGRESS = 10008
        GROUP_PERCENT = 10009
        PROGRESS_SLIDER = 10010
        GROUP_OF_GROUPS = 10011
        RENDER_BIT = 10012
        GROUP_ALL = 10013
        PROFILESELECT = 10014
        RENDERINFO = 10015
        def CreateLayout(self) :
            self.SetTitle("Shader Renderer")
            self.GroupBegin(self.GROUPFIT,c4d.BFH_SCALEFIT, cols = 2)
            bc = c4d.BaseContainer()
            bc.SetBool(c4d.BITMAPBUTTON_BUTTON, True)
            self.myBitButton=self.AddCustomGui(self.RENDER_BIT, c4d.CUSTOMGUI_BITMAPBUTTON, "Bend", c4d.BFH_CENTER | c4d.BFV_CENTER, 64, 64, bc)
            bmp = bitmaps.BaseBitmap()
            self.GroupBegin(self.GROUP_ALL, c4d.BFH_SCALEFIT, cols = 1)
            self.AddComboBox(self.PROFILESELECT, c4d.BFH_SCALEFIT)
            self.AddCustomGui(self.SHADERLINK, pluginid=c4d.CUSTOMGUI_LINKBOX, name="Link", flags=c4d.BFH_SCALEFIT, minw=200, minh=0) 
            self.GroupBegin(self.GROUP_SIZE,c4d.BFH_SCALEFIT, cols = 4, title = "Render Size")
            self.AddStaticText(self.WIDTH_TEXT, c4d.BFH_LEFT, name = "Width")
            self.AddEditNumber(self.WIDTH, c4d.BFH_SCALEFIT)
            self.AddStaticText(self.HEIGHT_TEXT, c4d.BFH_LEFT, name = "Height")
            self.AddEditNumber(self.HEIGHT, c4d.BFH_SCALEFIT)
            self.GroupBegin(self.GROUP_PERCENT,c4d.BFH_SCALEFIT, cols = 3)
            self.AddButton(self.RENDER, c4d.BFH_LEFT, name = "Render")
            self.AddStaticText(self.PROGRESS,c4d.BFH_LEFT,name = " 100%!")
            self.AddSlider(self.PROGRESS_SLIDER, c4d.BFH_SCALEFIT)
            self.AddStaticText(self.RENDERINFO, c4d.BFH_LEFT, name = "Please add a shader.", initw = 500)
            return True
        def InitValues(self) :
            self.SetString(self.PROGRESS," 0%")
            self.SetReal(self.PROGRESS_SLIDER, 0.0,min = 0, max = 100.0)
            self.SetInt32(self.WIDTH, 512, max = c4d.MAXLONGl)
            self.SetInt32(self.HEIGHT, 512, max = c4d.MAXLONGl)
            self.AddChild(self.PROFILESELECT, self.CS_NONE,"None")
            self.AddChild(self.PROFILESELECT, self.CS_L_TO_S,"Linear to SRGB")
            self.AddChild(self.PROFILESELECT, self.CS_S_TO_L,"SRGB to Linear")
            self.AddChild(self.PROFILESELECT, self.CS_L_TO_V,"Linear to View")
            self.AddChild(self.PROFILESELECT, self.CS_S_TO_V,"SRGB to View")
            return True
        def Command(self, id, msg) :
            link = self.FindCustomGui(self.SHADERLINK,c4d.CUSTOMGUI_LINKBOX)
            sh = link.GetLink(doc,0)
            def GetProfile(p) :
                if p == 0:
                    return self.CS_NONE
                if p == 1:
                    return self.CS_L_TO_S
                if p == 2:
                    return self.CS_S_TO_L
                if p == 10:
                    return self.CS_L_TO_V
                if p == 11:
                    return self.CS_S_TO_V
            def RenderShader(w,h,sh) :
                global percent
                global Pget
                shader = sh
                start = timeit.default_timer()
                irs = InitRenderStruct()
                cd = ChannelData()
                cd.p = Vector(.5,.5,0)
                bmp = bitmaps.BaseBitmap()
                pget = 100/w
                percent = 0.0
                profile = self.GetInt32(self.PROFILESELECT)
                profile = GetProfile(profile)# possibly not neccesarry?
                c4d.StatusSetText("Rendering: "+shader.GetName()+" shader")
                for x in xrange(w) :
                    self.SetReal(self.PROGRESS_SLIDER, percent,min = 0, max = 100.0)
                    self.SetString(self.PROGRESS," "+str(percent)+"%")
                    for y in xrange(h) :
                        PX = x/w
                        PY = y/h
                        cd.p = Vector(PX,PY,0)
                        s = shader.Sample(cd)
                        s = c4d.utils.TransformColor(s,profile)
                        r = int(s.x * 255)
                        g = int(s.y * 255)
                        b = int(s.z * 255)
                        bmp.SetPixel(x, y, r, g, b)
                    percent = percent + pget
                stop = timeit.default_timer()
                self.SetString(self.PROGRESS," 100%!")
                self.SetReal(self.PROGRESS_SLIDER, 100,min = 0, max = 100.0)
                OutInfo = shader.GetName()+" shader rendered in "+str(stop - start)+" seconds"
                self.SetString(self.RENDERINFO, OutInfo)
                return bmp
            if id == self.RENDER:
                w = self.GetInt32(self.WIDTH)
                h = self.GetInt32(self.HEIGHT)
                Abmp = RenderShader(w,h,sh)
            if id == self.RENDER_BIT:
                Ibmp = RenderShader(120,120,sh)
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
            if id == self.SHADERLINK:
                Ibmp = RenderShader(120,120,sh)
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
            if id == self.PROFILESELECT:
                Ibmp = RenderShader(120,120,sh)
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
            return True
    dlg = BasicDialog()
    dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, xpos=-1, ypos=-1)

  • On 14/01/2015 at 00:43, xxxxxxxx wrote:

    Hi Shawn,

    Thanks for posting your code. I should have asked in which context you where calling InitRender().
    I thought you were invoking InitRender() from a ShaderData plugin.
    Unfortunately InitRenderStruct.linear_workflow and InitRenderStruct.document_colorprofile are read-only in the Python API and can't be set.
    I'll report this limitation to the development team.

Log in to reply