我刚刚在Uni完成了第二年的游戏课程,这总是让我觉得数学和游戏编程是如何相关的。到目前为止,我一直在游戏中使用Vectors
,Matrices
和Quaternions
,我可以理解这些是如何融入游戏的。
这是关于数学和实时图形编程之间关系的General Question
,我很好奇数学是多么动态。是否所有公式和衍生物都是预定义的(半定义的)?
实时计算导数/积分是否可行?
这些是我看不出它们如何适合编程/数学的一些事情作为一个例子。
MacLaurin/Talor Series
我可以看到这很有用,但是你必须传递你的函数及其衍生物,或者你可以传递一个函数并让它为你找出衍生物?
MacLaurin(sin(X)); or MacLaurin(sin(x), cos(x), -sin(x));
Derivatives /Integrals
这与第一点有关。计算在运行时动态完成的函数的y'
,或者这是静态完成的事情,也许是在set函数内部的变量。
f = derive(x); or f = derivedX;
Bilnear Patches
我们了解到这是一种可能在小块中生成景观的方法,可以“拼凑”在一起,这是游戏中发生的事情吗?我从来没有听说过(授权我的知识非常有限)与程序方法或其他方式一起使用。到目前为止我所做的工作涉及处理顶点信息的数组。
很抱歉,如果这不是主题,但这里的社区似乎就此发现了。
感谢。
答案 0 :(得分:5)
Skizz的答案在字面意思上是正确的,但只需要进行一些小改动就可以计算出C ++函数的导数。我们将skizz的函数f
修改为
template<class Float> f (Float x)
{
return x * x + Float(4.0f) * x + Float(6.0f); // f(x) = x^2 + 4x + 6
}
现在可以编写一个C ++函数来计算f相对于x的导数。这是一个完整的自包含程序来计算f的导数。它是精确的(机器精度),因为它没有使用像有限差分这样的不准确方法。我在我写的paper中解释它是如何工作的。它推广到更高的衍生品。请注意,大部分工作都是由编译器静态完成的。如果你打开优化,并且你的编译器很好地内联,那么它应该和你为简单函数手动编写的任何东西一样快。 (有时候速度更快!特别是,它可以同时分摊计算f和f'的成本,因为它使编译器更容易消除公共子表达式,而不是为f和f'编写单独的函数。)
using namespace std;
template<class Float>
Float f(Float x)
{
return x * x + Float(4.0f) * x + Float(6.0f);
}
struct D
{
D(float x0, float dx0 = 0) : x(x0), dx(dx0) { }
float x, dx;
};
D operator+(const D &a, const D &b)
{
// The rule for the sum of two functions.
return D(a.x+b.x, a.dx+b.dx);
}
D operator*(const D &a, const D &b)
{
// The usual Leibniz product rule.
return D(a.x*b.x, a.x*b.dx+a.dx*b.x);
}
// Here's the function skizz said you couldn't write.
float d(D (*f)(D), float x) {
return f(D(x, 1.0f)).dx;
}
int main()
{
cout << f(0) << endl;
// We can't just take the address of f. We need to say which instance of the
// template we need. In this case, f<D>.
cout << d(&f<D>, 0.0f) << endl;
}
按照您的预期打印结果6
和4
。尝试其他功能f
。一个很好的练习是尝试制定规则以允许减法,除法,触发函数等。
答案 1 :(得分:2)
2)衍生品和积分通常不是实时计算大数据集,而是太昂贵了。相反,他们是预先计算的。例如(在我的头顶)渲染单个散射介质Bo Sun等。使用他们的“airlight模型”,它包含许多代数快捷键,以获得预先计算的查找表。
3)流式传输大型数据集是一个很大的话题,尤其是在地形中。
你在游戏中遇到的许多数学问题都是解决非常具体的问题,而且通常很简单。线性代数的使用远远超过任何微积分。在图形学中(我最喜欢这个)很多算法来自学术界的研究,然后它们被游戏程序员修改速度:尽管学术研究甚至可以加速他们的目标。
我推荐两本书实时碰撞检测和实时渲染,其中包含游戏引擎编程中使用的大多数数学和概念的内容。
答案 2 :(得分:2)
我认为您对C ++语言本身的理解存在根本问题。 C ++中的函数与数学函数不同。因此,在C ++中,您可以定义一个函数(我现在将其称为避免混淆的方法)来实现数学函数:
float f (float x)
{
return x * x + 4.0f * x + 6.0f; // f(x) = x^2 + 4x + 6
}
在C ++中,除了获取给定x的f(x)值之外,没有办法对方法f做任何事情。数学函数f(x)可以非常容易地转换,例如f'(x),在上面的例子中是f'(x)= 2x + 4.要在C ++中执行此操作,您需要定义一个方法df(x):
float df (float x)
{
return 2.0f * x + 4.0f; // f'(x) = 2x + 4
}
你不能这样做:
get_derivative (f(x));
并让方法get_derivative
为您转换方法f(x)。
此外,你必须确保当你想要f的派生时,你调用方法df。如果你意外地调用了g的导数方法,你的结果就会出错。
然而,对于给定的x,我们可以逼近f(x)的导数:float d (float (*f) (float x), x) // pass a pointer to the method f and the value x
{
const float epsilon = a small value;
float dy = f(x+epsilon/2.0f) - f(x-epsilon/2.0f);
return epsilon / dy;
}
但这非常不稳定且非常不准确。
现在,在C ++中,您可以创建一个类来帮助:
class Function
{
public:
virtual float f (float x) = 0; // f(x)
virtual float df (float x) = 0; // f'(x)
virtual float ddf (float x) = 0; // f''(x)
// if you wanted further transformations you'd need to add methods for them
};
并创建我们特定的数学函数:
class ExampleFunction : Function
{
float f (float x) { return x * x + 4.0f * x + 6.0f; } // f(x) = x^2 + 4x + 6
float df (float x) { return 2.0f * x + 4.0f; } // f'(x) = 2x + 4
float ddf (float x) { return 2.0f; } // f''(x) = 2
};
并将此类的实例传递给系列扩展例程:
float Series (Function &f, float x)
{
return f.f (x) + f.df (x) + f.ddf (x); // series = f(x) + f'(x) + f''(x)
}
但是,我们仍然需要自己为函数的派生创建一个方法,但至少我们不会意外地调用错误的方法。
现在,正如其他人所说,游戏往往倾向于速度,所以很多数学都被简化了:插值,预先计算的表等等。
答案 3 :(得分:1)
游戏中的大部分数学设计都是为了尽可能便宜地计算,交易速度超过准确性。例如,大多数数字运算使用整数或单精度浮点数而不是双精度数。
不确定您的具体示例,但如果您可以事先为衍生物定义廉价(计算)公式,那么这比计算动物更好。
答案 4 :(得分:1)
在游戏中,表现至关重要。当静态完成时,你不会发现动态完成的任何事情,除非它导致视觉保真度显着提高。
答案 5 :(得分:0)
您可能对编译时符号差异感兴趣。这可以(原则上)使用c ++模板完成。不知道游戏是否在实践中做到了这一点(符号差异可能太昂贵,无法正确编程,在编译时这种广泛的模板使用可能过于昂贵,我不知道)。
但是,我认为您可能会发现对此主题的讨论很有趣。谷歌搜索“c ++模板符号衍生物”给出了一些文章。
答案 6 :(得分:0)
如果您对符号计算和衍生物计算感兴趣,那么有很多很好的答案。
然而,就像一个完整性检查一样,这种象征性(分析性)微积分在游戏环境中实时做是不切实际的。
根据我的经验(计算机视觉中的3D几何比游戏更多),3D几何中的大部分微积分和数学都是通过提前离线计算事物然后编码来实现这种数学来实现的。您很少需要动态地进行符号计算,然后以这种方式获得即时分析公式。
任何游戏程序员都可以验证吗?
答案 7 :(得分:0)
1),2)
MacLaurin / Taylor系列(1)在任何情况下均由衍生物(2)构成。
是的,您不太可能需要在运行时以符号方式计算任何这些内容 - 但如果您需要,{%3}}肯定会有很好的答案。
你所发现的是你需要进行数学计算,并且需要在合理的时间内完成,有时甚至是非常快。要做到这一点,即使您重新使用其他解决方案,您也需要了解基本分析。
如果您必须自己解决问题,那么好处通常只需要大致的答案。这意味着,例如,系列类型扩展可能允许您将复杂函数简化为简单的线性或二次,这将非常快。
对于积分,您通常可以用数字方式计算结果,但它总是比分析解决方案多慢。差异可能是实际与否之间的差异。
简而言之:是的,你需要学习数学,但是为了编写程序而不是让程序为你做。