Skip to content

Commit d8455ab

Browse files
committed
More robust and simpler near plane clipping of lines
1 parent 50bd966 commit d8455ab

File tree

5 files changed

+40
-72
lines changed

5 files changed

+40
-72
lines changed

src/3d/qgs3dmapscene.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -578,17 +578,11 @@ void Qgs3DMapScene::addLayerEntity( QgsMapLayer *layer )
578578
QgsLineMaterial *lm = newEntity->findChild<QgsLineMaterial *>();
579579
if ( lm )
580580
{
581-
connect( mCameraController, &QgsCameraController::cameraChanged, lm, [lm, this]
582-
{
583-
Qt3DRender::QCamera *cam = mCameraController->camera();
584-
lm->setCameraParameters( cam->position(), cam->viewVector(), cam->nearPlane() );
585-
} );
586581
connect( mCameraController, &QgsCameraController::viewportChanged, lm, [lm, this]
587582
{
588583
lm->setViewportSize( mCameraController->viewport().size() );
589584
} );
590585

591-
lm->setCameraParameters( cameraController()->camera()->position(), cameraController()->camera()->viewVector(), cameraController()->camera()->nearPlane() );
592586
lm->setViewportSize( cameraController()->viewport().size() );
593587
}
594588
}

src/3d/shaders/lines.geom

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,13 @@ uniform float THICKNESS; // the thickness of the line in pixels
44
uniform float MITER_LIMIT; // 1.0: always miter, -1.0: never miter, 0.75: default
55
uniform vec2 WIN_SCALE; // the size of the viewport in pixels
66

7-
uniform mat4 modelViewProjection;
8-
9-
uniform vec3 camNearPlanePoint;
10-
uniform vec3 camNearPlaneNormal;
11-
127
layout( lines_adjacency ) in;
138
layout( triangle_strip, max_vertices = 7 ) out;
149

1510

16-
in VertexData{
17-
vec3 worldPosition;
11+
//in VertexData{
1812
// vec3 mColor;
19-
} VertexIn[4];
13+
//} VertexIn[4];
2014

2115
out VertexData{
2216
vec2 mTexCoord;
@@ -28,66 +22,61 @@ vec2 toScreenSpace( vec4 vertex )
2822
return vec2( vertex.xy / vertex.w ) * WIN_SCALE;
2923
}
3024

31-
vec4 clip_line_point(vec3 pt0, vec3 pt1, vec4 projected)
25+
vec4 clip_near_plane(vec4 pt1, vec4 pt2)
3226
{
33-
// we have line segment given by pt0 and pt1 (in world coordinates) and 'projected' point
34-
// (in clip coordinates) that is one of the endpoints. If the projected point's w >= 1
35-
// then everything is fine because the point is in front of the camera's near plane and
36-
// it is projected correctly. If not, the projected point is wrong and needs to be adjusted.
37-
// we place it at the intersection of the line and near plane to fix its position.
38-
39-
if (projected.w < 1)
40-
{
41-
vec3 lineDir = pt1 - pt0;
42-
float d = dot(camNearPlaneNormal, camNearPlanePoint - pt0) / dot(lineDir, camNearPlaneNormal);
43-
if (d > 0 && d < 1)
44-
{
45-
// figure out the intersection point of line and near plane
46-
vec3 wpIntersect = pt0 + lineDir * d;
47-
vec4 wpIntersectProj = modelViewProjection * vec4( wpIntersect, 1.0 );
48-
return wpIntersectProj;
49-
}
50-
}
51-
return projected;
27+
// Figure out intersection point of line pt1-pt2 and near plane in homogenous coordinates.
28+
// Near plane is z=-1 in NDC, that means in homogenous coordinates that's z/w=-1
29+
// Going from line equation P = P1 + u * (P2 - P1) we need to figure out "u"
30+
// In the above equation P, P1, P2 are vectors, so individual coordinate values are
31+
// x = x1 + u * (x2 - x1) and so on for y,z,w as well. Now combining near plane equation z/w=-1
32+
// with line equation gives us the following equation for "u" (it's easy to do the math on paper)
33+
34+
float u = (-pt1.z - pt1.w) / ((pt2.z-pt1.z) + (pt2.w - pt1.w));
35+
return pt1 + (pt2-pt1)*u;
5236
}
5337

5438
void main( void )
5539
{
56-
// these are original positions in world coordinates
57-
vec3 wp0 = VertexIn[0].worldPosition;
58-
vec3 wp1 = VertexIn[1].worldPosition;
59-
vec3 wp2 = VertexIn[2].worldPosition;
60-
vec3 wp3 = VertexIn[3].worldPosition;
40+
vec4 px0 = gl_in[0].gl_Position;
41+
vec4 px1 = gl_in[1].gl_Position;
42+
vec4 px2 = gl_in[2].gl_Position;
43+
vec4 px3 = gl_in[3].gl_Position;
6144

6245
// This implements rejection of lines from Cohen-Sutherland line clipping algorithm.
6346
// Thanks to that we filter out majority of lines that may otherwise cause issues.
64-
// Lines that can't be trivially rejected, should be further clipped - the clipping
65-
// in the next step is a bit half-baked but seems to work relatively well.
66-
vec4 px1 = gl_in[1].gl_Position;
67-
vec4 px2 = gl_in[2].gl_Position;
47+
// Lines that can't be trivially rejected, should be further clipped
6848
int px1c = int(px1.w+px1.x<0) << 0 | int(px1.w-px1.x<0) << 1 | int(px1.w+px1.y<0) << 2 | int(px1.w-px1.y<0) << 3 | int(px1.w+px1.z<0) << 4 | int(px1.w-px1.z<0) << 5;
6949
int px2c = int(px2.w+px2.x<0) << 0 | int(px2.w-px2.x<0) << 1 | int(px2.w+px2.y<0) << 2 | int(px2.w-px2.y<0) << 3 | int(px2.w+px2.z<0) << 4 | int(px2.w-px2.z<0) << 5;
7050
if ((px1c & px2c) != 0)
7151
return; // trivial reject
7252

73-
// Perform line clipping first. we search for intersection between the line and the near plane.
53+
// Perform line clipping with near plane if needed. We search for intersection between the line and the near plane.
7454
// In case the near plane intersects line between segment's endpoints, we need to adjust the line
7555
// otherwise we would use completely non-sense points when points get 'behind' the camera.
76-
// We do this also for the 'previous' and 'next' segments to get the miters right.
77-
vec4 projp0 = clip_line_point(wp0, wp1, gl_in[0].gl_Position);
78-
vec4 projp1 = clip_line_point(wp1, wp2, gl_in[1].gl_Position);
79-
vec4 projp2 = clip_line_point(wp1, wp2, gl_in[2].gl_Position);
80-
vec4 projp3 = clip_line_point(wp2, wp3, gl_in[3].gl_Position);
56+
// It seems we don't need to clip against other five planes - only the near plane is critical because
57+
// that turns the coordinates after perspective division in toScreenSpace() into a mess because of w < 1
58+
if ((px1c & 16) != 0)
59+
{
60+
// first point is in front of the near plane - need to clip it
61+
px1 = clip_near_plane(px1, px2);
62+
px0 = px1;
63+
}
64+
if ((px2c & 16) != 0)
65+
{
66+
// second point is in front of the near plane - need to clip it
67+
px2 = clip_near_plane(px1, px2);
68+
px3 = px2;
69+
}
8170

8271
// get the four vertices passed to the shader:
83-
vec2 p0 = toScreenSpace( projp0 ); // start of previous segment
84-
vec2 p1 = toScreenSpace( projp1 ); // end of previous segment, start of current segment
85-
vec2 p2 = toScreenSpace( projp2 ); // end of current segment, start of next segment
86-
vec2 p3 = toScreenSpace( projp3 ); // end of next segment
72+
vec2 p0 = toScreenSpace( px0 ); // start of previous segment
73+
vec2 p1 = toScreenSpace( px1 ); // end of previous segment, start of current segment
74+
vec2 p2 = toScreenSpace( px2 ); // end of current segment, start of next segment
75+
vec2 p3 = toScreenSpace( px3 ); // end of next segment
8776

8877
// these are already 'final' depths in range [0,1] so we don't need to further transform them
89-
float p1z = projp1.z / projp1.w;
90-
float p2z = projp2.z / projp2.w;
78+
float p1z = px1.z / px1.w;
79+
float p2z = px2.z / px2.w;
9180

9281
// determine the direction of each of the 3 segments (previous, current, next)
9382
vec2 v0 = normalize( p1 - p0 );

src/3d/shaders/lines.vert

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@ uniform mat4 modelViewProjection;
55
in vec3 vertexPosition;
66
//in vec3 ciColor;
77

8-
out VertexData{
8+
//out VertexData{
99
// vec3 mColor;
10-
vec3 worldPosition;
11-
} VertexOut;
10+
//} VertexOut;
1211

1312

1413
void main(void)
1514
{
1615
//VertexOut.mColor = ciColor;
1716
gl_Position = modelViewProjection * vec4( vertexPosition, 1.0 );
18-
VertexOut.worldPosition = vertexPosition;
1917
}

src/3d/symbols/qgslinematerial_p.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,11 @@ QgsLineMaterial::QgsLineMaterial()
3737
, mParameterMiterLimit( new Qt3DRender::QParameter( "MITER_LIMIT", -1, this ) ) // 0.75
3838
, mParameterLineColor( new Qt3DRender::QParameter( "lineColor", QColor( 0, 255, 0 ), this ) )
3939
, mParameterWindowScale( new Qt3DRender::QParameter( "WIN_SCALE", QSizeF(), this ) )
40-
, mParameterCameraNearPlanePoint( new Qt3DRender::QParameter( "camNearPlanePoint", QVector3D(), this ) )
41-
, mParameterCameraNearPlaneNormal( new Qt3DRender::QParameter( "camNearPlaneNormal", QVector3D(), this ) )
4240
{
4341
addParameter( mParameterThickness );
4442
addParameter( mParameterMiterLimit );
4543
addParameter( mParameterLineColor );
4644
addParameter( mParameterWindowScale );
47-
addParameter( mParameterCameraNearPlanePoint );
48-
addParameter( mParameterCameraNearPlaneNormal );
4945

5046
//Parameter { name: "tex0"; value: txt },
5147
//Parameter { name: "useTex"; value: false },
@@ -106,12 +102,6 @@ float QgsLineMaterial::lineWidth() const
106102
return mParameterThickness->value().toFloat();
107103
}
108104

109-
void QgsLineMaterial::setCameraParameters( const QVector3D &position, const QVector3D &viewVector, float nearPlane )
110-
{
111-
mParameterCameraNearPlanePoint->setValue( position + viewVector * nearPlane );
112-
mParameterCameraNearPlaneNormal->setValue( viewVector );
113-
}
114-
115105
void QgsLineMaterial::setViewportSize( const QSizeF &viewportSize )
116106
{
117107
mParameterWindowScale->setValue( viewportSize );

src/3d/symbols/qgslinematerial_p.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ class QgsLineMaterial : public Qt3DRender::QMaterial
6464
void setLineWidth( float width );
6565
float lineWidth() const;
6666

67-
Q_INVOKABLE void setCameraParameters( const QVector3D &position, const QVector3D &viewVector, float nearPlane );
6867
Q_INVOKABLE void setViewportSize( const QSizeF &viewportSize );
6968

7069
private:
@@ -73,8 +72,6 @@ class QgsLineMaterial : public Qt3DRender::QMaterial
7372
Qt3DRender::QParameter *mParameterLineColor = nullptr;
7473

7574
Qt3DRender::QParameter *mParameterWindowScale = nullptr;
76-
Qt3DRender::QParameter *mParameterCameraNearPlanePoint = nullptr;
77-
Qt3DRender::QParameter *mParameterCameraNearPlaneNormal = nullptr;
7875

7976
};
8077

0 commit comments

Comments
 (0)