2012-08-27 5 views
2

저는 어디에서부터 시작해 봅시다; current state조각 쉐이더 : 조각에서 베 지어 곡선까지 거리를 얻으십시오

FBO를 통해이 텍스처를 생성하는 프래그먼트 셰이더가 있습니다. 베 지어 커브를 제외하고 내가 원하는 모든 프리미티브가 거의 있습니다.

내 오히려 큰 조각 쉐이더 : 모든 2D 공간에서 곡선은 종종 3 개 이상의 지점을 가지고있는 베 지어
def on_draw(self): 
    if not self.inited: 
     vert = shader.Shader(shader.texvertex) 
     frag = shader.Shader(shader.testfrag) 
     self.TexProgram = shader.Program([vert, frag]) 
     with self.TexProgram: 
      self.TexProgram["lines[0]"] = (0.25, 0.5, 0.75, 0.5) 
      self.TexProgram["lines[1]"] = (0.0, 0.0, 1.0, 1.0) 
      self.TexProgram["circles[0]"] = (0.5, 0.5, 0.1) 
      self.TexProgram["ellipses[0]"] = (0.75, 0.25, 0.1, 2.0) #x,y, width, multiplicator on height 
      self.TexProgram["polygons[0]"] = (0.1, 0.9) 
      self.TexProgram["polygons[1]"] = (0.2, 0.9) 
      self.TexProgram["polygons[2]"] = (0.2, 1) 
      self.TexProgram["polygons[3]"] = (0.1, 1) 
      self.TexProgram["polygons[4]"] = (0,0) 
      self.TexProgram["polygons[5]"] = (0.1, 0.1) 
      self.TexProgram["polygons[6]"] = (0.2, 0.1) 
      self.TexProgram["polygons[7]"] = (0.2, 0.2) 
      self.TexProgram["polygons[8]"] = (0.1, 0.2) 
      self.TexProgram["polygons[9]"] = (0,0) 
      self.TexProgram["polylength"] = 8 
      self.TexProgram["light"] = 1.05 
      self.TexProgram["thickness"] = 0.02 
     self.inited = True 

    self.clear() 
    else: 
     with self.TexProgram: 
      self.fbo.bind_texture() 
      self.fbo.clear() 
      t = (0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0) 
      x1 = 0 
      x2 = w 
      y1 = 0 
      y2 = h 

      glColor4d(1,1,1,1) 
      glEnable (GL_TEXTURE_2D) 
      glBegin(GL_QUADS) 
      glTexCoord2d(t[0], t[1]); glVertex2d(x1, y1) 
      glTexCoord2d(t[2], t[3]); glVertex2d(x2, y1) 
      glTexCoord2d(t[4], t[5]); glVertex2d(x2, y2) 
      glTexCoord2d(t[6], t[7]); glVertex2d(x1, y2) 
      glEnd() 
입니다

하십시오 pyglet 환경에서 대략 다음과 같이이라고

testfrag = """//fragment 
uniform float thickness; //sets beam thickness 
uniform float light; //sets beam intensity 

uniform vec4 lines[200]; //pairs of lines; x1, y1, x2, y2 
uniform vec3 circles[200]; //circles x,y,radius 
uniform vec4 ellipses[200]; //ellipses x,y,width, heightmultiplication 
uniform int ellipselength = 1; //amount of ellipses 
uniform int linelength = 2; //amount of linepairs 
uniform int circlelength = 1; //amount of circles 


uniform vec2 polygons[200]; //polygon data, points in x,y. (0,0) points used as end marker 
uniform int polylength; //amount of polygons 


int i; //for counter variable 1 
int i2; //for counter variable 2 
float mindistance = 1.0; //distance from fragment to next segment 

float P2L(in vec2 p, in vec2 lp1, in vec2 lp2) //distance point to line segment 
{ 
    float squared = pow(distance(lp1, lp2), 2); //squared line length 
    float t = dot(p - lp1, lp2 - lp1)/squared; //relative position in parellel to line 
    if (t < 0.0) return distance(p, lp1); //before the line, get radius to point 
    if (t > 1.0) return distance(p, lp2); //after the line, get radius to point 
    return distance(p, lp1 + t * (lp2 - lp1)); //otherwise, get distance line to point 
} 
float P2C(in vec2 p, in vec3 circle) //point to circle 
{ 
    return abs(distance(p, circle.xy)-circle.z); //euclidian distance - radius 
} 
float P2E(in vec2 p, in vec4 ellipse) //point to ellipse 
{ 
    return abs(sqrt(pow(p.x-ellipse.x,2) + pow((p.y-ellipse.y)/ellipse.w, 2)) -ellipse.z); // similar to circle, with factor on height 
} 

bool PinPoly(in vec2 p, in int start, in int len) //test if point in polygon 
{ 
    int i, j; 
    bool c = false; 
    for (i = start, j = len-1+start; i < len+start; j = i++) { 
    if (((polygons[i].y>p.y) != (polygons[j].y>p.y)) && 
    (p.x < (polygons[j].x-polygons[i].x) * (p.y-polygons[i].y)/(polygons[j].y-polygons[i].y) + polygons[i].x)) 
     c = !c; 
    } 
    return c; 
} //balls if I know how this works 



void main() 
{ 

    vec2 pos = gl_TexCoord[0].xy; // get position on fbo 
    for (i = 0; i < linelength; i++) //test lines 
    { 
     mindistance = min(mindistance, P2L(pos, lines[i].xy, lines[i].zw)); 
    } 
    for (i = 0; i < circlelength; i++) //test circles 
    { 
     mindistance = min(mindistance, P2C(pos, circles[i])); 
    } 
    for (i = 0; i < ellipselength; i++) //test ellipses 
    { 
     mindistance = min(mindistance, P2E(pos, ellipses[i])); 
    } 
    i = 1; 
    int first; 
    while (i < polylength) //test polygons 
    { 
     //first for line segments 
     first = i-1; 
     while (polygons[i] != (0.0, 0.0)) 
     { 
      mindistance = min(mindistance, P2L(pos, polygons[i-1], polygons[i])); 
      i++; 

     } 

     mindistance = min(mindistance, P2L(pos, polygons[i-1], polygons[first])); 
     if (PinPoly(pos, first, i-first)) //then test if it is inside a polygon 
     { 
      mindistance = 0.0; 
     } 
     i += 2; //jump over the (0,0) vec2 

    } 

    gl_FragColor = light*(1.0/thickness)*(thickness-mindistance).xxxx; //set color of fragment 
} 
""" 

. 내가 보는 방법에는이 문제를 해결할 수있는 두 가지 방법이 있습니다.

1 :

Generate points on curve. 
get closest curve point. 
generate points around curve point. 
get closest point of those. 
rince and repeat last steps until satisfactory precision is reached. 

2 : 해석의 거리를 얻을 수있는 공식/알고리즘으로 올라와. 나는 이것을 시도하고 어떤 수의 베 지어 커브 점에 대해서도 일정한 양에 대해서만 해결책을 찾지 못했습니다.

두 번째 방법에 대한 해결책을 선호합니다. 저는 첫 번째 방법에 대한 해결책을 스스로 고안 할 수 있습니다. 그러나 누군가가 그것을 찾는 모든 자원을 알고 있으므로 어쨌든 시간을 낭비하지 않아도됩니다.

답변

1

베 지어 곡선의 모든 점은 모든 매듭 점에 따라 다르므로 임의의 베 지어 곡선에 대해 거리를 분석적으로 계산하지 않는 것이 좋습니다. 곡선까지의 거리도 마찬가지입니다. (심지어이없이 현재의 구현은 매우 소모적 인 것 같다 및 확장되지 않습니다.)

내가 임의의 두 형태에 대한 거리지도 (또는 보로 노이 다이어그램을)를 계산하는 방법을 추천 할 수 있습니다 :

  1. Fast computation of generalized Voronoi diagrams...를 : 각 선 (세그먼트)마다 "텐트"(지붕처럼 배열 된 두 개의 쿼드)를 그려서 위에서 장면을 렌더링합니다. 깊이 버퍼는 거리 맵입니다. 빔 두께와 강도는 쉐이더에서 조정하거나 텐트 높이를 조정하여 조정할 수 있습니다. 각 점에 대해 콘을 렌더링합니다. 편집 : 추가 지오메트리가 기하학 셰이더에서도 생성 될 수 있습니다.

  2. Jump Flooding :이 때문에 핑퐁 렌더링 스키마를 설정하고 여러 버퍼로 렌더링해야합니다. 내가 설명하기에는 약간 길기 때문에 나는 알고리즘을 건너 뛰고, 종이를 보았다.

두 알고리즘 모두 많은 수의 모양에 적합합니다.