2015-03-16 5 views
-1

В настоящее время я изучаю шейдеры и графические конвейеры, и мне было интересно, можно ли использовать пиксельный шейдер для создания, например, треугольника или более сложной формы, такой как зигзаг.Можно ли рисовать простые геометрические фигуры в пиксельном шейдере?

Это можно сделать без использования вершинного шейдера?

+0

Как отметил кто-то еще, вы можете, конечно, использовать трассировку лучей, чтобы делать что угодно с пиксельными шейдерами, но производительность и сложность являются основным ограничением. Тем не менее, на современном high-end GPU вы можете сделать с ним довольно интересные вещи. Вы также можете использовать [карты смещения] (http://en.wikipedia.org/wiki/Displacement_mapping). –

ответ

2

Ответ да! Вы можете рисовать все, что хотите, используя пиксельный шейдер, реализуя луч Tracer. Вот пример кода:

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); 
} 
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 для точек внутри нужной вам формы, если это неверно.

Оранжевая книга, OpenGL Shading Language 3-е издание, содержит несколько примеров (в свою очередь, RenderMan) о том, как рисовать такие фигуры.

Надеюсь, что это поможет.

0

Что вы хотите, это procedural textures или процедурное затенение.

Вы можете нарисовать различные фигуры с помощью простой (и не простой) математики.

Посмотрите на некоторые примеры здесь: http://glslsandbox.com/

Подробнее о Google.