Opengl es 具有恒定屏幕宽度的厚3D纹理线条

Opengl es 具有恒定屏幕宽度的厚3D纹理线条,opengl-es,3d,line,vertex-shader,Opengl Es,3d,Line,Vertex Shader,我正在尝试绘制具有恒定屏幕宽度的3D纹理线。(OpenGL ES 2.0) 实际上,我想要的是具有最小保证(夹紧)屏幕宽度的简单“体积”线。这样,当它们离得很远时,它们就不会变得太薄 任何关于如何到达那里的意见都将非常感谢,但是我也希望就我目前面临的问题获得一些反馈。很可能是对透视正确插值工作原理的误解 我有一个三角形的条带,像这样: struct tVtx { vec3 mPos; vec3 mDir; vec2 mTexCoord; }; auto vtxs = std:

我正在尝试绘制具有恒定屏幕宽度的3D纹理线。(OpenGL ES 2.0)

实际上,我想要的是具有最小保证(夹紧)屏幕宽度的简单“体积”线。这样,当它们离得很远时,它们就不会变得太薄

任何关于如何到达那里的意见都将非常感谢,但是我也希望就我目前面临的问题获得一些反馈。很可能是对透视正确插值工作原理的误解

我有一个三角形的条带,像这样:

struct tVtx
{
  vec3  mPos;
  vec3  mDir;
  vec2  mTexCoord;
};

auto vtxs = std::vector< tVtx >{
  { vec3{ -1,0,0 }, vec3{ 1,0,0 }, vec2{ -1,  1 } },
  { vec3{ -1,0,0 }, vec3{ 1,0,0 }, vec2{ -1, -1 } },
  { vec3{ -1,0,0 }, vec3{ 1,0,0 }, vec2{  0,  1 } },
  { vec3{ -1,0,0 }, vec3{ 1,0,0 }, vec2{  0, -1 } },
  { vec3{  1,0,0 }, vec3{ 1,0,0 }, vec2{  0,  1 } },
  { vec3{  1,0,0 }, vec3{ 1,0,0 }, vec2{  0, -1 } },
  { vec3{  1,0,0 }, vec3{ 1,0,0 }, vec2{  1,  1 } },
  { vec3{  1,0,0 }, vec3{ 1,0,0 }, vec2{  1, -1 } }
};
pt1 = vec3{  -0.450794667,  0.454502404,-0.437951744 };
pt2 = vec3{   -0.248224616,0.682369053, -0.886776387 };

auto center = ( pt1 + pt2 ) * 0.5f;
auto right = normalize( pt2 - pt1 );
auto up = normalize( cross( vec3( 0,0,1 ), right ) );
auto forw = cross( right, up );
auto mtx = mat4{ vec4( right, 0.0 ), vec4( up, 0.0 ), vec4( forw, 0.0   ), vec4( center, 1.0f ) };
我的顶点着色器类似于:

attribute vec3  aPos;
attribute vec3  aDir;
attribute vec2  aTexCoord;

uniform mat4  uMVPMtx;
uniform vec2  uScreenExtent;  // half size of screen
uniform vec2  uInflate;       // amount of line "grow" in pixels

varying mediump vec2 vTexCoord;

void main()
{
  vec4  clipPos1 = uMVPMtx * vec4( aPos, 1.0 );
  // get a point on "direction" line, transform in screen and then get screen space direction vector
  // don't know how to transform a direction vector from WORLD to SCREEN space, naive way does not work ( MVP * vec4( aDir, 0.0 ) )
  vec4  clipPos2 = uMVPMtx * vec4( aPos + aDir * 1000.0, 1.0 );
  vec2  ndc1 = vec2( clipPos1 ) / clipPos1.w;
  vec2  ndc2 = vec2( clipPos2 ) / clipPos2.w;
  vec2  sc1 = ndc1 * uScreenExtent;
  vec2  sc2 = ndc2 * uScreenExtent;
  vec2  dir = normalize( sc2 - sc1 ) * sign( clipPos1.w * clipPos2.w ); // reduce damage if points lie on opposite sides of origin
  vec2  perp = vec2( -dir.y, dir.x );
  vec2  sc = sc1 + dir * aTexCoord.x * uInflate.x + perp * aTexCoord.y * uInflate.y;

  vTexCoord = aTexCoord;

  // bring back to clip space
  gl_Position = vec4( sc / uScreenExtent * clipPos1.w, clipPos1.zw );
}
varying mediump vec2 vTexCoord;

void main()
{
  mediump float dist = clamp( length( vTexCoord ), 0.0, 1.0 );

  gl_FragColor = vec4( mix( vec3( 1.0, 0.25, 0.25 ), vec3( 0.25, 1.0, 0.25 ), dist ), 1.0 );
}
片段着色器类似于:

attribute vec3  aPos;
attribute vec3  aDir;
attribute vec2  aTexCoord;

uniform mat4  uMVPMtx;
uniform vec2  uScreenExtent;  // half size of screen
uniform vec2  uInflate;       // amount of line "grow" in pixels

varying mediump vec2 vTexCoord;

void main()
{
  vec4  clipPos1 = uMVPMtx * vec4( aPos, 1.0 );
  // get a point on "direction" line, transform in screen and then get screen space direction vector
  // don't know how to transform a direction vector from WORLD to SCREEN space, naive way does not work ( MVP * vec4( aDir, 0.0 ) )
  vec4  clipPos2 = uMVPMtx * vec4( aPos + aDir * 1000.0, 1.0 );
  vec2  ndc1 = vec2( clipPos1 ) / clipPos1.w;
  vec2  ndc2 = vec2( clipPos2 ) / clipPos2.w;
  vec2  sc1 = ndc1 * uScreenExtent;
  vec2  sc2 = ndc2 * uScreenExtent;
  vec2  dir = normalize( sc2 - sc1 ) * sign( clipPos1.w * clipPos2.w ); // reduce damage if points lie on opposite sides of origin
  vec2  perp = vec2( -dir.y, dir.x );
  vec2  sc = sc1 + dir * aTexCoord.x * uInflate.x + perp * aTexCoord.y * uInflate.y;

  vTexCoord = aTexCoord;

  // bring back to clip space
  gl_Position = vec4( sc / uScreenExtent * clipPos1.w, clipPos1.zw );
}
varying mediump vec2 vTexCoord;

void main()
{
  mediump float dist = clamp( length( vTexCoord ), 0.0, 1.0 );

  gl_FragColor = vec4( mix( vec3( 1.0, 0.25, 0.25 ), vec3( 0.25, 1.0, 0.25 ), dist ), 1.0 );
}
注意,aTexCoord从-1变为1

我得到的是:

attribute vec3  aPos;
attribute vec3  aDir;
attribute vec2  aTexCoord;

uniform mat4  uMVPMtx;
uniform vec2  uScreenExtent;  // half size of screen
uniform vec2  uInflate;       // amount of line "grow" in pixels

varying mediump vec2 vTexCoord;

void main()
{
  vec4  clipPos1 = uMVPMtx * vec4( aPos, 1.0 );
  // get a point on "direction" line, transform in screen and then get screen space direction vector
  // don't know how to transform a direction vector from WORLD to SCREEN space, naive way does not work ( MVP * vec4( aDir, 0.0 ) )
  vec4  clipPos2 = uMVPMtx * vec4( aPos + aDir * 1000.0, 1.0 );
  vec2  ndc1 = vec2( clipPos1 ) / clipPos1.w;
  vec2  ndc2 = vec2( clipPos2 ) / clipPos2.w;
  vec2  sc1 = ndc1 * uScreenExtent;
  vec2  sc2 = ndc2 * uScreenExtent;
  vec2  dir = normalize( sc2 - sc1 ) * sign( clipPos1.w * clipPos2.w ); // reduce damage if points lie on opposite sides of origin
  vec2  perp = vec2( -dir.y, dir.x );
  vec2  sc = sc1 + dir * aTexCoord.x * uInflate.x + perp * aTexCoord.y * uInflate.y;

  vTexCoord = aTexCoord;

  // bring back to clip space
  gl_Position = vec4( sc / uScreenExtent * clipPos1.w, clipPos1.zw );
}
varying mediump vec2 vTexCoord;

void main()
{
  mediump float dist = clamp( length( vTexCoord ), 0.0, 1.0 );

  gl_FragColor = vec4( mix( vec3( 1.0, 0.25, 0.25 ), vec3( 0.25, 1.0, 0.25 ), dist ), 1.0 );
}

上面的图片有uInflate.x=0,所以它没有圆顶

我想得到的是一个有中心红线的四边形,逐渐变为绿色。 这是因为我在屏幕空间中改变x和y坐标而不接触z和w分量的方式会产生不再共面的三角形吗?我很难想象这个

更新

这些三角形在眼睛空间中是共面的,但它们的大小(在眼睛空间中)差别很大。屏幕上看起来像四边形的东西在眼睛空间中不再是四边形了。我想这是主要问题(因为透视正确插值??)。问题仍然存在:如何绘制具有恒定(或受控)屏幕宽度的3D纹理线。对于3D,我指的是用其他3D内容进行深度测试的线条。

我认为你在思考和做复杂的事情方面做得太过火了。只需输出x,y,0,1作为位置,您就应该全部设置好了。看看任何一个只会闪烁纹理的示例着色器。你的顶点着色器应该是三条线左右…这些线应该是3D的,深度测试与其他3D内容。像“体积”线(请参阅),但我需要完全控制它们的屏幕空间宽度。无论如何,谢谢你的评论。