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:

    Hello,

    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,
    Sebastian



  • 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="http://shawnfrueh.com/references/c4d/original_cinemaoutput.png" height="512" width="512" border="0" /_>_

    This is what I get when I use initRender() :
    <_<_img src="http://shawnfrueh.com/references/c4d/original_initoutput.png" 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:

    COLORSPACETRANSFORMATION_NONE: 
    _<_img src="http://shawnfrueh.com/references/c4d/colorspace_nOne.gif" height="278" width="633" border="0" /_>_

    COLORSPACETRANSFORMATION_LINEAR_TO_SRGB:
    <_<_img src="http://shawnfrueh.com/references/c4d/colorspace_linear_to_srgb.gif.gif" height="278" width="633" border="0" /_>_" />

    COLORSPACETRANSFORMATION_SRGB_TO_LINEAR:_r="0" />

    COLORSPACETRANSFORMATION_LINEAR_TO_VIEW_<_img src="http://shawnfrueh.com/references/c4d/colorspace_linear_to_view.gif" height="278" width="633" border="0" /_>_order="0" />

    COLORSPACETRANSFORMATION_SRGB_TO__<_img src="http://shawnfrueh.com/references/c4d/colorspace_srgb_to_view.gif" 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
        
        CS_NONE = c4d.COLORSPACETRANSFORMATION_NONE
        CS_L_TO_S = c4d.COLORSPACETRANSFORMATION_LINEAR_TO_SRGB
        CS_S_TO_L = c4d.COLORSPACETRANSFORMATION_SRGB_TO_LINEAR
        CS_L_TO_V = c4d.COLORSPACETRANSFORMATION_LINEAR_TO_VIEW
        CS_S_TO_V = c4d.COLORSPACETRANSFORMATION_SRGB_TO_VIEW
        
        def CreateLayout(self) :
            
            self.SetTitle("Shader Renderer")
            
            self.GroupBegin(self.GROUPFIT,c4d.BFH_SCALEFIT, cols = 2)
            
            bc = c4d.BaseContainer()
            bc.SetLong(c4d.BITMAPBUTTON_ICONID1, c4d.RESOURCEIMAGE_MOVE)
            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()
            bmp.Init(120,120,24)
            self.myBitButton.SetImage(bmp)
            
            self.GroupBegin(self.GROUP_ALL, c4d.BFH_SCALEFIT, cols = 1)
            self.GroupBorderSpace(4,4,4,4)
            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.GroupEnd()
            
            self.GroupBegin(self.GROUP_PERCENT,c4d.BFH_SCALEFIT, cols = 3)
            self.GroupBorderSpace(4,4,4,4)
            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.GroupEnd()
            
            self.AddStaticText(self.RENDERINFO, c4d.BFH_LEFT, name = "Please add a shader.", initw = 500)
            
            self.GroupEnd()
            self.GroupEnd()
            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()
                #####
                shader.InitRender(irs)
                #####
                cd = ChannelData()
                cd.p = Vector(.5,.5,0)
                bmp = bitmaps.BaseBitmap()
                bmp.Init(w,h,24)
                c4d.StatusSetBar(0.0)
                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) :
                    c4d.StatusSetBar(percent)
                    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
                    
                shader.FreeRender()
                
                stop = timeit.default_timer()
                
                c4d.StatusClear()
                
                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)
                ShowBitmap(Abmp)
                
            if id == self.RENDER_BIT:
                Ibmp = RenderShader(120,120,sh)
                self.myBitButton.SetImage(Ibmp)
                self.SetString(self.PROGRESS,"0%")
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
                self.myBitButton.SetImage(Ibmp)
                
            if id == self.SHADERLINK:
                Ibmp = RenderShader(120,120,sh)
                self.myBitButton.SetImage(Ibmp)
                self.SetString(self.PROGRESS,"0%")
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
                self.myBitButton.SetImage(Ibmp)
                
            if id == self.PROFILESELECT:
                Ibmp = RenderShader(120,120,sh)
                self.myBitButton.SetImage(Ibmp)
                self.SetString(self.PROGRESS,"0%")
                self.SetReal(self.PROGRESS_SLIDER, 0,min = 0, max = 100.0)
                self.myBitButton.SetImage(Ibmp)
                
            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