当前位置:   article > 正文

Three 之 three.js (webgl)CSS2DObject 添加文字按钮等并与OrbitController / html button 等交互冲突的简单使用说明整理

css2dobject

Three 之 three.js (webgl)CSS2DObject 添加文字按钮等并与OrbitController / html button 等交互冲突的简单使用说明整理

目录

Three 之 three.js (webgl)CSS2DObject 添加文字按钮等并与OrbitController / html button 等交互冲突的简单使用说明整理

一、简单介绍

二、实现原理

在 Three js 3D 添加 CSS2D 的方法

处理 CSS2DRenderer 与 OrbitController 等轨道交互的冲突(导致失效)问题

如果 CSS2DRenderer   与 html button 等有交互冲突

三、注意事项

四、效果预览

 五、案例实现代码


一、简单介绍

Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。

本节介绍, three 开发网页 3D 场景, three.js (webgl)在 3D 场景中添加 文本按钮等的UI 方法,并且在添加中如何处理与OrbitController / html button 等交互冲突的处理,保证各自的功能正常使用,这里做简单使用说明整理,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。

CSS 2D渲染器(CSS 2D渲染器(CSS2DRenderer))

CSS2DRenderer是CSS3DRenderer(CSS 3D渲染器)的简化版本,唯一支持的变换是位移。

如果你希望将三维物体和基于HTML的标签相结合,则这一渲染器将十分有用。在这里,各个DOM元素也被包含到一个CSS2DObject实例中,并被添加到场景图中。

CSS 2D渲染器(CSS2DRenderer) 方法:

.getSize () : Object

返回一个包含有渲染器宽和高的对象。

.render ( scene : Scene, camera : Camera ) : undefined

使用camera渲染scene。

.setSize (width : Number, height : Number) : undefined

将渲染器的尺寸调整为(width, height).

CSS 3D渲染器(CSS3DRenderer)

CSS3DRenderer用于通过CSS3的transform属性, 将层级的3D变换应用到DOM元素上。 如果你希望不借助基于canvas的渲染来在你的网站上应用3D变换,那么这一渲染器十分有趣。 同时,它也可以将DOM元素与WebGL的内容相结合。

然而,这一渲染器也有一些十分重要的限制:

  • 它不可能使用three.js中的材质系统。
  • 同时也不可能使用几何体。

因此,CSS3DRenderer仅仅关注普通的DOM元素,这些元素被包含到了特殊的对象中(CSS3DObject或者CSS3DSprite),然后被加入到场景图中。

二、实现原理

在 Three js 3D 添加 CSS2D 的方法

1、创建 const xx = document.createElement('xxx'),对应设置

2、在以上基础上 const xxCSS2dObject = new CSS2DObject( xx ) ,并添加到 scene 中

3、然后记住创建 const css2DLabelRenderer = new CSS2DRenderer(),并且添加到 document.body.appendChild( this.css2DLabelRenderer.domElement )

4、在 render() 渲染函数中进行渲染 css2DLabelRenderer.render( this.scene, this.camera );

处理 CSS2DRenderer 与 OrbitController 等轨道交互的冲突(导致失效)问题

1、如果 CSS2DRenderer  没有需要交互的使用,可以直接设置 pointerEvents = 'none' (css2DLabelRenderer.domElement.style.pointerEvents = 'none';)

pointer-events:none —元素永远不会成为鼠标事件的target。但是,当其后代元素的pointer-events属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶触发父元素的事件侦听器。其他值只能应用在SVG上。

2、如果 CSS2DRenderer  有需要交互的使用,可以把 OrbitControls 控制器 用于事件监听的HTML元素替换(可以换成 CSS2DRenderer   这个)

  1. // new OrbitControls( this.camera, this.renderer.domElement );
  2. new OrbitControls( this.camera, this.css2DLabelRenderer.domElement );

如果 CSS2DRenderer   与 html button 等有交互冲突

1、可以设置该元素的 zIndex 值 大些,试试

style = "z-index: 1000" 或者 btnDiv.style.zIndex = 1000;

三、注意事项

1、CSS2DRenderer 渲染需要实时更新,必要也需要做窗口大小的变换,对应的事件处理

  1. CSS2DLabelRender() {
  2. if (this.css2DLabelRenderer != null) {
  3. this.css2DLabelRenderer.render( this.scene, this.camera );
  4. }
  5. },
  6. CSS2DLabelOnWindowSize() {
  7. if (this.css2DLabelRenderer != null) {
  8. this.css2DLabelRenderer.setSize(window.innerWidth, window.innerHeight);
  9. }

四、效果预览

 

 五、案例实现代码

效果预览基于,以下博文的基础环境实现:

Vue 之 Vue Cli 创建 Three js 工程( 网页 3D )的简单整理(一些注意事项)_仙魁XAN的博客-CSDN博客

1、关键代码(App.vue)

  1. <template>
  2. <div id="container"></div>
  3. <div id="menu" style="position: absolute;left:45%;text-align: center; z-index: 1000">
  4. <button @click="TestClick">TestClick(Click)</button>
  5. </div>
  6. </template>
  7. <script>
  8. import * as THREE from 'three';
  9. import Stats from 'three/examples/jsm/libs/stats.module.js';
  10. import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
  11. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
  12. export default {
  13. name: 'ThreeTest',
  14. components: {},
  15. data() {
  16. return {}
  17. },
  18. mounted() {
  19. this.container;
  20. this.stats;
  21. this.camera;
  22. this.scene;
  23. this.renderer;
  24. this.css2DLabelRenderer;
  25. this.init();
  26. this.animate();
  27. },
  28. methods: {
  29. init() {
  30. this.container = document.createElement('div');
  31. document.body.appendChild(this.container);
  32. this.addSceneCameraAndLight();
  33. this.addObject();
  34. this.initRenderer();
  35. this.addStatus();
  36. this.AddSceneTextCSS2DLabel();
  37. this.initOrbitController();
  38. // window.addEventListener
  39. window.addEventListener('resize', this.onWindowResize);
  40. },
  41. addSceneCameraAndLight(){
  42. this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
  43. this.camera.position.set(0,20,20);
  44. this.scene = new THREE.Scene();
  45. this.scene.background = new THREE.Color(0xf0f0f0);
  46. const light = new THREE.DirectionalLight(0xffffff, 1);
  47. this.scene.add(this.camera);
  48. this.scene.add(light);
  49. },
  50. initRenderer(){
  51. this.renderer = new THREE.WebGLRenderer();
  52. this.renderer.setPixelRatio(window.devicePixelRatio);
  53. this.renderer.setSize(window.innerWidth, window.innerHeight);
  54. this.container.appendChild(this.renderer.domElement);
  55. },
  56. addStatus(){
  57. this.stats = new Stats();
  58. this.container.appendChild(this.stats.dom);
  59. },
  60. // 添加测试物体,并设置他们的层为 0 1 2
  61. addObject(){
  62. const mesh = new THREE.Mesh(new THREE.BoxGeometry(10,10,10),
  63. new THREE.MeshLambertMaterial({color:'#f00'}))
  64. this.scene.add( mesh);
  65. },
  66. initOrbitController(){
  67. // new OrbitControls( this.camera, this.renderer.domElement );
  68. new OrbitControls( this.camera, this.css2DLabelRenderer.domElement );
  69. },
  70. onWindowResize() {
  71. this.camera.aspect = window.innerWidth / window.innerHeight;
  72. this.camera.updateProjectionMatrix();
  73. this.renderer.setSize(window.innerWidth, window.innerHeight);
  74. this.CSS2DLabelOnWindowSize();
  75. },
  76. animate() {
  77. requestAnimationFrame(this.animate);
  78. this.render();
  79. this.stats.update();
  80. },
  81. render() {
  82. this.renderer.render(this.scene, this.camera);
  83. this.CSS2DLabelRender();
  84. },
  85. AddSceneTextCSS2DLabel( ) {
  86. this.css2DLabelRenderer = new CSS2DRenderer();
  87. this.css2DLabelRenderer.setSize( window.innerWidth, window.innerHeight );
  88. this.css2DLabelRenderer.domElement.style.position = 'absolute';
  89. this.css2DLabelRenderer.domElement.style.top = '0px';//信息弹窗界面高度一半
  90. this.css2DLabelRenderer.domElement.style.left = '0px';//信息弹窗界面宽度一半
  91. //this.css2DLabelRenderer.domElement.style.pointerEvents = 'none';
  92. document.body.appendChild( this.css2DLabelRenderer.domElement );
  93. const labelDiv = document.createElement( 'div' );
  94. labelDiv.className = 'label';
  95. labelDiv.identifierName = 'label';
  96. labelDiv.textContent = 'CSS2D Label: Test ...';
  97. labelDiv.style.marginTop = '-1em';
  98. const css2dLabel = new CSS2DObject( labelDiv );
  99. css2dLabel.position.set( 3, 3, 0 );
  100. labelDiv.style.pointerEvents = 'none';//避免HTML标签遮挡三维场景的鼠标事件
  101. this.scene.add( css2dLabel );
  102. const btnDiv = document.createElement( 'button' );
  103. btnDiv.className = 'btn';
  104. btnDiv.identifierName = 'btn';
  105. btnDiv.textContent = 'Btn: Click ...';
  106. btnDiv.style.marginTop = '-1em';
  107. btnDiv.style.zIndex = 1000;
  108. const css2dBtn = new CSS2DObject( btnDiv );
  109. css2dLabel.position.set( 3, 0, 0 );
  110. this.scene.add( css2dBtn );
  111. },
  112. CSS2DLabelRender() {
  113. if (this.css2DLabelRenderer != null) {
  114. this.css2DLabelRenderer.render( this.scene, this.camera );
  115. }
  116. },
  117. CSS2DLabelOnWindowSize() {
  118. if (this.css2DLabelRenderer != null) {
  119. this.css2DLabelRenderer.setSize(window.innerWidth, window.innerHeight);
  120. }
  121. },
  122. TestClick() {
  123. console.log('Click...');
  124. }
  125. },
  126. // beforeDestroy 废弃,使用 beforeUnmount
  127. beforeUnmount() {
  128. this.container = null;
  129. this.stats = null;
  130. this.camera = null;
  131. this.scene = null;
  132. this.renderer = null;
  133. this.theta = null;
  134. this.radius = null;
  135. console.log("beforeUnmount");
  136. }
  137. }
  138. </script>
  139. <style>
  140. #app {
  141. text-align: center;
  142. height: 100%;
  143. }
  144. * {
  145. /*初始化样式*/
  146. margin: 0;
  147. padding: 0;
  148. }
  149. html {
  150. /*用于 获取 屏幕的可视宽高*/
  151. width: 100%;
  152. height: 100%;
  153. overflow: hidden;
  154. }
  155. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/121600
推荐阅读
相关标签
  

闽ICP备14008679号