自制React-three-fiber
🐜Threejs101
代码1 设置了舞台,创建了三个基本组件:renderer, scene, camera
代码2 往场景中增加物体,将根节点加到dom里
代码3 定义renderLoop
通过上面的代码,可以创建出一个几何体
👼拥抱React
Canvas组件
为了在React中使用Threejs,可以创建一个Canvas组件,代码如下:
组件中只封装了canvas,在hook中定义了设置舞台的代码,定义了renderLoop,并且开启了render loop,现在要在页面中显示出物体,只差一步:创建物体,往场景中添加。
如何往场景(scene)里添加物体
选项1: Javascript方式
直接就在hook里创建几何体,创建材质,再创建mesh,然后直接加到scene里
这样子的话,其实React只是一层皮,实际的Threejs完全就是当作普通JS代码在写
选项2: React jsx
这里需要知道的一个点是scene作为整个场景的根节点,其他所有的mesh都是往这里加,而每个mesh也可以有自己的child,整个场景是一个树状。我们要做的就是往树的根节点加节点,使用JS的方式就是我们显示创建,自己给加进去。而React创建dom树是通过声明式构建出的,所以也可以通过jsx声明式的方式创建mesh,让react帮我们构建场景树。
我们期望可以用下面方式创建场景
在Canvas组件内部通过jsx定义mesh,构建mesh的geometry,material通过props指定,然后React会自动给我创建mesh加到scene里。
自定义Renderer
React是如何创建dom的
React是由ReactDOM负责根据虚拟dom创建dom,并且加到根节点的,所以我们也需要一个类似的render函数
这个render函数类似ReactDOM的render函数,接收虚拟dom和场景根节点,然后帮我们创建mesh,加到scene里。
仿照ReactDOM写个render函数
创建一个renderer,render函数中通过renderer调用updateContainer去更新,我们需要实现传入Renconciler的参数。
填充Reconciler参数
拷贝十几个函数,我们关心的只有几个:createInstance,appendChild, appendChildToContainer, appendInitialChild,finalizeInitialChildren,因为只需实现这几个就可以完成渲染,而我只想明白为什么可以通过React渲染3D物体,不关心更新卸载等问题,所以其他函数不实现了。
createInstance函数:根据虚拟dom创建实例的方法,通过它可以创建自定义的标签节点,这里就是从Threejs里找到标签对应的类生成并返回。
finalizeInitialChildren:可以在这里做属性赋值的工作,也可以在createInstance直接就完成。
appendChild:将子节点加到父节点中,构建树状的方法
appendInitialChild:和上面那个一样,将子节点加到父节点(暂不清楚为什么要分两个方法)
appendChildToContainer:加到根节点中的方法
效果:
https://codesandbox.io/s/elastic-wood-ux0mkj?file=/src/App.js
免责声明
本篇文章完全是个人出于好奇,想了解为什么React-three-fiber可以用React语法写threejs应用,因此着重点在实现渲染的基本思路,对于更新卸载等都未关注。另外,使用到的react-reconciler也是老版本,对其api也未深入探索。