使用three.js有孔的圆角框 [英] Rounded corner box having holes using three.js

查看:63
本文介绍了使用three.js有孔的圆角框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建一个在 4 个边上但在顶部和底部都有圆角的盒子.Three.js 有一个很好的例子

我对圆角正方形使用了相同的逻辑

原始形状

//圆角矩形var roundedRectShape = new THREE.Shape();(函数roundedRect(ctx,x,y,宽度,高度,半径){ctx.moveTo( x, y + 半径);ctx.lineTo( x, y + 高度 - 半径);ctx.quadraticCurveTo( x, y + 高度, x + 半径, y + 高度);ctx.lineTo( x + 宽度 - 半径, y + 高度 );ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度, y + 高度 - 半径);ctx.lineTo( x + 宽度, y + 半径);ctx.quadraticCurveTo( x + 宽度, y, x + 宽度 - 半径, y );ctx.lineTo( x + 半径, y );ctx.quadraticCurveTo( x, y, x, y + 半径);} )( roundedRectShape, 0, 0, 50, 50, 20 );

新孔形状

 var roundedRectShape_small = new THREE.Path();(函数roundedRect(ctx,x,y,宽度,高度,半径){ctx.moveTo( x, y + 半径);ctx.lineTo( x, y + 高度 - 半径);ctx.quadraticCurveTo( x, y + 高度, x + 半径, y + 高度);ctx.lineTo( x + 宽度 - 半径, y + 高度 );ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度, y + 高度 - 半径);ctx.lineTo( x + 宽度, y + 半径);ctx.quadraticCurveTo( x + 宽度, y, x + 宽度 - 半径, y );ctx.lineTo( x + 半径, y );ctx.quadraticCurveTo( x, y, x, y + 半径);} )( roundedRectShape_small, 10, 10, 30, 30, 20 );

然后我添加孔

roundedRectShape.holes.push(roundedRectShape_small);

结果不一样...

如您所见,洞在那里,但内部的 3D 效果是错误的.如何解决?

解决方案

您必须以相反的缠绕顺序绘制孔.由于外部矩形路径是顺时针绘制,因此孔路径必须逆时针绘制:

let f_rect = function roundedRect( ctx, x, y, width, height, radius ) {ctx.moveTo( x, y + 半径);ctx.lineTo( x, y + 高度 - 半径);ctx.quadraticCurveTo( x, y + 高度, x + 半径, y + 高度);ctx.lineTo( x + 宽度 - 半径, y + 高度 );ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度, y + 高度 - 半径);ctx.lineTo( x + 宽度, y + 半径);ctx.quadraticCurveTo( x + 宽度, y, x + 宽度 - 半径, y );ctx.lineTo( x + 半径, y );ctx.quadraticCurveTo( x, y, x, y + 半径);}让 f_rect_reverse = 函数 roundedRect(ctx,x,y,宽度,高度,半径){ctx.moveTo( x, y + 高度 - 半径);ctx.lineTo( x, y + 半径);ctx.quadraticCurveTo( x, y, x + 半径, y );ctx.lineTo( x + 宽度 - 半径, y );ctx.quadraticCurveTo( x + 宽度, y, x + 宽度, y + 半径);ctx.lineTo( x + 宽度, y + 高度 - 半径);ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度 - 半径, y + 高度);ctx.lineTo( x + 半径, y + 高度);ctx.quadraticCurveTo( x, y + 高度, x, y + 高度 - 半径);}var roundedRectShape = new THREE.Shape();f_rect(roundedRectShape, -25, -25, 50, 50, 20);var roundedRectShape_small = new THREE.Path();f_rect_reverse(roundedRectShape_small, -15, -15, 30, 30, 10 );roundedRectShape.holes.push( roundedRectShape_small );

查看完整示例:

(function onLoad() {var 容器、相机、场景、渲染器、控件;在里面();动画();函数初始化(){container = document.getElementById('container');渲染器 = 新的 THREE.WebGLRenderer({抗锯齿:真});renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMap.enabled = true;container.appendChild(renderer.domElement);场景 = 新的 THREE.Scene();场景背景 = 新三色(0xffffff);camera = new THREE.PerspectiveCamera(70, window.innerWidth/window.innerHeight, 1, 10000);相机位置设置(3、2、7);场景.添加(相机);window.onresize = function() {renderer.setSize(window.innerWidth, window.innerHeight);camera.aspect = window.innerWidth/window.innerHeight;相机.updateProjectionMatrix();}varambientLight = new THREE.AmbientLight(0x404040);场景.添加(环境光);var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );方向光.position.x = 4;方向光.position.y = 1;方向光.position.z = 2;场景添加(定向光);控件 = 新的 THREE.OrbitControls(camera, renderer.domElement);addGridHelper();创建模型();}函数创建模型(){让 f_rect = 函数 roundedRect(ctx,x,y,宽度,高度,半径){ctx.moveTo( x, y + 半径);ctx.lineTo( x, y + 高度 - 半径);ctx.quadraticCurveTo( x, y + 高度, x + 半径, y + 高度);ctx.lineTo( x + 宽度 - 半径, y + 高度 );ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度, y + 高度 - 半径);ctx.lineTo( x + 宽度, y + 半径);ctx.quadraticCurveTo( x + 宽度, y, x + 宽度 - 半径, y );ctx.lineTo( x + 半径, y );ctx.quadraticCurveTo( x, y, x, y + 半径);}让 f_rect_reverse = 函数 roundedRect(ctx,x,y,宽度,高度,半径){ctx.moveTo( x, y + 高度 - 半径);ctx.lineTo( x, y + 半径);ctx.quadraticCurveTo( x, y, x + 半径, y );ctx.lineTo( x + 宽度 - 半径, y );ctx.quadraticCurveTo( x + 宽度, y, x + 宽度, y + 半径);ctx.lineTo( x + 宽度, y + 高度 - 半径);ctx.quadraticCurveTo( x + 宽度, y + 高度, x + 宽度 - 半径, y + 高度);ctx.lineTo( x + 半径, y + 高度);ctx.quadraticCurveTo( x, y + 高度, x, y + 高度 - 半径);}var roundedRectShape = new THREE.Shape();f_rect(roundedRectShape, -25, -25, 50, 50, 20);var roundedRectShape_small = new THREE.Path();f_rect_reverse(roundedRectShape_small, -15, -15, 30, 30, 10 );roundedRectShape.holes.push( roundedRectShape_small );var material = new THREE.MeshLambertMaterial( { color: 0x00ff00, side: THREE.DoubleSide } );var extrudeSettings = { depth: 8, bevelEnabled: true, bevelSegments: 2, steps: 3, bevelSize: 5, bevelThickness: 5 };var geometry = new THREE.ExtrudeBufferGeometry(roundedRectShape, extrudeSettings);让 s = 0.1;var mesh = new THREE.Mesh(几何,材质);mesh.scale.set(s, s, s);场景添加(网格);}函数 addGridHelper() {var helper = new THREE.GridHelper(10, 10);helper.material.opacity = 0.25;helper.material.transparent = true;场景添加(助手);var axis = new THREE.AxesHelper(100);场景添加(轴);}函数动画(){请求动画帧(动画);使成为();}函数渲染(){renderer.render(场景,相机);}})();

<!--script src="https://threejs.org/build/three.js"></!--脚本--><script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script><script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script></script><div id="container"></div>

I need to create a box having rounded corners on 4 sides but on top and bottom. Three.js has a very good example webgl_geometry_shapes and I'm trying to replicate it to add a hole to the green rounded box. In this example to add a hole to the circle:

        // Arc circle

            var arcShape = new THREE.Shape()
                .moveTo( 50, 10 )
                .absarc( 10, 10, 40, 0, Math.PI * 2, false );

            var holePath = new THREE.Path()
                .moveTo( 20, 10 )
                .absarc( 10, 10, 10, 0, Math.PI * 2, true )

            arcShape.holes.push( holePath );

They create a shape and a path and then they add the hole. The result is

I used the same logic to the rounded square

Original shape

 // Rounded rectangle

            var roundedRectShape = new THREE.Shape();

            ( function roundedRect( ctx, x, y, width, height, radius ) {

                ctx.moveTo( x, y + radius );
                ctx.lineTo( x, y + height - radius );
                ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
                ctx.lineTo( x + width - radius, y + height );
                ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
                ctx.lineTo( x + width, y + radius );
                ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
                ctx.lineTo( x + radius, y );
                ctx.quadraticCurveTo( x, y, x, y + radius );

            } )( roundedRectShape, 0, 0, 50, 50, 20 );

new hole shape

            var roundedRectShape_small = new THREE.Path();

            ( function roundedRect( ctx, x, y, width, height, radius ) {

                ctx.moveTo( x, y + radius );
                ctx.lineTo( x, y + height - radius );
                ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
                ctx.lineTo( x + width - radius, y + height );
                ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
                ctx.lineTo( x + width, y + radius );
                ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
                ctx.lineTo( x + radius, y );
                ctx.quadraticCurveTo( x, y, x, y + radius );

            } )( roundedRectShape_small, 10, 10, 30, 30, 20 );

Then I add the hole

roundedRectShape.holes.push( roundedRectShape_small );

The result is not the same...

As you can see the hole is there but the 3D effect is wrong on internal side. How to fix it?

解决方案

You have to drew the hole in the opposite winding order. Since the outer rectangle path is draw clockwise, the hole path has to be draw counter clockwise:

let f_rect = function roundedRect( ctx, x, y, width, height, radius ) {
    ctx.moveTo( x, y + radius );
    ctx.lineTo( x, y + height - radius );
    ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
    ctx.lineTo( x + width - radius, y + height );
    ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
    ctx.lineTo( x + width, y + radius );
    ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
    ctx.lineTo( x + radius, y );
    ctx.quadraticCurveTo( x, y, x, y + radius );
}

let f_rect_reverse = function roundedRect( ctx, x, y, width, height, radius ) { 
    ctx.moveTo( x, y + height - radius );
    ctx.lineTo( x, y + radius ); 
    ctx.quadraticCurveTo( x, y, x + radius, y );
    ctx.lineTo( x + width - radius, y );
    ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
    ctx.lineTo( x + width, y + height - radius );
    ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
    ctx.lineTo( x + radius, y + height );
    ctx.quadraticCurveTo( x, y + height, x, y + height - radius );       
}

var roundedRectShape = new THREE.Shape();
f_rect( roundedRectShape, -25, -25, 50, 50, 20 );
var roundedRectShape_small = new THREE.Path();
f_rect_reverse( roundedRectShape_small, -15, -15, 30, 30, 10 );
roundedRectShape.holes.push( roundedRectShape_small );

See the complete example:

(function onLoad() {
  var container, camera, scene, renderer, controls;
  
  init();
  animate();

  function init() {
    container = document.getElementById('container');
    
    renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.set(3, 2, 7);
    scene.add(camera);
    window.onresize = function() {
      renderer.setSize(window.innerWidth, window.innerHeight);
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
    }
    
    var ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);

    var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
    directionalLight.position.x = 4;
    directionalLight.position.y = 1;
    directionalLight.position.z = 2;
    scene.add( directionalLight );
    
    controls = new THREE.OrbitControls(camera, renderer.domElement);
        
    addGridHelper();
    createModel();
  }

  function createModel() {

      let f_rect = function roundedRect( ctx, x, y, width, height, radius ) {
          ctx.moveTo( x, y + radius );
          ctx.lineTo( x, y + height - radius );
          ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
          ctx.lineTo( x + width - radius, y + height );
          ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
          ctx.lineTo( x + width, y + radius );
          ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
          ctx.lineTo( x + radius, y );
          ctx.quadraticCurveTo( x, y, x, y + radius );
      }

      let f_rect_reverse = function roundedRect( ctx, x, y, width, height, radius ) { 
          ctx.moveTo( x, y + height - radius );
          ctx.lineTo( x, y + radius ); 
          ctx.quadraticCurveTo( x, y, x + radius, y );
          ctx.lineTo( x + width - radius, y );
          ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
          ctx.lineTo( x + width, y + height - radius );
          ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
          ctx.lineTo( x + radius, y + height );
          ctx.quadraticCurveTo( x, y + height, x, y + height - radius );       
      }

      var roundedRectShape = new THREE.Shape();
      f_rect( roundedRectShape, -25, -25, 50, 50, 20 );
      var roundedRectShape_small = new THREE.Path();
      f_rect_reverse( roundedRectShape_small, -15, -15, 30, 30, 10 );
      roundedRectShape.holes.push( roundedRectShape_small );

      var material = new THREE.MeshLambertMaterial( { color: 0x00ff00, side: THREE.DoubleSide } );
      var extrudeSettings = { depth: 8, bevelEnabled: true, bevelSegments: 2, steps: 3, bevelSize: 5, bevelThickness: 5 };
      var geometry = new THREE.ExtrudeBufferGeometry( roundedRectShape, extrudeSettings );
      
      let s = 0.1;
      var mesh = new THREE.Mesh( geometry, material );
      mesh.scale.set( s, s, s );

      scene.add( mesh );
  }

  function addGridHelper() {

    var helper = new THREE.GridHelper(10, 10);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper(100);
    scene.add(axis);
  }

  function animate() {
    requestAnimationFrame(animate);
    render();
  }

  function render() {
    renderer.render(scene, camera);
  }
})();

<!--script src="https://threejs.org/build/three.js"></!--script-->
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script></script>
<div id="container"></div>

这篇关于使用three.js有孔的圆角框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆