我正在为旋转操纵器编写一个 glsl 着色器。我的目标是 Autodesk Maya 风格,xy 和 z 旋转各有 3 个轴,沿相机前轴旋转的一个轴在它们上等于 4;
用户可以通过直接在视口中选择特定轴来将其操作结果限制在特定轴上。
为了启用对象选择,我使用带有 2 个附加纹理的 custrom 帧缓冲区作为渲染目标 - 一个用于颜色,一个用于选择 ID。
问题是让这 4 个轴由 GL_LINES 模式绘制会给用户带来问题。如果线条画得又细又漂亮,用户应该非常精确地点击它们来激活特定的轴,因为他必须精确地选择具有正确 object_id 轴的像素。我想通过制作两张单独的图纸来缓解他的生活。用于颜色输出的细线和用于 objectid 输出纹理的 3 倍宽的线。
我是openGL的新手。现在我的天真逻辑是传递一个布尔统一,告诉片段着色器绘制颜色或对象ID缓冲区。
这是带有传递的 render_target 选择器的绘图命令
GLfloat lw;
glGetFloatv(GL_LINE_WIDTH,&lw);
glUniform1ui(7,0);//render to RGB
glDrawArrays(GL_POINTS,0,1);
glUniform1ui(7,1);//render to OBJECTID
glLineWidth(10);
glDrawArrays(GL_POINTS,0,1);
glLineWidth(lw);
这是片段着色器:
#version 450
//inputs
layout(location=6) uniform uint manipulator_selected_axis;
layout(location=7) uniform uint render_to_selection_buffer;
//outputs
layout(location=0) out vec4 out_color;
layout(location=1) out float out_objectid;
void main(void)
{
if (render_to_selection_buffer==1)
{
switch (gl_PrimitiveID)
{
case 0: //CAMERA FORWARD
out_objectid=float(253)/256;
break;
case 1: //X
out_objectid=float(250)/256;
break;
case 2: //Y
out_objectid=float(251)/256;
break;
case 3: //Z
out_objectid=float(252)/256;
break;
}
out_color=vec4(0,0,0,0);
}
else
{
vec4 active_axis_color=vec4(1.0,1.0,0.0,1.0);
switch(gl_PrimitiveID)
{
case 0: //CAMERA FORWARD
if(manipulator_selected_axis==0)
out_color=active_axis_color;
else
out_color =vec4(1.0,0.5,1.0,1.0);
break;
case 1: //X
if(manipulator_selected_axis==1)
out_color=active_axis_color;
else
out_color =vec4(1.0,0.0,0.0,1.0);
break;
case 2: //Y
if(manipulator_selected_axis==2)
out_color=active_axis_color;
else
out_color =vec4(0.0,1.0,0.0,1.0);
break;
case 3: //Z
if(manipulator_selected_axis==3)
out_color=active_axis_color;
else
out_color =vec4(0.0,0.0,1.0,1.0);
break;
case 4:
out_color =vec4(0.6,0.6,0.6,1.0);
break;
}
out_objectid=0;
}
}
我真的不喜欢我为此使用的逻辑,因为它看起来丑陋且未经优化。首先,因为着色器必须运行两次,并且它有一个相当复杂的几何着色器,我在其中生成圆。其次,因为我的片段着色器中有很多 if else 的东西,我被告知 gpu 不喜欢分支。
那么问题 1 编写这样的着色器的替代正确方法是什么?问题2更具技术性。
在这里,我提供了通过 theese 2 glDrawArrays 调用得到的屏幕截图。如您所见,我的颜色缓冲区中有黑色轮廓。问题是当 framgent 着色器执行 out_objectid 目标的渲染代码时,它仍然会向 out_color 写入一些脏的随机信息,如下图所示,所以我不得不用 out_color=vec4(0,0,0,0 )。至少它给出了干净的黑色。
所以问题2。我的错误在哪里?如何防止 objectid 块写入 out_color?谢谢更新:按照我的建议,我达到了这种效果。我无法描述 openGL 内部发生了什么。看起来它仍然写入 GL_DEPTH_COMPONENT 并进行了一些未定义的深度测试,从而导致了这种结果。我不希望在此绘制调用期间进行任何深度写入,因为操纵器始终位于顶部。也许你可以给我额外的建议。
绘图代码
glBindBuffer(GL_ARRAY_BUFFER,0);
glUseProgram(program_id_ctl_manip_color);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glUniform4f(0,0,0,0,1);
glUniform1f(5,0.67);
glUniform1ui(6,manipulator_axis_highlight);
glUniformMatrix4fv(10,1,GL_TRUE,cam.matrix_view.m);
glUniformMatrix4fv(14,1,GL_TRUE,cam.matrix_projection_ortho.m);
glUniformMatrix4fv(18,1,GL_TRUE,cam.matrix_camera.m);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glDrawArrays(GL_POINTS,0,1);
GLfloat lw;
glGetFloatv(GL_LINE_WIDTH,&lw);
glLineWidth(6);
glUseProgram(program_id_ctl_manip_objectid);
glUniform4f(0,0,0,0,1);
glUniform1f(5,0.67);
glUniform1ui(6,manipulator_axis_highlight);
glUniformMatrix4fv(10,1,GL_TRUE,cam.matrix_view.m);
glUniformMatrix4fv(14,1,GL_TRUE,cam.matrix_projection_ortho.m);
glUniformMatrix4fv(18,1,GL_TRUE,cam.matrix_camera.m);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glDrawArrays(GL_POINTS,0,1);
GLenum buffers[2]={GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1};
glDrawBuffers(2,buffers);
glLineWidth(lw);