opengldirectxglslpixel-shaderpixel-shading

Is it possible to draw simple geometrical shapes in a Pixel Shader?


I'm currently learning about shaders and graphics pipelines and I was wondering if a pixel shader could be used to create, for example, a triangle or a more complex shape like a zigzag.

Could this be done without the use of a vertex shader?


Solution

  • Answer is yes! You can draw anything you want using pixel shader by implementing a ray Tracer. Here is a sample code:

    Sample Ray Tracer

    uniform vec3 lightposition;
    uniform vec3 cameraposition;
    uniform float motion;
    
    struct Ray 
    {
      vec3 org;
      vec3 dir;
    };
    
    struct Sphere 
    {
      vec3 Center;
      float Radius;
      vec4 Color;
      float MatID;
      float id;
    };
    
    
    struct Intersection
    {
      float t;
      vec3 normal;
      vec3 hitpos;
      vec4 color;
      float objectid;
      float materialID;
    };
    
    
    bool sphereIntersect(Ray eyeray, Sphere sp, inout Intersection intersection)
    {
    
        float t1=0.0;
        eyeray.dir = normalize(eyeray.dir);
        float B = 2.0 *( ( eyeray.dir.x * (eyeray.org.x - sp.Center.x ) )+  ( eyeray.dir.y *(eyeray.org.y - sp.Center.y )) + ( eyeray.dir.z * (eyeray.org.z - sp.Center.z ) ));
        float C = pow((eyeray.org.x - sp.Center.x),2.0) + pow((eyeray.org.y - sp.Center.y),2.0) + pow((eyeray.org.z - sp.Center.z),2.0) - pow(sp.Radius,2.0);   
        float D = B*B - 4.0*C ;
    
        if(D>=0.0)
        {
            t1= (-B - pow(D, .5)) / 2.0;
            if (t1 < 0.0)
            {
                t1 = (-B + pow(D, .5)) / 2.0;
                if( t1 < 0.0)
                    return false; 
                else
                {
                    if (t1 > 1e-2 && t1 < intersection.t)
                    { 
                        intersection.t = t1;
                        intersection.materialID = sp.MatID;
                        intersection.hitpos = eyeray.org + t1 * eyeray.dir;
                        intersection.normal = normalize(intersection.hitpos - sp.Center);
                        intersection.color = sp.Color;
                        intersection.objectid = sp.id;
    
                        return true;
    
                    }
                }
            }
            else
            {
                if(t1 > 1e-2 && t1 < intersection.t)
                {
                    intersection.t = t1;
                    intersection.materialID = sp.MatID;
                    intersection.hitpos = eyeray.org + t1 * eyeray.dir;
                    intersection.normal = normalize(intersection.hitpos - sp.Center);
                    intersection.color = sp.Color;
                    intersection.objectid = sp.id;  
    
                    return true; 
                }
            }
        }
        else
            return false; 
    }   
    
    
    void findIntersection(Ray ray, inout Intersection intersection)
    {
        intersection.t = 1e10;
        intersection.materialID = 0.0;
    
        Sphere sp1 = Sphere(vec3(-2.0,0.0,-5.0),1.5,vec4(0.5, 0.1, 0.5, 1.0),1.0,1.0);
        Sphere sp2 = Sphere(vec3( 2.0,0.0,-5.0),1.5,vec4(0.5,0.5,0.1,1.0),1.0,2.0);
        Sphere sp3 = Sphere(vec3( 0.0,3.0,-5.0),1.5,vec4(0.1,0.5,0.5,1.0),1.0,3.0);
    
        sphereIntersect(ray, sp1, intersection);
        sphereIntersect(ray, sp2, intersection);
        sphereIntersect(ray, sp3, intersection);
    }           
    
    vec4 CalculateColor(vec4 ambient ,float shiness,vec3 intersection, vec3 normal);
    Ray ReflectedRay(vec3 Normal,Ray EyeRay,vec3 intersection);
    vec4 GetColor(Ray ray) 
    {  
        Ray currentRay = ray;
        vec4 finalColor = vec4(0.0);
    
        for(int bounce = 1 ; bounce < 4 ; bounce++)
        {
            Intersection intersection;
            intersection.objectid = 0.0;
            findIntersection(currentRay, intersection);
            if (intersection.materialID == 0.0) // We could not find any object. We return the background color
                return finalColor;
            else if (intersection.materialID == 1.0) 
            {               
                vec3 lv = lightposition - intersection.hitpos;
                vec3 nlv = normalize(lv);
    
                Intersection shadowIntersection;
                Ray shadowRay = Ray(intersection.hitpos, nlv);
                shadowIntersection.objectid = intersection.objectid;
    
                findIntersection(shadowRay, shadowIntersection);
    
                if (shadowIntersection.t > length(lv) || shadowIntersection.t < 1)
                {
                    finalColor = finalColor + float(1.0f/bounce) * CalculateColor(intersection.color, 100.0, intersection.hitpos, intersection.normal);;
                }
                else
                { 
                    finalColor = finalColor + float(1.0f/bounce) * intersection.color;          
                }
    
                //currentRay = Ray(intersection.hitpos, reflect(ray.dir, intersection.normal));
                currentRay = ReflectedRay(intersection.normal,ray,intersection.hitpos);                             
            }
        }
    
        return finalColor;
    }
    
    
    Ray createRay(float ScreenWidth,float ScreenHeight)
    {   
        Ray toret;
        toret.org = cameraposition;
    
        float left = -3.0;
        float bottom = -3.0;
        float screenZ = -3.0;
    
    
        float su = -3.0 + gl_FragCoord.x/ScreenWidth * 6; //gl_FragCoord gives you the current x and y component of your current pixel 
        float sv = -3.0 + gl_FragCoord.y/ScreenHeight * 6;  
        float sz = screenZ - cameraposition.z;
    
        toret.dir = normalize(vec3(su,sv,sz));
    
    
        //vec2 p =   (gl_FragCoord.xy/resolution) * 2 ;
        //toret.dir  =  normalize(vec3(p, -1.0));   
        return toret;
    }
    
    Ray ReflectedRay(vec3 Normal,Ray EyeRay,vec3 intersection)
    {
        Ray reflection;
    
    
    
        reflection.dir = EyeRay.dir - 2 * Normal * dot(EyeRay.dir,Normal);
        reflection.org = intersection + reflection.dir * 0.01;
    
        return reflection;
    }
    
    vec4 CalculateColor(vec4 ambient ,float shiness,vec3 intersection, vec3 normal)
    {
            //intensities
            vec3 Idifuse = vec3(1, 1, 1);  
            vec3 Iambient = vec3(0.8, 0.8, 0.8);
            vec3 Ispecular = vec3(1,1,1);
    
            vec3 kDifuse = vec3(0.5,0.5,0.5); //for difuse
            vec3 kSpecular = vec3(0.75, 0.6, 0.3); //for specular
            vec3 kAmbient = vec3(0.1, 0.2, 0.3); //for ambient
    
            //vec4 kSpecular = vec4(0.5,0.5,0.5,1.0);
            //vec4 kDifuse = vec4(0.5,0.5,0.5,1.0); 
    
    
            float ColorDifuse = max(dot(normal,lightposition),0.0) * kDifuse;
    
    
            //vector calculations
            vec3 l = normalize(lightposition - intersection); //light vector
            vec3 n = normalize(normal); // normalVector of point in the sea
            vec3 v = normalize(cameraposition - intersection); // view Vector 
            vec3 h = normalize(v + l); // half Vector
    
    
            vec3 difuse  = kDifuse * Idifuse * max(0.0, dot(n, l));
            vec3 specular = kSpecular * Ispecular * pow(max(0.0, dot(n, h)), shiness);
            vec3 color = ambient.xyz + difuse + specular;
            return vec4(color,1.0);
    
            gl_FragColor = vec4(color,1.0);
    
    
    }
    
    
    void main()
    {
        if(lightposition == vec3(0.0,0.0,0.0))
            gl_FragColor = vec4(0.0,1.0,0.0,1.0);
    
        Ray eyeray = createRay(600.0,600.0);
        gl_FragColor = GetColor(eyeray);
    }