Ray为什么这么消耗性能

最近在研究cc物理方面底层代码,一直想弄明白为什么Ray这么消耗性能,都在说减少检测次数,分帧检测,降低检测三角面数等等优化方案,从中我们能猜测应该是Ray检测for三角面次数过多导致,但是是哪一个fun导致的或者说哪个fun中的哪块代码块导致的呢,你知道吗?我想大多数人都是不知道,我也不是太清除,所以我想开这个帖子把我的见解和疑问都说出来,还望大佬不吝赐教
首先我使用了Performance测试出了Ray中消耗性能的关键处,这是Call Tree


可以看到M函数占3.4,intersetTrimesh函数占10-5.3=4.7
找到M函数,这里有3次sub和5次dot ,看来3.4的性能消耗是sub和dot,我把sub和dot单独拎出来用console.time测试了一下消耗,结果发现了一个惊人的问题,先来看下测试:
我就假设与射线相交的subMesh三角面有2500个,代码如下:

5次dot2500,一共运行这么多次,时间消耗为image
我们知道dot是三个分量相乘再相加,就是一共三次
两次+,我把这个换成相对应的*+运算

image
居然相差3倍!我同事说是这两个运算虽然是一样的但是一个是vec3引用类型一个是值类型运算,但是相差的这么多还是觉得有问题啊!然后我又测试了一下sub和add函数

image

image
602d87a3525e45bf1d836ddb4dc10e2

image
Vec3的加减乘除代码我就不贴了,就是基本值类型运算的组合,这倍数相差这么大,还望大佬能告知一下原因。是我的凭空捏造还是确实这样呢!?
然后intersetTrimesh代码在这里,代码比较多,我暂时还没能定位到具体的哪个fun,有大佬知道的还望告知,不胜感激!
这是处理过的代码2dad8bafaa4c6e2c24d3a52abaacd46
这是源代码:

红色圈出来的就是M函数

1赞

@panda 为什么Vec3运算和基本运算差这么多

console.time贼鸡不准

那用什么评测代码块消耗呢

const t = Date.now();
// ....
console.log(Date.now()-t);

我感觉这样比console.time稳,console.time输出的耗时有时候很诡异,明显不正常(环境是win10+chrome)

好的,我用这个再来测试下

你可以试试定义数值,和使用对象里的数值进行运算对比;封装成函数调用和直接调用对比;

封装成函数确实是增加了耗时


image 但是还是差一倍哦,我是用sub来测试的

上面的vec3.sub是3点多ms

我这里没有封装成对象,只是封装了函数,难道是对象封装运算和直接运算也会差1ms多吗

我按照你测测试了下,没啥差别哈 :joy:

c#为例

class Program
{

    static int mul(int a, int b)
    {
        return a * b;
    }

    static void Main(string[] args)
    {
        int a = 10, b = 20;
        a = a * b;
        a = mul(a, b);
    }
}

生成的IL


.class private auto ansi beforefieldinit Program
    extends [System.Runtime]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [System.Runtime]System.Object::.ctor()
        L_0006: nop 
        L_0007: ret 
    }

    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] int32 num,
            [1] int32 num2)
        L_0000: nop 
        L_0001: ldc.i4.s 10
        L_0003: stloc.0 
        L_0004: ldc.i4.s 20
        L_0006: stloc.1 



        L_0007: ldloc.0 
        L_0008: ldloc.1 
        L_0009: mul 
        L_000a: stloc.0 



        L_000b: ldloc.0 
        L_000c: ldloc.1 
        L_000d: call int32 Program::mul(int32, int32)
        L_0012: stloc.0 
        L_0013: ret 
    }

    .method private hidebysig static int32 mul(int32 a, int32 b) cil managed
    {
        .maxstack 2
        .locals init (
            [0] int32 num)
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: ldarg.1 
        L_0003: mul 
        L_0004: stloc.0 
        L_0005: br.s L_0007
        L_0007: ldloc.0 
        L_0008: ret 
    }

}

你对比两个生成的指令集数就可以看出来了吧

你用面向对象不可能写出来比汇编运行更快的吧,用面向对象不就是为了提升开发效率,好维护么,你对这没啥意思啊

受教了!!