3

ViewPort3D在多设备应用程序表单中有一个元素,其中填充了大量TRectangle3D元素(从 1 到 10000)并LightMaterialSource应用于它们,所有这些都需要动态呈现,因为我还使用以下方法旋转相机程序:

procedure TForm3.Viewport3D1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
var
  I: IViewport3D;
begin
  if ssRight in shift then
  begin
    I:=ViewPort3D1;
    with tdummy(I.CurrentCamera.Parent) do RotationAngle.X:=RotAng.X - Y;
    with tdummy(I.CurrentCamera.Parent.Parent) do RotationAngle.Y:=RotAng.Y + X;
  end;
end;

然而,ViewPort3D当渲染的矩形数量至少接近几十个时,性能开始显着下降。将更多矩形添加到视口直到变成幻灯片时,相机旋转变得更慢且更无响应。

有没有办法在不删除所述矩形的情况下提高 ViewPort3D 的性能?

我尝试使用将 Multisample 属性设置为“none”:ViewPort3d1.Context.SetMultisample(TMultisample.None)以及MaterialSource从所有矩形中删除。虽然它确实对性能有所帮助,但并没有完全解决问题。

4

2 回答 2

1

10k 绘制的立方体

在我的测试中为 10k

Context.Draw/Fill.cube

在渲染事件中绘制效率更高,但是当摄像机角度发生变化时性能会显着下降。

TRectangle3D 创建 10k 块在创建 2k 块并在 Windows 上显示后会变成严重的性能问题。

如果在创建 TRectangle3D 后设置了 visible=false,则渲染完成速度非常快,

但是,当 visible=true 时,当摄像机角度发生变化时,性能会严重下降。

据我所知,减速的原因是对CPU的操作,即gpu不是这里减速的部分,但是当我检查代码时,总是有大量的事件类型消息将鼠标移动到对象的通知。

我的建议是,如果要使用很多可见对象,如果对象不在相机视图中,隐藏对象(可见 = false),在每个 mousemove 事件中使用循环隐藏对象,查看对象是否在相机区域中,这将有助于提高性能。

这里不仅有 10k 对象问题,它还有很多缺点。基本上这个可以用作简单工作的简单绘图 3d 引擎。

据我所知,在Java中,就像viewport3d对象一样,我们可以将unity引擎图形窗口添加到Java应用程序中的表单中,

我不知道是否可以将unity引擎图形窗口添加到delphi中,您可以向embercadero请求支持,但是对于高级图形,使用像unreal unity proffesional优化引擎这样的引擎会更合乎逻辑。

于 2021-09-13T01:14:38.553 回答
0

每个高级 fmx 3d 对象都会进行“drawcall”。(从 cpu(网格准备)到 gpu(用于显示)重新处理所有内容->您始终必须最小化 drawcall 计数。

因此,显示 10000 个 FMX 矩形永远不是解决方案。:)

您只需制作 1 个 Tmesh 后代,女巫将在一次调用中绘制您的 10000 个“手工”矩形。

请参阅 TMesh.Data(data.points 和 data.triangleindice)以了解如何在直接模式下绘制 3d 对象。或者,更简单地说,看看“TPlane”(在源代码中)是如何构建的。

作为一般计划,并且作为基本的“3d 制作”方法,制作“复杂”的 3d FMX 对象是可能的,但是您必须处理顶点/索引以在一次调用中绘制很多可能的东西。

例如,这里 a 是实现它的代码:

把 TMesh 放在你的视口上,然后调用这个 proc :


Procedure PopulateMesh_RectangleMap(aMesh : TMesh; const xCount : integer = 100; const yCount : integer=100; const rectWidth : single = 2.0; const rectHeight : single= 1.0);
var lv,li : integer;
    lsx, lsy, xpos, ypos : single;
    i,j : integer;
    a,b,c,d : TPoint3d; //4 corner of a rect.
begin
  Assert(assigned(aMesh));

  lsx := rectWidth;
  lsy := rectHeight;
  li := 0;
  lv := 0;

  //mem. allocation.
  aMesh.Data.Clear;
  aMesh.Data.VertexBuffer.Length := 4 * xCount * yCount;     //4 vertices by rect, need k*k rects.
  aMesh.Data.IndexBuffer.Length := 6 * xCount * yCount;     // 6 indices for 2 triangles desc (to make 1 rect) for k*k rects.

  for i := 0 to xcount-1 do
  for j := 0 to ycount-1 do begin

    xpos := -xcount/2 + i + i*lsx;
    ypos := -ycount/2 + j + j*lsy;

    a := point3d(xpos - lsx/2,ypos - lsy/2,0);
    b := point3d(xpos + lsx/2,ypos - lsy/2,0);
    c := point3d(xpos + lsx/2,ypos + lsy/2,0);
    d := point3d(xpos - lsx/2,ypos + lsy/2,0);

    aMesh.Data.VertexBuffer.Vertices[li+0] := a;
    aMesh.Data.VertexBuffer.Vertices[li+1] := b;
    aMesh.Data.VertexBuffer.Vertices[li+2] := c;
    aMesh.Data.VertexBuffer.Vertices[li+3] := d;

    aMesh.Data.IndexBuffer.Indices[lv+0] := li+0;
    aMesh.Data.IndexBuffer.Indices[lv+1] := li+1;
    aMesh.Data.IndexBuffer.Indices[lv+2] := li+2;
    aMesh.Data.IndexBuffer.Indices[lv+3] := li+2;
    aMesh.Data.IndexBuffer.Indices[lv+4] := li+3;
    aMesh.Data.IndexBuffer.Indices[lv+5] := li+0;

    inc(li,4);
    inc(lv,6);
  end;
  aMesh.Data.BoundingBoxNeedsUpdate; //We touch data. Update Mesh container.
  aMesh.Width := lsx*3;              //keep proportion.
  aMesh.Height := lsy*3;
  aMesh.Repaint;
end;
于 2021-10-27T12:01:53.563 回答