【问题标题】:TMesh - generate 3d shape and calculate normalsTMesh - 生成 3d 形状并计算法线
【发布时间】:2021-12-27 17:45:01
【问题描述】:

我尝试了解 3d 的工作原理,并创建了 3d 形状,例如立方体

我填写mesh.data.VertexBuffer.Verticesmesh.data.IndexBuffer。 在屏幕上看起来一切正常,但不是阴影。

我不明白如何为顶点提供法线?我可以考虑 triangles 的法线,但我无法想象单个顶点。一个verticle可以被多个三角形共享,是还是不是?例如。对于立方体,一个角的顶点可以被 3 面墙共享。

也许我的理解是错误的。

问题是:

  1. 我应该像现在一样只为立方体获得 8 分吗?并在 indexbuffer 中使用它们。
  2. 或者我应该为每个三角形设置单独的点,即使它们与其他三角形点具有相同的坐标,以便能够计算法线?例如。对于我应该拥有的立方体:
    6 walls * 4 points = 24 points 而不是我目前的 8 个?

更新

unit UnitMain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Viewport3D, System.Math.Vectors, FMX.Types3D,
  FMX.Controls3D, FMX.Objects3D, FMX.MaterialSources;

type
  TFormCube = class(TForm)
    Viewport3D1: TViewport3D;
    Camera1: TCamera;
    Light1: TLight;
    Mesh1: TMesh;
    LightMaterialSource1: TLightMaterialSource;
    LightMaterialSource2: TLightMaterialSource;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormCube: TFormCube;

implementation

{$R *.fmx}

procedure TFormCube.FormCreate(Sender: TObject);
Var idx: Integer;
begin
  Mesh1.Data.VertexBuffer.Length:= 8;

  Mesh1.Data.VertexBuffer.Vertices[0]:= Point3d(1, 1, 1);
  Mesh1.Data.VertexBuffer.Vertices[1]:= Point3d(1, -1, 1);
  Mesh1.Data.VertexBuffer.Vertices[2]:= Point3d(-1, -1, 1);
  Mesh1.Data.VertexBuffer.Vertices[3]:= Point3d(-1, 1, 1);

  Mesh1.Data.VertexBuffer.Vertices[4]:= Point3d(1, 1, -1);
  Mesh1.Data.VertexBuffer.Vertices[5]:= Point3d(1, -1, -1);
  Mesh1.Data.VertexBuffer.Vertices[6]:= Point3d(-1, -1, -1);
  Mesh1.Data.VertexBuffer.Vertices[7]:= Point3d(-1, 1, -1);

  Mesh1.Data.IndexBuffer.Length:= 8*2*3;


  //front
  idx:= 0;
  Mesh1.Data.IndexBuffer[idx + 0]:= 0;
  Mesh1.Data.IndexBuffer[idx + 1]:= 3;
  Mesh1.Data.IndexBuffer[idx + 2]:= 2;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 0;
  Mesh1.Data.IndexBuffer[idx + 1]:= 2;
  Mesh1.Data.IndexBuffer[idx + 2]:= 1;

  //right
  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 4;
  Mesh1.Data.IndexBuffer[idx + 1]:= 0;
  Mesh1.Data.IndexBuffer[idx + 2]:= 1;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 4;
  Mesh1.Data.IndexBuffer[idx + 1]:= 1;
  Mesh1.Data.IndexBuffer[idx + 2]:= 5;


  //back
  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 7;
  Mesh1.Data.IndexBuffer[idx + 1]:= 4;
  Mesh1.Data.IndexBuffer[idx + 2]:= 5;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 7;
  Mesh1.Data.IndexBuffer[idx + 1]:= 5;
  Mesh1.Data.IndexBuffer[idx + 2]:= 6;

  //left
  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 3;
  Mesh1.Data.IndexBuffer[idx + 1]:= 7;
  Mesh1.Data.IndexBuffer[idx + 2]:= 6;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 3;
  Mesh1.Data.IndexBuffer[idx + 1]:= 6;
  Mesh1.Data.IndexBuffer[idx + 2]:= 2;

  //top
  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 4;
  Mesh1.Data.IndexBuffer[idx + 1]:= 7;
  Mesh1.Data.IndexBuffer[idx + 2]:= 3;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 4;
  Mesh1.Data.IndexBuffer[idx + 1]:= 3;
  Mesh1.Data.IndexBuffer[idx + 2]:= 0;

  //bottom
  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 1;
  Mesh1.Data.IndexBuffer[idx + 1]:= 2;
  Mesh1.Data.IndexBuffer[idx + 2]:= 6;

  inc(idx, 3);
  Mesh1.Data.IndexBuffer[idx + 0]:= 1;
  Mesh1.Data.IndexBuffer[idx + 1]:= 6;
  Mesh1.Data.IndexBuffer[idx + 2]:= 5;
end;

end.

和 dfm

object FormCube: TFormCube
  Left = 0
  Top = 0
  Caption = 'Cube'
  ClientHeight = 823
  ClientWidth = 1166
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnCreate = FormCreate
  DesignerMasterStyle = 0
  object Viewport3D1: TViewport3D
    Align = Client
    Camera = Camera1
    Color = claBlack
    Size.Width = 1166.000000000000000000
    Size.Height = 823.000000000000000000
    Size.PlatformDefault = False
    UsingDesignCamera = False
    object Camera1: TCamera
      AngleOfView = 45.000000000000000000
      Position.X = -2.000000000000000000
      Position.Y = -2.000000000000000000
      Position.Z = -10.000000000000000000
      Width = 1.000000000000000000
      Height = 1.000000000000000000
      Depth = 1.000000000000000000
    end
    object Light1: TLight
      Color = claWhite
      LightType = Directional
      SpotCutOff = 180.000000000000000000
      Position.X = -9.222618103027344000
      Position.Y = 2.758471012115479000
      RotationAngle.Y = 21.211906433105470000
      Width = 1.000000000000000000
      Height = 1.000000000000000000
      Depth = 1.000000000000000000
      Quanternion = '(0,-0.184053480625153,0,-0.982916116714478)'
    end
    object Mesh1: TMesh
      Width = 1.000000000000000000
      Height = 1.000000000000000000
      Depth = 1.000000000000000000
      TwoSide = True
      MaterialSource = LightMaterialSource2
    end
    object LightMaterialSource1: TLightMaterialSource
      Diffuse = claRed
      Ambient = claBlue
      Emissive = claGreen
      Specular = claWhite
      Shininess = 30
      Left = 280
      Top = 168
    end
  end
  object LightMaterialSource2: TLightMaterialSource
    Diffuse = claWhite
    Ambient = xFF202020
    Emissive = claNull
    Specular = xFF606060
    Shininess = 30
    Left = 248
    Top = 256
  end
end

【问题讨论】:

  • 您是否在场景中添加了光源?在没有光源的情况下,对象的所有面都显示出来,根本没有任何阴影。只有当您添加至少一个光源时,才会计算正确的阴影。
  • 我在现场有灯光并且它正在工作,但没有适当的法线(如果我有 8 个点,我不知道如何计算)。当我旋转立方体时,一切都没有被正确地“遮蔽”。我必须知道如何对基本立方体执行此操作,因为我有更多图形,例如管道、圆环 ....
  • 请提供minimal reproducible example(包括 .pas 和 .fmx 文件)

标签: delphi 3d firemonkey


【解决方案1】:

看起来第二个选项是真的。
我原以为这是资源浪费,因为需要更多积分。
而不是从第一个角度描述 qube 优点的 8
我需要 24 分 (6 walls * 4 points = 24 points)。
在这个计算之后,通过 corssproduct 计算法线很简单。

现在结果看起来不错,对于更复杂的形状也是如此。

Blender 2.93 确认的结论,它为立方体导出了 24 个点。

<float_array id="Cube-mesh-positions-array" count="24">1 1 1 1 1 -1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1</float_array>

【讨论】:

  • 这似乎不对。 3D 库性能受到内存使用和带宽的显着影响。面共享的顶点的重复肯定是没有必要的,只会导致性能不佳。我无法相信你会需要这样做。
  • 没有一行代码(或“qode”?)标签“delphi”和“firemonkey”几乎没有帮助。请为任一部分添加摘录。
  • @DavidHeffernan 我现在已经检查了 Embarcadero 本身是如何在源代码中为立方体完成的,我看到他们也使用 24 点而不是只有 8 点。但如果你知道如何做到这一点好的,请提供答案,我真的很感兴趣,因为我是 3d 的初学者。
  • @AmigoJack 你需要什么代码?我不知道如何只写 8 点的法线,然后没有代码。 mesh.data.VertexBuffer.Verticesmesh.data.IndexBuffer 和 delphi 也参考了 firemonkey。
  • 如果您需要帮助,请发送minimal reproducible example 以显示您面临的问题。我们不会坐下来花时间尝试重现您的问题。您有责任让我们尽快解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多