SOLVED How to set the shadow for polygon drawing

I am writing an object to draw a cube. I draw each polygon by using DrawPolygon() to draw it. I did not use DrawBox() to draw because I don't know how to set the length of the side. When I use DrawPolygon() to draw, the shadow of the cube is wrong, how to set its shadow.
dc16e103-57a6-45e0-be55-7927c2f6bd21-image.png

DRAWRESULT Box_Obj::Draw(BaseObject *op, DRAWPASS drawpass, BaseDraw *bd, BaseDrawHelp *bh)
{
    if (drawpass == DRAWPASS::OBJECT)
    {
        if (op == nullptr || bd == nullptr)
        {
            return DRAWRESULT::FAILURE;
        }
        GeData Ge_Date;
        //Get side length information from parameters.
        op->GetParameter(RIGID_SHAPE_SIZE_X, Ge_Date, DESCFLAGS_GET::NONE);
        Float rigid_size_x = Ge_Date.GetFloat();
        op->GetParameter(RIGID_SHAPE_SIZE_Y, Ge_Date, DESCFLAGS_GET::NONE);
        Float rigid_size_y = Ge_Date.GetFloat();
        op->GetParameter(RIGID_SHAPE_SIZE_Z, Ge_Date, DESCFLAGS_GET::NONE);
        Float rigid_size_z = Ge_Date.GetFloat();
        op->GetParameter(RIGID_GROUP_ID, Ge_Date, DESCFLAGS_GET::NONE);

        //Set the drawing matrix to world coordinates.
        bd->SetMatrix_Matrix(nullptr, Matrix());
        
        //Get object coordinates.
        Vector pos = op->GetAbsPos();

        bd->SetLightList(BDRAW_SETLIGHTLIST_NOLIGHTS);
        bd->SetTransparency(127);

        Vector Box_vc[4] = {Vector(0)};
        Vector Box_vp0[4] = {
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
        };
        Vector Box_vp1[4] = {
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
        };
        Vector Box_vp2[4] = {
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
        };
        Vector Box_vp3[4] = {
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
        };
        Vector Box_vp4[4] = {
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z + rigid_size_z),
        };
        Vector Box_vp5[4] = {
            Vector(pos.x + rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x + rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y - rigid_size_y, pos.z - rigid_size_z),
            Vector(pos.x - rigid_size_x, pos.y + rigid_size_y, pos.z - rigid_size_z),
        };
        bd->DrawPolygon(Box_vp0, Box_vc, true);
        bd->DrawPolygon(Box_vp1, Box_vc, true);
        bd->DrawPolygon(Box_vp2, Box_vc, true);
        bd->DrawPolygon(Box_vp3, Box_vc, true);
        bd->DrawPolygon(Box_vp4, Box_vc, true);
        bd->DrawPolygon(Box_vp5, Box_vc, true);
    }
    return SUPER::Draw(op, drawpass, bd, bh);
}

Thank,
AiMiDi

Hello @aimidi,

thank you for reaching out to us. Please excuse the delay, but your questions had to be reassigned internally, which is why I only took it on yesterday.

The main reason for your problems is the incomplete initialization of Vector Box_vc[4] = {Vector(0)};. Box_vc should be initialized with four vectors as you do declare yourself. This partial initialization causes the shading errors you did experience.

Please also note that you did flag your posting as R21, which is out of the support cycle. Below I do provide some example code written for S24. It should work on R21, since there have been no changes to the involved interfaces and methods as far as I am aware of, but I did not try to compile the code for R21. The code is also narrative in nature and lines out a few other problems with the code provided by you. I hope this will be helpful to you.

Cheers,
Ferdinand

The result:
alt text

The code:

// Example for some drawing operations via ObjectData::Draw().
// 
// Draws a white polygon and a red cube in the local coordinate system of the BaseObject. The main
// problem of your code was that you did not initialize the color array properly.
//
// As discussed in:
//     https://plugincafe.maxon.net/topic/13441

#include "c4d.h"
#include "c4d_symbols.h"

class Pc13441 : public ObjectData
{
    INSTANCEOF(Pc13441, ObjectData)

public:
    static NodeData* Alloc() { return NewObjClear(Pc13441); }

    DRAWRESULT Draw(BaseObject* op, DRAWPASS drawpass, BaseDraw* bd, BaseDrawHelp* bh)
    {
        if (drawpass == DRAWPASS::OBJECT)
        {
            if (op == nullptr || bd == nullptr)
            {
                return DRAWRESULT::FAILURE;
            }

            // Set the drawing matrix to the global matrix of the object we are drawing for. This is
            // more intuitive than what you did, because we can now just draw as if the origin of
            // our object is the origin of the drawing space and also will respect the orientation
            // of the that object. Or in short: We will draw in the local matrix of op.
            bd->SetMatrix_Matrix(nullptr, op->GetMg());

            // The replacement for the drawing size parameter(s) of your example.
            Vector poylgonSize = Vector(100);
            
            // We are now going to draw a manually shaded polygon. This will ignore shading defined 
            // by the user/scene. The user turning on and off shadows in the viewport or moving 
            // lights will have no impact on this.

            // Define the vertices of the polygon to draw.
            Vector vertices[4] = {
                Vector(+poylgonSize.x, +poylgonSize.y, 0),
                Vector(-poylgonSize.x, +poylgonSize.y, 0),
                Vector(-poylgonSize.x, -poylgonSize.y, 0),
                Vector(+poylgonSize.x, -poylgonSize.y, 0)
            };
            // Define the color for each vertex to draw, Cinema will interpolate between these 
            // colors. 
            Vector colors[4] = { Vector(1), Vector(1), Vector(1), Vector(1) };

            // You did not initialize this array properly and also did pass in black as a color.
            // So, this,
            //
            //     Vector colors[4] = { Vector(0) };
            //
            // where we only initialize the 0th element, is not equivalent to that:
            //
            //     Vector colors[4] = { Vector(0), Vector(0), Vector(0), Vector(0) };
            //
            // The first one will give you the weird shading errors you had while the latter will
            // give you an all black polygon. Black as a color is of course not that useful if we
            // want to see some shading.

            // If our polygon is a quad or triangle.
            bool isQuad = true;

            // Set the drawing transparency to about 50%.
            bd->SetTransparency(127);

            // Draw the polygon.
            bd->DrawPolygon(vertices, colors, isQuad);

            // Now we are going to draw a box.

            // The size of the box.
            float boxSize = 50;
            // A transform for the box, we are going to draw it a bit off-center, so that it does
            // not overlap with the polygon we did draw.
            Matrix boxTransform = Matrix();
            boxTransform.off = Vector(200, 0, 0);
            // The color for the box, this can only be a solid color.
            Vector boxColor = Vector(1, 0, 0);
            // And if we want to draw it as a wire frame.
            bool isWireFrame = false;
            // Draw the box.
            bd->DrawBox(boxTransform, boxSize, boxColor, isWireFrame);

            // For more complex drawing operations one could use DrawPoly() to draw a single 
            // polygon, while respecting scene shading, or DrawPolygonObject() to draw a BaseObject 
            // that is a PolygonObject. Which will also respect user defined scene shading by 
            // default. I would not recommend constructing such polygon object to draw in Draw() as 
            // this method is rather performance critical. If possible, this should be done 
            // beforehand, i.e., in a cached manner.
        }
        return SUPER::Draw(op, drawpass, bd, bh);
    }
};

Can someone help me, I don't know what to do?

Thank,
AiMiDi

Hello @aimidi,

thank you for reaching out to us. Please excuse the delay, but your questions had to be reassigned internally, which is why I only took it on yesterday.

The main reason for your problems is the incomplete initialization of Vector Box_vc[4] = {Vector(0)};. Box_vc should be initialized with four vectors as you do declare yourself. This partial initialization causes the shading errors you did experience.

Please also note that you did flag your posting as R21, which is out of the support cycle. Below I do provide some example code written for S24. It should work on R21, since there have been no changes to the involved interfaces and methods as far as I am aware of, but I did not try to compile the code for R21. The code is also narrative in nature and lines out a few other problems with the code provided by you. I hope this will be helpful to you.

Cheers,
Ferdinand

The result:
alt text

The code:

// Example for some drawing operations via ObjectData::Draw().
// 
// Draws a white polygon and a red cube in the local coordinate system of the BaseObject. The main
// problem of your code was that you did not initialize the color array properly.
//
// As discussed in:
//     https://plugincafe.maxon.net/topic/13441

#include "c4d.h"
#include "c4d_symbols.h"

class Pc13441 : public ObjectData
{
    INSTANCEOF(Pc13441, ObjectData)

public:
    static NodeData* Alloc() { return NewObjClear(Pc13441); }

    DRAWRESULT Draw(BaseObject* op, DRAWPASS drawpass, BaseDraw* bd, BaseDrawHelp* bh)
    {
        if (drawpass == DRAWPASS::OBJECT)
        {
            if (op == nullptr || bd == nullptr)
            {
                return DRAWRESULT::FAILURE;
            }

            // Set the drawing matrix to the global matrix of the object we are drawing for. This is
            // more intuitive than what you did, because we can now just draw as if the origin of
            // our object is the origin of the drawing space and also will respect the orientation
            // of the that object. Or in short: We will draw in the local matrix of op.
            bd->SetMatrix_Matrix(nullptr, op->GetMg());

            // The replacement for the drawing size parameter(s) of your example.
            Vector poylgonSize = Vector(100);
            
            // We are now going to draw a manually shaded polygon. This will ignore shading defined 
            // by the user/scene. The user turning on and off shadows in the viewport or moving 
            // lights will have no impact on this.

            // Define the vertices of the polygon to draw.
            Vector vertices[4] = {
                Vector(+poylgonSize.x, +poylgonSize.y, 0),
                Vector(-poylgonSize.x, +poylgonSize.y, 0),
                Vector(-poylgonSize.x, -poylgonSize.y, 0),
                Vector(+poylgonSize.x, -poylgonSize.y, 0)
            };
            // Define the color for each vertex to draw, Cinema will interpolate between these 
            // colors. 
            Vector colors[4] = { Vector(1), Vector(1), Vector(1), Vector(1) };

            // You did not initialize this array properly and also did pass in black as a color.
            // So, this,
            //
            //     Vector colors[4] = { Vector(0) };
            //
            // where we only initialize the 0th element, is not equivalent to that:
            //
            //     Vector colors[4] = { Vector(0), Vector(0), Vector(0), Vector(0) };
            //
            // The first one will give you the weird shading errors you had while the latter will
            // give you an all black polygon. Black as a color is of course not that useful if we
            // want to see some shading.

            // If our polygon is a quad or triangle.
            bool isQuad = true;

            // Set the drawing transparency to about 50%.
            bd->SetTransparency(127);

            // Draw the polygon.
            bd->DrawPolygon(vertices, colors, isQuad);

            // Now we are going to draw a box.

            // The size of the box.
            float boxSize = 50;
            // A transform for the box, we are going to draw it a bit off-center, so that it does
            // not overlap with the polygon we did draw.
            Matrix boxTransform = Matrix();
            boxTransform.off = Vector(200, 0, 0);
            // The color for the box, this can only be a solid color.
            Vector boxColor = Vector(1, 0, 0);
            // And if we want to draw it as a wire frame.
            bool isWireFrame = false;
            // Draw the box.
            bd->DrawBox(boxTransform, boxSize, boxColor, isWireFrame);

            // For more complex drawing operations one could use DrawPoly() to draw a single 
            // polygon, while respecting scene shading, or DrawPolygonObject() to draw a BaseObject 
            // that is a PolygonObject. Which will also respect user defined scene shading by 
            // default. I would not recommend constructing such polygon object to draw in Draw() as 
            // this method is rather performance critical. If possible, this should be done 
            // beforehand, i.e., in a cached manner.
        }
        return SUPER::Draw(op, drawpass, bd, bh);
    }
};