Matrix 4x4 对象的结构或类 [英] Struct or class for Matrix 4x4 object

查看:66
本文介绍了Matrix 4x4 对象的结构或类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现简单的软件 3D 引擎.所以我需要一个矩阵 4x4 来表示转换.我的矩阵的每个单元格类型都是 System.Double 格式,这意味着整个矩阵将使用 8 个字节 * 16 个单元格 = 128 个字节.目前我已经将它作为一个类来实现.这个矩阵也是一个不可变的类型.
所以现在,当我尝试将向量乘以这个矩阵时,我正在做这样的事情:matrix.m11 * vector.X(等等......).我认为,要访问字段 m11,程序首先需要获取 'matrix' 参考值,然后检查它是否为空,然后找到 m11 值,是吗?如果我将 class 更改为 struct,我的乘法会快很多吗?我知道 128 字节的结构很大,但是如果我编写仅使用 ref/out keyowrds 的方法?这会是一个不错的选择吗?
正如我在 SharpDX 库中看到的,矩阵是一个结构.我应该将 class 更改为 struct 然后提高性能吗?

I'm trying to implement simple software 3D engine. So I need a matrix 4x4 to represents transformations. Each cell type of my matrix is in the System.Double format which means entire matrix will use 8 bytes * 16 cells = 128 bytes. Currently I have implemented this as a class. Also this matrix is an immutable type.
So now, when I trying to multiply vector by this matrix, I'm doing something like this: matrix.m11 * vector.X (etc...). As I think, to access field m11, program first need to get 'matrix' reference value, then check it for null, then find m11 value, yes? If I would change class to struct, my multiplication coukd be alot faster? I know 128 bytes struct is big, but if I write method that works only using ref/out keyowrds? It will be good chooose?
As I see in SharpDX library, matrix is a struct. Should I change class to struct then to improve performance?

推荐答案

出于以下原因,我不建议使用 class 来存储 3D 引擎的 double4x4 矩阵:

I would not recommend to use class for storing a double4x4 matrix for a 3D engine for the following reasons:

  • 对GC的不良影响:与可以存储在堆栈上或堆上的对象内部的值类型不同,对象实例总是在堆上分配,这会给GC带来不必要的压力.例如,如果您需要将 World、View 和 Projection 矩阵存储到一个对象中,您将有 3 个矩阵(原始数据 + 对象实例的成本 ~ 8-12 字节)+ 3 个引用:它将在对象上创建更多的对象GC 必须扫描的堆.使用对象实例有效地执行此操作需要缓存您的矩阵以重用它们,而不是我们在仅在矩阵上存储中间计算时使用的那种模式......
  • 错误的数据局部性:值类型的一个重要特征是数据局部性,它不能由对象实例来保证.如果将 3 个值类型存储到一个对象实例中,它们将在内存中并置,从而更好地使用缓存.使用对象作为矩阵不能保证这一点,并且很可能会导致 CPU缓存抖动
  • 糟糕的互操作:3D 引擎通常会将其所有计算发送到最有可能连接到 GPU 的底层 3D 图形层(除非您自己光栅化所有内容,老派).您经常需要向 GPU 发送一个 float4x4 数组:使用对象实例需要一个循环和一个到中间 float4x4 结构格式的副本,以便复制数据,这违背了将 float4x4 作为类的全部目的.对于值类型,它只是 C# 中的一个 fixed 指令.它也适用于与其他库的互操作(物理引擎需要一个 float4x4 结构,而不是一个对象实例)
  • 坏双:双在 3D 游戏引擎中几乎不使用,因为它们占用更多空间,因此占用更多 CPU 缓存空间.此外,处理 GPU 意味着您主要使用浮点数.它也对 CPU SSE 指令不友好,这些指令针对在单条指令中执行 4 个浮点操作进行了很好的优化,但在单条指令中只有 2 个双选项.所以使用double来存储矩阵并不是一个好主意,除非你有一个非常的理由(例如,你想在加强透视渲染的精度")
  • 不可变性:避免使用矩阵的不变性.除非您要在多个线程中大量浮动所有计算,并且您想确保不会搞砸事情.这种结构的不变性完全是矫枉过正.想象一下将转换应用于矩阵的非常简单的场景,带有 可变struct,你只需要更新一行.对于不可变结构,您需要在复制初始值的同时创建一个新的完整矩阵.
  • Bad impact on GC: Unlike value types that can be store on the stack or inside an object on the heap, object instances are always allocated on the heap and It will put unnecessary pressure on the GC. For example, if you need to store a World, View and Projection matrix into an object, you will have 3 matrices (raw datas + cost of object instance ~ 8-12 bytes) + 3 references: It will create much more objects on the heap that the GC will have to scan. Doing this efficiently with object instances would require to cache your matrices in order to reuse them, not really the kind of pattern we are using when just storing intermediate calculations on matrices...
  • Bad data locality: One important feature of value types is data locality, which is not guaranteed by object instances. If you store 3 value types into an object instance, they will be collocated in memory, resulting in much better cache usage. Using object as a matrix cannot guarantee this and will most likely results in CPU cache thrashing
  • Bad interop: A 3D engine is usually sending all its calculations to an underlying 3D graphics layer that is most likely connected to a GPU (unless you are rasterizing everything yourself, a la old school). You often need to send an array of float4x4 to the GPU: using an object instance would require a loop and a copy to an intermediate float4x4 struct format in order to copy the data, defeating the whole purpose of having float4x4 as class. With value types, it is just a single fixed instruction in C#. It also applies to interop to other libraries (a physic engine will expect a float4x4 struct and never an object instance)
  • Bad double: Double are barely used in a 3D game engine, as they take more space and hence eat more space in CPU cache. Also, dealing with GPU means that you are mainly working with floats. It is also not friendly with CPU SSE instructions that are well optimized for performing 4 floats ops in a single instruction, but only 2 double opts in a single instruction. So it is not a good idea to use double for storing a matrix, unless you have a very good reason (for example, you want to improve the calculation of matrix when "Tightening the Precision of Perspective Rendering")
  • Bad immutability: Avoid using the premise of immutability for matrices. Unless you are going to be massively floating around all your calculations in multiple threads and you want to be sure that you will not mess up things. Immutability for such structs is a complete overkill. Imagine the very simple scenario of applying a translation to a matrix, with a mutable struct, you just need to update a row. With an immutable struct, you need to create a new whole matrix while copying the initial values.

顺便说一句,如果您关心性能:

On a side note, if you care about performance:

  • 如果需要在类中存储值类型矩阵,最好将它们存储在公共字段而不是公共属性中,因为这样可以避免访问矩阵时不必要的副本.您还可以直接固定矩阵以将其移动到非托管内存
  • 相关,更喜欢通过 ref 传递矩阵,而不是通过复制所有矩阵计算.
  • if you need to store valuetype matrix in a class, prefer to store them in a public field instead of a public property as It will avoid unnecessary copies when accessing the matrix. You will be also able to directly pin the matrix to move it to an unmanaged memory
  • Related, prefer passing matrices by ref instead of by copy on all your matrix calculations.

这篇关于Matrix 4x4 对象的结构或类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆