Basic Shading in C++ to a BMP image. Facing ratio calculation

67 Views Asked by At

I am studying Shading and how light interacts with objects. I found a great website and wanted to implement knowledge from https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/shading-normals in my own way.

I wrote a code. It is supposed to calculate a facing ratio (cosine of the angle between a normal vector and a light Ray ) and generate a ".BMP" image with that. I took a surface as an object (well, on the image it will be a circle). The idea was to calculate the effect of this ratio on the color of the surface, i.e how light and object interact.

The code is as follows

    
template <typename T> 

class Vec3
{
private: 
    T x, y, z;
public:
    Vec3(): x{0},y{0},z{0} {}
    Vec3(T xx): x{xx}, y{xx},z{xx} {}
    Vec3(T xx, T yy, T zz): x{xx}, y{yy}, z{zz} {}

   friend Vec3<T> operator+(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x + vec2.x, vec1.y + vec2.y, vec1.z + vec2.z); }
   friend Vec3<T> operator-(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x - vec2.x, vec1.y - vec2.y, vec1.z - vec2.z); }
   friend Vec3<T> operator*(const Vec3<T>& vec1, const Vec3<T>& vec2) { return Vec3<T>(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z); }
   friend Vec3<T> operator*(const Vec3<T>& vec1, const T& k) { return Vec3<T>(vec1.x * k, vec1.y * k, vec1.z * k); }
   friend Vec3<T> operator/(const Vec3<T>& vec1, const T& k) { return Vec3<T>(vec1.x / k, vec1.y / k, vec1.z / k); }
    Vec3<T> operator - () const { return Vec3<T>(-x, -y, -z); }

    T dot (const Vec3<T>& v) const { return x * v.x + y * v.y + z * v.z; }
    T lengthWithoutRoot() const { return x * x + y * y + z * z; }
    T length() const { return sqrt(lengthWithoutRoot()); }

    Vec3& normalize()
    {
        T nor2 = lengthWithoutRoot();
        if (nor2 > 0) {
            T divider = 1 / sqrt(nor2);
            x *= divider, y *= divider, z *= divider;
        }
        return *this;
    }

    Vec3<T> reflection(const Vec3<T>& prim,const Vec3<T>& normal) // TO BE CHECKED 
    {
        Vec3<T> reflection = prim - 2 * (prim.dot(normal)) * normal;
        return reflection;

    }



    friend std::ostream& operator<<(std::ostream &out, const Vec3<T>& vec)
    {
        out << '(' << vec.x << ',' << vec.y << ',' << vec.z << ')';
        return out;
    }

    const T& getX() { return x; }
    const T& getY() { return y; }
    const T& getZ() { return z; }





};

typedef Vec3<float> Vec3f;

class Sphere
{
private:
    Vec3f center;
    float radius;
public:
    Sphere(const Vec3f& c, const float& r): center{c}, radius{r} {}
    

    bool intersect(const Vec3f& primRay) 
       

    {
        Vec3f vecRadius = center - primRay;
        float distLength = vecRadius.length();
        
        if (distLength > radius)
            return false;

        
        return true;
    }

    bool intersectSurface(const Vec3f& primRay)
        
    {
        Vec3f vecRadius = center - primRay;
        float distLength = vecRadius.length();

        if (distLength == radius)
            return true;


        return false;
    }

        float alphaPositive(const Vec3f& p, const Vec3f& source)
    {
        
        Vec3f primRay = (source-p).normalize();
        Vec3f normal = (p-center).normalize();

        float diff = primRay.dot(normal);
                     

        return std::max(diff,0.f) ;
    }

    
};



int main()
{
    
    Sphere sphere (Vec3f{ 250.0f, 250.0f, 0.0 }, 150.0f );
    Vec3f source{ 100,200,0.0 };
    Vec3f color{ 255,255,255 };
    
    std::ofstream file;
    file.open("DIF_SPHERE36.ppm");
    file << "P6\n" << height << " " << width << "\n255\n";

    
    for (float h = 0; h < 500; ++h)
    {
        for (float w = 0; w < 500; ++w)
        {
            Vec3f primRay = { h,w,0.0 };
            
            if (sphere.intersect(primRay))
            {
                
                float facingRatio= sphere.alphaPositive(primRay, source); 
                color = Vec3f{255,0,0}*facingRatio;
                             
                file << unsigned char(color.getX()) << unsigned char(color.getY()) << unsigned char(color.getZ());
                               
            }
            else 
                file << unsigned char(255) << unsigned char(255) << unsigned char(255);
        }
    }

    file.close();

    return 0;

}

However. I get smth strange, even when I try to change 'source' coordinates. Facing ratio is calculated in alphaPositive function This is what a code must generate according to the idea

1

There are 1 best solutions below

0
Sakesfar On

Thank you all for your comments.

I made following conclusions:

  1. In function alphaPositive I had to use return std::max(diff,0.1f) instead of return std::max(diff,0.f).
  2. Had to change positioning of the Object and Light by adding z-coordinates.

With that I managed to get a sphere with some effects.

picture