是否可以在像素着色器中绘制简单的几何形状?

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

我目前正在学习着色器和图形管线,我想知道是否可以使用像素着色器来创建例如三角形或更复杂的形状,例如之字形。

是否可以在不使用顶点着色器的情况下完成此操作?

答案是肯定的!您可以通过实施光线追踪器使用像素着色器绘制任何您想要的东西。这是一个示例代码:

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);
}

一个有用的技术是使用带有点精灵的片段着色器(我是 OpenGL 专家)。 OpenGL 3+ 中的点精灵被渲染为像素正方形,正方形的大小 (gl_PointSize) 由顶点着色器设置。

在片段着色器中,gl_PointCoord 具有正方形内该特定像素的 x 和 y 坐标,从 0.0 到 1.0。因此,您可以通过测试 gl_PointCoord.x 和 gl_PointCoord.y 是否都在半径内来绘制圆圈,如果不在半径内则丢弃,通过检查 .x 和 .y 是否与边缘有一定距离来绘制带框的正方形,以及很快。这是经典数学,定义一个函数 (x, y) ,它 returns 对你想要的形状内的点为真,否则为假。

橙皮书 OpenGL Shading Language 3rd edition 有一些关于如何绘制此类形状的示例(这些示例又来自 RenderMan)。

希望对您有所帮助。

你想要的叫做procedural textures或程序着色。

你可以用简单的(也不是那么简单的)数学画出不同的形状。

在这里查看一些示例: http://glslsandbox.com/

更多关于 google。