界面优化
在上一章最后,我们虽然做了优化,但是还是有点模糊,如下
我们继续优化
在上一节我们做了如下的设置,使效果好了一些,但是这个是有性能消耗的,官网默认是false,说明关键不是这个,也大概推断一下,默认方法应该是权衡之后的默认值,所以我们应该查看下面的方法(人家也不可能那么傻对吧)
查看方法的原因就是因为我们有些内容没有设置对,我们查阅官网,查看会导致模糊的原因
可以看到设备像素比影响像素(清晰度),有两个需要我们设置,我们来设置一下
// useMyContextProvider.ts
import { shallowRef, watchEffect } from "vue";
watchEffect(() => {
const sizes = useElementSize(computed(() => toValue(canvas).parentElement));
renderer.value.setSize(sizes.width.value, sizes.height.value);
});
const { pixelRatio } = useDevicePixelRatio();
watchEffect(() => {
renderer.value.setPixelRatio(pixelRatio.value);
});
然后我们看一下效果,是不是好了
OrbitControls
现在界面还是不能控制物体旋转的,我们来继续封装
当我们传入一个OrbitControls标签的时候,就代表我们有了这个能力,我们来继续开发
在开始之前我们先看一下正常这个东西需要我们怎么做,如下
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls( camera, renderer.domElement );
循环里的update我们先不管,因为我们不需要更改相机等操作
开发
前面我们封装的都是直接传入标签,然后解析完成我们的设置,今天这个我们放到一个单独组件里进行
// App.vue
<script setup lang="ts">
import MyCanvas from "./components/MyCanvas.vue";
import OrbitControls from "./components/OrbitControls.vue";
</script>
<template>
<MyCanvas>
<OrbitControls />
<MyMesh>
<MyConeGeometry />
<MyMeshToonMaterial />
</MyMesh>
</MyCanvas>
</template>
<style scoped></style>
// ./components/OrbitControls.vue
<script setup lang="ts">
</script>
<template>
<MyOrbitControls />
</template>
<style scoped></style>
通过上面我们知道我们需要在实例化的时候,传入相机和画布,然后是实例化的过程在nodeOps中,我们来修改一下,先判断props和参数和tag类型,然后传入相应参数进行实例化
const nodeOps: RendererOptions<MyObject, MyObject> = {
createElement(tag, _isSVG, _anchor, props) {
if (!props) {
props = {};
}
if (!props.args) {
props.args = [];
}
if (tag === "template") {
return null;
}
if (isHTMLTag(tag)) {
return null;
}
let instance;
let name = tag.replace("My", "");
const target = catalogue.value[name];
// 实例化 - OrbitControls
instance = new target(...props.args);
if (props?.attach === undefined) {
if (instance.isMaterial) {
instance.attach = "material";
} else if (instance.isBufferGeometry) {
instance.attach = "geometry";
}
}
return instance;
}
}
参数我们在组件中传入一下
<MyOrbitControls :args="[camera, canvas]" />
这个参数是应该怎么获取呢?props?inject?pinia?我们这是组件,如果以后想分开呢,做成真正的npm包呢?这样应该很容易的知道要使用 inject 了吧
在创建组件的时候我们提供上下文
// src/components/MyCanvas.vue
const createInternalComponent = (context) =>
defineComponent({
setup() {
provide("context", context);
return () => h(Fragment, null, slots?.default ? slots.default() : []);
},
});
const mountCustomRenderer = (context) => {
const InternalComponent = createInternalComponent(context);
render(h(InternalComponent), scene.value);
};
这个时候在在src/components/OrbitControls.vue下面inject没有camera,这是因为我们提供的时候,还没有这个,我们把创建时机移后一些,如下
然后我们在OrbitControls.vue接收一下并传入参数
<script setup lang="ts">
import { inject, unref } from "vue";
const { camera, canvas } = inject("context");
</script>
<template>
<MyOrbitControls :args="[camera, canvas]" />
</template>
<style scoped></style>
最后效果如下