mai*_*rgs 7 java opengl jogl worldwind
Worldwind的Point PlaceMark可渲染具有通过调用setLineEnabled从地标到地形的一条线,如下截图所示:
我正在尝试做的是添加一条这样的线,它也适用于可渲染的战术符号.我的第一个想法是从PointPlacemark可渲染中借用逻辑来执行此操作,并将其添加到AbstractTacticalSymbol可渲染.我试过了,到目前为止我还没有成功.
这是我到目前为止所做的:
将此添加到OrderedSymbol类:
public Vec4 terrainPoint;
Run Code Online (Sandbox Code Playgroud)更新了computeSymbolPoints以计算terrainPoint
protected void computeSymbolPoints(DrawContext dc, OrderedSymbol osym)
{
osym.placePoint = null;
osym.screenPoint = null;
osym.terrainPoint = null;
osym.eyeDistance = 0;
Position pos = this.getPosition();
if (pos == null)
return;
if (this.altitudeMode == WorldWind.CLAMP_TO_GROUND || dc.is2DGlobe())
{
osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
}
else if (this.altitudeMode == WorldWind.RELATIVE_TO_GROUND)
{
osym.placePoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), pos.getAltitude());
}
else // Default to ABSOLUTE
{
double height = pos.getElevation() * dc.getVerticalExaggeration();
osym.placePoint = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), height);
}
if (osym.placePoint == null)
return;
// Compute the symbol's screen location the distance between the eye point and the place point.
osym.screenPoint = dc.getView().project(osym.placePoint);
osym.eyeDistance = osym.placePoint.distanceTo3(dc.getView().getEyePoint());
// Compute a terrain point if needed.
if (this.isLineEnabled() && this.altitudeMode != WorldWind.CLAMP_TO_GROUND && !dc.is2DGlobe())
osym.terrainPoint = dc.computeTerrainPoint(pos.getLatitude(), pos.getLongitude(), 0);
}
Run Code Online (Sandbox Code Playgroud)添加了此逻辑(取自PointPlacemark.java并更新以符合AbstractTacticalSymbol.java).请注意,我将lineEnabled设置为true,因此默认情况下应该绘制该行.
boolean lineEnabled = true;
double lineWidth = 1;
protected int linePickWidth = 10;
Color lineColor = Color.white;
/**
* Indicates whether a line from the placemark point to the corresponding position on the terrain is drawn.
*
* @return true if the line is drawn, otherwise false.
*/
public boolean isLineEnabled()
{
return lineEnabled;
}
/**
* Specifies whether a line from the placemark point to the corresponding position on the terrain is drawn.
*
* @param lineEnabled true if the line is drawn, otherwise false.
*/
public void setLineEnabled(boolean lineEnabled)
{
this.lineEnabled = lineEnabled;
}
/**
* Determines whether the placemark's optional line should be drawn and whether it intersects the view frustum.
*
* @param dc the current draw context.
*
* @return true if the line should be drawn and it intersects the view frustum, otherwise false.
*/
protected boolean isDrawLine(DrawContext dc, OrderedSymbol opm)
{
if (!this.isLineEnabled() || dc.is2DGlobe() || this.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND
|| opm.terrainPoint == null)
return false;
if (dc.isPickingMode())
return dc.getPickFrustums().intersectsAny(opm.placePoint, opm.terrainPoint);
else
return dc.getView().getFrustumInModelCoordinates().intersectsSegment(opm.placePoint, opm.terrainPoint);
}
/**
* Draws the placemark's line.
*
* @param dc the current draw context.
* @param pickCandidates the pick support object to use when adding this as a pick candidate.
*/
protected void drawLine(DrawContext dc, PickSupport pickCandidates, OrderedSymbol opm)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
if ((!dc.isDeepPickingEnabled()))
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glDepthMask(true);
try
{
dc.getView().pushReferenceCenter(dc, opm.placePoint); // draw relative to the place point
this.setLineWidth(dc);
this.setLineColor(dc, pickCandidates);
gl.glBegin(GL2.GL_LINE_STRIP);
gl.glVertex3d(Vec4.ZERO.x, Vec4.ZERO.y, Vec4.ZERO.z);
gl.glVertex3d(opm.terrainPoint.x - opm.placePoint.x, opm.terrainPoint.y - opm.placePoint.y,
opm.terrainPoint.z - opm.placePoint.z);
gl.glEnd();
}
finally
{
dc.getView().popReferenceCenter(dc);
}
}
/**
* Sets the width of the placemark's line during rendering.
*
* @param dc the current draw context.
*/
protected void setLineWidth(DrawContext dc)
{
Double lineWidth = this.lineWidth;
if (lineWidth != null)
{
GL gl = dc.getGL();
if (dc.isPickingMode())
{
gl.glLineWidth(lineWidth.floatValue() + linePickWidth);
}
else
gl.glLineWidth(lineWidth.floatValue());
if (!dc.isPickingMode())
{
gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_FASTEST);
gl.glEnable(GL.GL_LINE_SMOOTH);
}
}
}
/**
* Sets the color of the placemark's line during rendering.
*
* @param dc the current draw context.
* @param pickCandidates the pick support object to use when adding this as a pick candidate.
*/
protected void setLineColor(DrawContext dc, PickSupport pickCandidates)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
if (!dc.isPickingMode())
{
Color color = this.lineColor;
gl.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(),
(byte) color.getAlpha());
}
else
{
Color pickColor = dc.getUniquePickColor();
Object delegateOwner = this.getDelegateOwner();
pickCandidates.addPickableObject(pickColor.getRGB(), delegateOwner != null ? delegateOwner : this,
this.getPosition());
gl.glColor3ub((byte) pickColor.getRed(), (byte) pickColor.getGreen(), (byte) pickColor.getBlue());
}
}
Run Code Online (Sandbox Code Playgroud)将此调用添加到drawOrderedRenderable方法的开头:
boolean drawLine = this.isDrawLine(dc, osym);
if (drawLine)
this.drawLine(dc, pickCandidates, osym);
Run Code Online (Sandbox Code Playgroud)我相信这很接近于PointPlacemark正在做什么以使线到地形出现,但这是我在运行TacticalSymbols示例时得到的结果:
以下是我的(尝试)更改的整个AbsractTacticalSymbol文件:http://pastebin.com/aAC7zn0p (对于SO来说太大了)
好吧,这里的问题是框架内的正交投影和透视投影之间的混合.至关重要的是,如果我们看看PointPlaceMark,beginDrawing
我们会看到:
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
int attrMask =
GL2.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func
... bunch more bits being set ...
gl.glPushAttrib(attrMask);
if (!dc.isPickingMode())
{
gl.glEnable(GL.GL_BLEND);
OGLUtil.applyBlending(gl, false);
}
Run Code Online (Sandbox Code Playgroud)
而已.但是如果我们看一下AbstractTacticalSymbol,beginDrawing
我们会看到更多的代码,特别是这两行:
this.BEogsh.pushProjectionIdentity(gl);
gl.glOrtho(0d, viewport.getWidth(), 0d, viewport.getHeight(), 0d, -1d);
Run Code Online (Sandbox Code Playgroud)
从视角切换的OpenGL投影到正交模式中,两个完全不同的投影技术不拌匀,除了几个显着的情况:他们中的一个UI渲染在3D场景,例如:绘制图标!视频显示正交和透视渲染之间的差异
我觉得别扭言传,但角度呈现给你的角度来看,和正交渲染没有,那么你得到的东西就像一个2D游戏,这对于UI效果很好,但不适合逼真的3D图像.
但PointPlaceMark也会渲染一个图标,那么该文件在两种投影模式之间切换的位置是什么?事实证明他们doDrawOrderedRenderable
在通话后这样做drawLine
(第976行).
那么,为什么会出错呢?现在框架内部有很多魔法,所以我不能确切地知道会发生什么,但我已经大家都知道出了什么问题.这是错误的,因为透视投影允许您以完全不同的方式提供坐标到正投影(在框架中),在这种情况下可能提供(x,y,z)投影渲染渲染点(X,Y,Z) )世界空间,而正交渲染渲染在(x,y,z)屏幕空间(或剪辑空间,我不是专业人士).因此,当您现在在坐标(300000,300000,z)处从图标到地面绘制一条线时,它们当然会脱离屏幕而不可见,因为您没有300000x3000000像素的屏幕.也可能两种方法都允许在世界空间中提供坐标(虽然这似乎不太可能),在这种情况下,下图说明了问题.两个相机在下面的方框中指向相同的方向,但看到不同的东西.
因此,由于渲染代码在透视投影在开出render()
的方法,解决这个是延迟的正投影开始简单之后,我们已经绘制的线条,就像PointPlaceMark的代码.这正是我在这里做的(1962年到1968年),它只是在正交投影之外移动了几行代码,所以之前beginDrawing
,你差不多完成了.
现在这个解决方案不是很优雅,因为代码的功能现在很大程度上取决于它的执行顺序,这通常非常容易出错.这部分是因为我做了简单的修复,但主要是因为框架遵循不推荐的OpenGL标准来切换视角(除此之外),所以我无法生成一个真正完美的解决方案,无论这样的解决方案是否在我的内部能力.
根据您的偏好,您可能希望使用继承来创建SymbolWithLine
超类或接口,或使用组合来添加功能.或者你可以这样离开,如果你不需要这个功能与许多其他类.无论如何,我希望这是解决这个问题的足够信息.
根据您的要求,以下行演示了线宽和线条颜色的变化(第1965行):
this.lineColor = Color.CYAN;
this.lineWidth = 3;
this.drawLine(dc, this.pickSupport, osym);
Run Code Online (Sandbox Code Playgroud)
我不确定这是否属于"规范性答案",但我很乐意用任何建议更新答案,或者更多地澄清我的解释.我认为答案的关键在于对正交投影与透视投影的理解,但我认为这不是真正回答这个问题的典型答案的地方.