是否可以在Pixel Shader中绘制简单的几何形状?

时间:2015-03-16 13:04:26

标签: opengl directx glsl pixel-shader pixel-shading

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

这可以在不使用顶点着色器的情况下完成吗?

3 个答案:

答案 0 :(得分:2)

答案是肯定的!您可以通过实现光线跟踪器使用像素着色器绘制任何所需的内容。以下是示例代码:

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

答案 1 :(得分:0)

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

在片段着色器中,gl_PointCoord在正方形内具有此特定像素的x和y坐标,从0.0到1.0。因此,您可以通过测试gl_PointCoord.x和gl_PointCoord.y是否都在半径范围内并且如果不是则丢弃来绘制圆形,通过检查.x和.y与边缘有一定距离来确定框架正方形,依此类推。这是经典的数学,定义一个函数(x,y),它为你想要的形状中的点返回true,否则返回false。

橙皮书,OpenGL着色语言第3版,有一些例子(反过来来自RenderMan)如何绘制这样的形状。

希望这有帮助。

答案 2 :(得分:0)

您想要的是procedural textures或程序着色。

您可以使用简单(而不是那么简单)的数学绘制不同的形状。

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

更多关于谷歌。