在3d-force-graph中(vue3),使用SpriteText报错Uncaught TypeError: ‘get‘ on proxy: property ‘modelViewMatrix‘
起初完全是按照官方示例中的代码进行编写的

在Graph后面进行链式操作,功能看上去没问题,但鼠标在视图中一滑动就连续报错ଲଇଉକ:
Uncaught TypeError: 'get' on proxy: property 'modelViewMatrix' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value
// 创建图实例 传入 DOM 元素
const Graph = ForceGraph3D()(container);
// 配置图数据和节点
Graph.graphData(this.graphData)
.nodeAutoColorBy("name")
.linkWidth(2)
.linkDirectionalArrowLength(4)
.linkDirectionalArrowRelPos(1)
.nodeThreeObject((node) => {
const sprite = new SpriteText(node.id);
sprite.material.depthWrite = false; // make sprite background transparent
sprite.color = node.color;
sprite.textHeight = 10;
sprite.center.y = -0.6; // shift above node
return sprite;
})
.nodeThreeObjectExtend(true)
网上也有很多人在问这个问题,也有很多大佬解答ฅ ˘ฅ
原因是vue proxy导致的,vue的响应式系统基于proxy,这东西跟three.js的对象不兼容,threejs很多对象内有大量不可配置(non-configurable)、只读的属性(就比如modelViewMatrix),而vue在将对象放入data()或者通过响应式系统处理时,会尝试用proxy包裹这些对象——这就导致了冲突
很多大佬说把声明实例化的threejs对象放在全局即可解决,但是这里,注意!这里我没有将其挂载到vue里,我是局部变量・ࡇ・
但是问题的主要原因是一样的ଲଇଉକ ,只不过Vue的响应式系统与 Three.js 对象在nodeThreeObject回调中被间接“污染”了
但是我这里压根儿没用全局变量,这我他喵的怎么解决啊⚆_⚆?
但的确有解决办法 (具体说明在下面,没空儿直接cv,有空就去看看了解一下) :
解决办法
使用vue的 markRaw 包裹我上述代码中return出的对象sprite(vue2应该不会出现这个问题,我只在vue3遇到了这个问题,所以用了vue3的markRaw)
import {markRaw} from "vue";
//要改的就最后一行,return那个地方!!
//用markRaw包裹即可
Graph.graphData(this.graphData)
.nodeAutoColorBy("name")
.linkWidth(2)
.linkDirectionalArrowLength(4)
.linkDirectionalArrowRelPos(1)
.nodeThreeObject((node) => {
const sprite = new SpriteText(node.id);
sprite.material.depthWrite = false; // make sprite background transparent
sprite.color = node.color;
sprite.textHeight = 10;
sprite.center.y = -0.6; // shift above node
return markRaw(sprite); //这里!!!!!!
})
问题解决:

说明:
再看看报错:
'get' on proxy: property 'modelViewMatrix' is a read-only and non-configurable data property...
这说明:某个 Three.js 对象(如 SpriteText 实例)被 Vue 的响应式系统( reactive() / ref() )包裹了。
虽然你没有显式把它放进data() , 但 Vue 在某些情况下会自动追踪闭包中的对象引用(尤其是在 devtools 启用、或组件实例持有引用时)。
而3d-force-graph内部会把nodeThreeObject返回的对象加入到 Three.js 的场景树(scene graph)中,这些对象含有大量只读属性(如matrixWorld, modelViewMatrx),一旦被 Proxy 包裹就会崩溃。
就算你是在函数内部创建的 SpriteText ,但是如果它被 Vue 的响应式上下文“看到”,可能还会出问题。。。
(但我觉得一定会出问题 ( ̄▽ ̄)"),在这种情况下,markRaw应该是唯一最可靠的方法了
最保险的方式是: 明确告诉vue "这个对象不要响应式化" !!!
补充
- markRaw 不会影响Three.js的正常渲染,它只是告诉vue:"别管这个对象"
- 这个问题一般出现在 vue3 + 开发模式 + 某些第三方库 中出现,生产构建( vite build / vue-cli-service build ) 有时会因 tree-shaking 或无 devtools 而不报错,但开发时必须修复 ( ̄_ ̄|||)
- three-spriteText 本身没啥问题,问题是在于它返回的是 THREE.Sprite 子类,而 THREE.Object3D 族系与 vue3 proxy 天然冲突
- vue2应该不会出现这个问题,我只在vue3遇到了这个问题,所以用了vue3的markRaw
最后就祝大家新年快乐吧ヾ(≧▽≦*)o
更多推荐


所有评论(0)