Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    BaseDraw::DrawTexture alpha issue

    Cinema 4D SDK
    r20 r21 c++
    2
    5
    776
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • C4DSC
      C4DS
      last edited by

      I am trying to draw onto the viewport with some alpha values but don't get the expected value.
      To test out I simply draw a white rectangle as background and on top of that I draw a black line with a varying alpha value. Basically building a gradient going from full transparency (top) to full opaque (bottom).

      To compare to what would be expected I've drawn a Photoshop gradient at the right.
      To me it seems the first N lines are not drawn at all, or their alpha value prevent the lines from being visible, while the rest of the "gradient" doesn't seem to be linear.

      Main code of the "gradient"

      for (Int32 i = 0; i <= 255; ++i)
      {
      	clipMap->SetColor(0, 0, 0, i);
      	clipMap->Line(10, 10+i, width-10, 10+i);
      }
      

      This is the result with R20, but similar results obtained with R21. Have not tested more recent releases.

      Alpha Gradient.png

      Am I missing something about the "gradient" implementation, or is there another setting missing?

      Here's the full plugin implementation:

      // ========================
      // Cinema 4D C++ plugin
      //
      // PluginName: Test
      // Dummy "empty" plugin
      // ========================
      
      // Main.cpp
      
      #include "c4d.h"
      #include "lib_clipmap.h"
      
      // Dummy IDs - for demonstration purposes only
      #define MYSCENEHOOK_PLUGIN_ID	1000000
      
      
      
      
      Bool DrawTheStuff(BaseDraw *bd, Int32 x, Int32 y)
      {
      	AutoAlloc<GeClipMap> clipMap;
      	if (!clipMap) return false;
      
      	Int32 width = 300;
      	Int32 height = 275;
      
      	// now the dimensions are known
      	// intialize clipmap for the actual drawing
      	if (clipMap->Init(width, height, 32) != IMAGERESULT::OK)
      		return false;
      	clipMap->BeginDraw();
      	// fill background with white
      	clipMap->SetColor(255, 255, 255, 255);
      	clipMap->FillRect(0, 0, width, height);
      
      	// draw black stripes over background with different alpha values,
      	// leaving a border of 10 pixels of background at each side
      	for (Int32 i = 0; i <= 255; ++i)
      	{
      		clipMap->SetColor(0, 0, 0, i);
      		clipMap->Line(10, 10+i, width-10, 10+i);
      	}
      
      	clipMap->EndDraw();
      	const BaseBitmap* bitmap = clipMap->GetBitmap();
      	if (bitmap)
      	{
      		maxon::Vector *positions;
      		iferr(positions = NewMem(maxon::Vector, 4))
      			return false;
      		maxon::Vector *colors = nullptr; // NewMem(maxon::Vector, 4);
      		maxon::Vector *normals = nullptr; // NewMem(maxon::Vector, 4);
      		maxon::Vector *uvcoords;
      		iferr(uvcoords = NewMem(maxon::Vector, 4))
      		{
      			DeleteMem(positions);
      			return false;
      		}
      
      		// center image on top of the point
      		x -= (width / 2);
      		y -= (height / 2);
      
      		positions[0] = maxon::Vector(x, y, 0);
      		positions[1] = maxon::Vector(x + width, y, 0);
      		positions[2] = maxon::Vector(x + width, y + height, 0);
      		positions[3] = maxon::Vector(x, y + height, 0);
      
      		uvcoords[0] = maxon::Vector(0, 0, 0);
      		uvcoords[1] = maxon::Vector(1, 0, 0);
      		uvcoords[2] = maxon::Vector(1, 1, 0);
      		uvcoords[3] = maxon::Vector(0, 1, 0);
      
      		// draw texture in screen space
      		const Matrix currentMg = bd->GetMg();
      		bd->SetMatrix_Screen();
      		bd->SetLightList(BDRAW_SETLIGHTLIST_NOLIGHTS);
      		const DRAW_ALPHA        alpha = DRAW_ALPHA::NORMAL; //DRAW_ALPHA::NONE
      #if API_VERSION < 23000
      		const DRAW_TEXTUREFLAGS texture = DRAW_TEXTUREFLAGS::NONE;
      #else
      		const DRAW_TEXTUREFLAGS texture = DRAW_TEXTUREFLAGS::INTERPOLATION_NEAREST | DRAW_TEXTUREFLAGS::TEMPORARY;
      #endif
      		bd->DrawTexture(bitmap, positions, colors, normals, uvcoords, 4, alpha, texture);
      
      		DeleteMem(positions);
      		//DeleteMem(colors);
      		//DeleteMem(normals);
      		DeleteMem(uvcoords);
      
      		// restore the matrix
      		bd->SetMatrix_Matrix(nullptr, currentMg);
      	}
      
      	return true;
      }
      
      
      // ====================================
      // SceneHook
      // ====================================
      
      class MySceneHook : public SceneHookData
      {
      	INSTANCEOF(MySceneHook, SceneHookData)
      
      public:
      	MySceneHook();
      	virtual Bool Draw(BaseSceneHook *node, BaseDocument *doc, BaseDraw *bd, BaseDrawHelp *bh, BaseThread *bt, SCENEHOOKDRAW flags);
      
      	static NodeData *Alloc(void) { return NewObjClear(MySceneHook); }
      };
      
      MySceneHook::MySceneHook() : SceneHookData()
      {
      }
      
      Bool MySceneHook::Draw(BaseSceneHook *node, BaseDocument *doc, BaseDraw *bd, BaseDrawHelp *bh, BaseThread *bt, SCENEHOOKDRAW flags)
      {
      	if (!node || !doc || !bd || !bh)
      		return false;
      	if (flags != SCENEHOOKDRAW::DRAW_PASS)
      		return true;
      
      	Int32 lLeft, lTop, lRight, lBottom;
      	bd->GetFrame(&lLeft, &lTop, &lRight, &lBottom);
      
      	bd->SetMatrix_Screen();
      
      	DrawTheStuff(bd, SAFEINT32((lLeft + lRight) * 0.5), SAFEINT32((lTop + lBottom) * 0.5));
      
      
      	// restore basedraw matrix
      	bd->SetMatrix_Matrix(nullptr, Matrix());
      
      	return true;
      }
      
      // ====================================
      // Plugin Main 
      // ====================================
      Bool PluginStart(void)
      {
      	ApplicationOutput("Test"_s);
      
      	RegisterSceneHookPlugin(MYSCENEHOOK_PLUGIN_ID, "MySceneHook"_s, 0, MySceneHook::Alloc, EXECUTIONPRIORITY_GENERATOR, 0);
      
      	return true;
      }
      void PluginEnd(void)
      {
      }
      Bool PluginMessage(Int32 id, void * data)
      {
      	switch (id) {
      	case C4DPL_INIT_SYS:
      		if (!g_resource.Init())
      			return false;
      		return true;
      	case C4DMSG_PRIORITY:
      		return true;
      	case C4DPL_BUILDMENU:
      		break;
      	case C4DPL_ENDACTIVITY:
      		return true;
      	}
      	return false;
      }
      
      
      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        Hi,
        your code seems to work on R22.2, there's no alpha hole below a certain value. I will ask our dev team if there's a workaround but i got huge doubt.

        About the gradient not being the same that's probably because cinema4D is using linear workflow.
        Converting the alpha value to linear should fix the issue.

        	for (Int32 i = 0; i <= 255; ++i)
        	{
        		Float linearAlpha = Pow(Float(i) / 255.0, .45);
        		clipMap->SetColor(1, 0, 0, linearAlpha * 255);
        		clipMap->Line(10, 10 + i, width - 10 , 10 + i);
                        
                        // draw only the half for comparaison	
        		clipMap->SetColor(0, 1, 0, i);
        		clipMap->Line(10, 10 + i, (width - 10) /2, 10 + i);
        	
        

        Cheers,
        Manuel

        MAXON SDK Specialist

        MAXON Registered Developer

        C4DSC 1 Reply Last reply Reply Quote 0
        • C4DSC
          C4DS @Manuel
          last edited by C4DS

          @m_magalhaes
          Thanks for the tip to convert the alpha to linear value.
          It is not perfect, but it does reduce the "gap" to a much smaller percentage.

          Linear Alpha Gradient.png

          With the original value I have a gap of 19%. Any alpha value below 20% opacity is just drawn as full transparent.
          With the alpha value converted to linear this is now reduced to a gap of only 2%
          I can live with this limitation.

          It would be nice to hear from devs if there is a workaround to get a full gradient.
          But I am already setting this topic as "solved".

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by

            I'm probably forgetting something for the conversion, i asked the dev to confirm. I really got doubt for a workaround for the version before R22.1.

            What about if you just disable the linear workflow?

            MAXON SDK Specialist

            MAXON Registered Developer

            C4DSC 1 Reply Last reply Reply Quote 0
            • C4DSC
              C4DS @Manuel
              last edited by

              @m_magalhaes

              Gradients.png

              Did some more testing, using the original code and the conversion code, with linear workflow on and off.

              When I look at the original code with linear workflow OFF, this most resembles the gradient from Photoshop. Except for the gap at the top .. obviously.

              The result from conversion code with linear workflow ON is what I am using now, as this provides the smallest gap. And to my eyes that result looks the most linear.

              1 Reply Last reply Reply Quote 0
              • First post
                Last post