问题描述
我制作了一个 glsl 几何着色器,它可以使 2D 线条的角变圆。着色器在每个角插入圆形圆角。
有一种特殊情况,即两个相邻线段共线且无法创建圆角。在这种情况下,只传递一个原始顶点。
这需要对每个输入顶点执行一个 if 语句。在这种特殊情况下,有没有一种聪明的方法可以避免分支?如果每帧处理的顶点总数通常在几百个左右,这甚至是一个问题吗?
这是完整的着色器代码:
#version 400
layout(lines_adjacency) in;
layout(line_strip,max_vertices=25) out;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform float radius = 160.0;
uniform int steps = 10;
in VS_OUT {
vec2 position;
} gsIn[];
bool arc(vec2 p0,vec2 p1,vec2 p2,out vec2 arcCenter,out vec2 arcStartPoint,out vec2 arcMidPoint,out vec2 arcEndPoint){
vec2 t0 = normalize(p0 - p1);
vec2 t1 = normalize(p2 - p1);
// segments are colinear,exit
if(abs(dot(t0,t1)) > .9999f){
return false;
}
vec2 h = normalize((t0 + t1) /2.0);
float cosa = abs(dot(h,vec2(-t0.y,t0.x)));
float hlen = radius/cosa;
arcCenter = p1 + h*hlen;
float d = sqrt(hlen*hlen - radius*radius);
arcStartPoint = p1 + t0 * d;
arcEndPoint = p1 + t1 *d;
arcMidPoint = arcCenter - h * radius;
return true;
}
float stepangle(vec2 center,vec2 s,vec2 e){
vec2 rv1 = s-center;
vec2 rv2 = e-center;
float angle = acos( dot(normalize(rv1),normalize(rv2)) ) / steps;
if( dot(rv1,vec2(-rv2.y,rv2.x))<0 ){
angle = -angle;
}
return angle;
}
mat2 rotationMatrix(float angle){
float cosa = cos(angle);
float sina = sin(angle);
return mat2(cosa,-sina,sina,cosa);
}
void emitFillet(vec2 center,vec2 arcStartPoint,vec2 arcEndPoint,mat4 mvpMatrix){
float a = stepangle(center,arcStartPoint,arcEndPoint);
mat2 rotMat = rotationMatrix(a);
vec2 radVec = arcStartPoint-center;
for(int i=0; i <=steps ; ++i){
gl_Position = mvpMatrix * vec4(center + radVec,0.0,1.0);
EmitVertex();
radVec = rotMat * radVec;
}
}
void emitSingLevertex(vec2 vert,mat4 mvpMatrix){
gl_Position = mvpMatrix * vec4(vert,1.0);
EmitVertex();
}
void main(){
mat4 mvMatrix = viewMatrix * modelMatrix;
mat4 mvpMatrix = projectionMatrix * mvMatrix;
vec2 p0 = gsIn[0].position;
vec2 p1 = gsIn[1].position;
vec2 p2 = gsIn[2].position;
vec2 p3 = gsIn[3].position;
vec2 center,s,m,e;
mat2 rotMat;
vec2 radVec;
float a;
bool canMakeFillet;
// first corner half-fillet
canMakeFillet = arc(p0,p1,p2,center,e);
if(canMakeFillet){
emitFillet(center,e,mvpMatrix);
}
else{
emitSingLevertex(p1,mvpMatrix);
}
// scond corner half-fillet
canMakeFillet = arc(p1,p3,mvpMatrix);
}
else{
emitSingLevertex(p2,mvpMatrix);
}
EndPrimitive();
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)