I am using Web Technology to practice Ray Tracing Relevant knowledge , A lot of problems .
After overcoming those problems , I find , It goes with React Optimization techniques are the same （ there React Optimization techniques , It's not about optimizing React Realized Web APP The technique of , It is React Optimization techniques included in the internal implementation ）.
Is not so much React Optimization skills in Web Applications in ray tracing . It's better to say ,UI Rendering optimization techniques , stay React ,Ray Tracing Or else? UI platform , It's universal .
It's just that there's an order of hearing , I personally have React background , Go to study again Ray Tracing, So the title . If I go the other way , It is 《Ray Tracing Optimization skills in React Applications in 》 了 .
Next , Let's list the problems and solutions one by one .
problem ：Operator Overloading
stay C++ in ,color The function is written like this .
Numbers multiply vectors , Only need to use * No . However, in JS You have to write like this ：
stay JS in ,+-/* Cannot be used in Float32Array And so on . We have to abstract it into add, sub, mul, div And so on . It's dull to write , Debugging is also very painful .
that , How to overcome this problem ？
Solution ：Babel Plugin
So far, we can search several Babel Plugin Can let JS Operator overloading is supported , But they all have their own problems .
such as ：babel-plugin-overload, Its idea is to refer to Python, stay JS In the use Symbol.for('+') Express overloading.
Its principle is , Put all the +-/* The code is compiled like this ：
Four Operational expressions , It becomes an anonymous function expression . Check left Whether to include overloaded properties .
It's a low degree of completion . Can't handle number * vector such left When the value is a number , There are also very serious performance issues , Each execution creates an anonymous function . It's basically not available .
The other is ,operator-overloading-js, Older , even Symbol All useless , It uses __plus This kind of agreed practice .
The idea is , Parse function at run time AST, Then compile and generate the new function and execute it .
Using it means that we rely on esprima,escodegen, Used to parse code and generate code respectively . This part is not small .
also , Because it generates new functions , Our function can't access the variables in the closure at will . This is basically goodbye ES2016 Module writing , Because of the top import Statement to introduce variables , For functions within a module , It's the variable in the closure . In its example , Module writing is commonjs Of .
As shown in the figure above ,overload Functions wrap almost all the code . Its runtime overhead , It increases with the size of the code . On the whole, the gains outweigh the losses .
After examining a number of options , I didn't succeed in finding a solution that could be used directly . therefore , I wrote one myself babel plugin, Finding it can be very simple .
In my scene , Just a few dozen lines of code , As shown below ：
What it does is very simple , Is to put +-*/ The expression of , according to mapping Relationship , Replace with add, sub, mul and div Four function calls . hold left, right The operation value of , Pass in as a parameter .
such , We only need to achieve four runtime-helper function , You can customize +-*/ Behavior .
For example, we do it for 3 The behavior of adding a vector of two dimensions , First of all, it's a vector , It's not a vector, it's direct return left + right, Take the branch of default behavior . If it is , Then normalize to two vectors , And then use gl-matrix The method provided in .
sub, mul and div The code is almost the same , It's just calling different vec3 It's just the method .
There's only... Shown here vector Part of , There is no reference to matrix, Because I just can't use it in my current scene matrix. If necessary , It's easy to add , One more branch of judgment . We can also make plug-in registration mechanism .
overloading According to the registered plug-ins , Construct the corresponding runtime-helper, The matching plug-ins are detected in turn , Call its processing function .
Use effect , We can write intuitive code , There is no need to worry about the types of operations and left, right The order ：
Babel The plug-in compiles it into ：
Compared to our original code ：
Just look at return sentence , We will find that , The result of its compilation is , It's the same as when we started , It's consistent on the whole . This is exactly what we want , We got the same results as we did by hand , But what we're actually writing is more straightforward code .
problem ：Blocking The Main UI Thread
Use Web Technology to learn and implement ray tracing or 3D Graphic rendering , The most attractive advantage is , We can easily deploy and browse effects in browsers .
However , Highly computational algorithms like ray tracing , It takes a long time to calculate , To get the result . If you use synchronous Computing , It will jam the main thread , The page doesn't interact , It's even hard to shut down .
The picture above is rendered 500+ Here comes the ball 800 * 400 In the resolution of , Use node.js v8.9.4, It's close to 2 Hours . Even smaller balls , Only 20 To a , It will take more than ten minutes .
such , Even if we solve JS No, operator overloading The problem of , To no avail . No one wants to see a ray tracing that will jam your browser DEMO.
We have to find a way to solve this problem .
How to solve the problem , Please look at the next breakdown . I'll talk about Time Slicing and Streaming Rendering Optimization strategy .