扇形

参考:
https://threejsfundamentals.org/threejs/lessons/threejs-custom-buffergeometry.html
https://www.jianshu.com/p/5f6d0cd75443

文本代码 中的第24篇。

024-模拟ThreeJS扇形几何体

在这里插入图片描述

1、网格(Mesh)

在ThreeJS中3D物体的网格(Mesh)由几何体(Geometry)和材质(Material)组成。下面着重看一下几何体。

const geometry = new THREE.PlaneGeometry(1,1);
const material = new THREE.MeshBasicMaterial();
const mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);
2、几何体(Geometry)

几何体由三角形组成,三角形由点组成。组成三角形的点叫做顶点(vertex),法向量(normal)决定了每个顶点在光照下所呈现出的颜色。

Geometry 的要素:
(1) 顶点(Vertex)
ThreeJS中的属性 geometry.vertices查看顶点数据。
在这里插入图片描述

(2) 面(Face)
ThreeJS中的属性 geometry.faces通过数组的形式保存了一个3D物体所有的三角面信息。
在这里插入图片描述

数组每一项的内容:

  • a,b,c: geometry.vertices的顶点索引
  • normal: THREE.Vector3 : 三角面的法向量
  • vertexNormals: Array: 每个顶点的法向量
  • color: THREE.Color: 指定面的颜色
  • vertexColors:Array 指定每个顶点的颜色
    注意
    一个三角面只会有一个法向量。一个顶点会属于不同的三角面,因此一个顶点会有多个法向量。
    在这里插入图片描述

(3) 顶点索引(index)
geometry.index查看.
在这里插入图片描述

3、WebGL绘制方式

参考

// 绘制顶点索引的数据
gl.drawElements()
// 直接绘制顶点
gl.drawArrays()

猜测: 在ThreeJS中,如果指定了geometry的索引(index),那么就是调用gl.drawElements,否则调用gl.drawArrays进行顶点绘制。性能考虑以后的绘制几何体都采用顶点索引方式绘制。

4、顶点绘制顺序

参考
在OpenGL中,决定三角面的正反由这个函数指定:

// GL_CCW: 顶点顺序为逆时针方向的表面为正面
// GL_CW: 顶点顺序为顺时针方向的表面为正面
glFrontFace(mode)

WebGL中:

// 逆时针顶点顺序为正面
gl.frontFace(gl.CCW);
// 顺时针顶点顺序为正面
gl.frontFace(gl.CW);
// 开启背面剔除
gl.enable(gl.CULL_FACE);
// 剔除背面
gl.cullFace(gl.BACK);

ThreeJS中:

// 将多边形的缠绕顺序设置为顺时针方向
THREE.FrontFaceDirectionCW = 0
// 将多边形的缠绕顺序设置为逆时针方向
THREE.FrontFaceDirectionCCW = 1
3、计算圆形的顶点

开始计算圆形的顶点坐标和索引。
在这里插入图片描述

// 顶点的数量
vertices.length = 1(圆心) + (segments + 1);
// 每个顶点的X,Y值
//Θ等于每个三角形的所经过的圆心角度数
Θ = thetaStart + (thetaLength / segments) * index
X = radius * cos(Θ)
Y = radius * sin(Θ)

顶点坐标:

for(s =0; s<= segments;s++) {
  var segment = thetaStart + s / segments * thetaLength;
  vertex.x = radius * Math.cos( segment );
  vertex.y = radius * Math.sin( segment );
  vertex.z = 0;
  vertices.push(vertex.x,vertex.y,vertex.z = 0)
}

顶点索引:

//保存顶点索引
//(1,2,0),(2,3,0),(3,4,0)...
for ( i = 1; i <= segments; i ++ ) {
    indices.push( i, i + 1, 0 );
}
5、放到场景中工作起来

代码改写自这里

CircleData.js

/**
 * 产生圆的数据
 */
class CircleData {
  constructor({ radius, segments, thetaStart, thetaLength }) {
    // 参数检查
    radius = radius || 1
    segments = segments !== undefined ? Math.max(3, segments) : 8;
    thetaStart = thetaStart !== undefined ? thetaStart : 0;
    thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;

    // ---- buffers ----
    // 顶点索引
    let indices = []
    // 顶点坐标
    let vertices = [];
    // 法线
    let normals = [];
    // uv坐标
    let uvs = [];

    // ---- helper variables ----
    let i, s;
    let vertex = new Vector3();
    let uv = new Vector2();

    // ---- center point ----
    vertices.push(0, 0, 0);
    normals.push(0, 0, 1);
    uvs.push(0.5, 0.5);

    for (s = 0, i = 3; s <= segments; s++ , i += 3) {
      var segment = thetaStart + s / segments * thetaLength;
      // vertex
      vertex.x = radius * Math.cos(segment);
      vertex.y = radius * Math.sin(segment);
      vertices.push(vertex.x, vertex.y, vertex.z);

      // normal
      normals.push(0, 0, 1);

      // uvs
      uv.x = (vertices[i] / radius + 1) / 2;
      uv.y = (vertices[i + 1] / radius + 1) / 2;
      uvs.push(uv.x, uv.y);
    }

    // indices
    for (i = 1; i <= segments; i++) {
      indices.push(i, i + 1, 0);
    }

    this.indices = indices
    this.normal = normals
    this.position = vertices
    this.uvs = uvs
    // build geometry
    // this.setIndex(indices);
    // this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
    // this.setAttribute('normal', new Float32BufferAttribute(normals, 3));
    // this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
  }

  getData() {
    return {
      uvs: this.uvs,
      indices: this.indices,
      normal: this.normal,
      position: this.position,
    }
  }
}

App.js

class App {
  ...
  addCircle(stage) {
    let circleData = new CircleData({
      radius: 5,
      segments: 64,
      thetaLength: Math.PI * 2
    })

    let { position, indices } = circleData.getData()
    var geometry = new THREE.BufferGeometry();

    // 设置顶点索引
    geometry.setIndex(indices)
    // 设置顶点坐标
    geometry.setAttribute('myPosition', new THREE.Float32BufferAttribute(position, 3));

    let circle = new THREE.Mesh(geometry, material);
    circle.name = "circle"
    stage.scene.add(circle)
  }
  ...
}

着色器代码:

export let vertexShader = `
  attribute vec3 myPosition;
  void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(myPosition, 1.0);
  }
`

export let fragmentShader = `
void main() {
 vec3 color = vec3(0.,1.,1.);
 gl_FragColor = vec4(color,1.0);
}
`

最后效果:
在这里插入图片描述
<全文结束>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenLayers是一个开源的JavaScript库,用于在Web上创建交互式地图应用程序。它提供了丰富的地图功能和工具,包括地图显示、地图控制、图层管理、地图交互等。 关于OpenLayers中的扇形,OpenLayers本身并没有直接提供扇形绘制功能,但可以通过使用OpenLayers的绘制工具和几何图形类来实现绘制扇形的效果。 一种常见的方法是使用OpenLayers的绘制工具绘制一个圆形,然后根据需要设置圆形的起始角度和结束角度,从而实现扇形的效果。可以通过设置圆形的样式、填充颜色和透明度等属性来自定义扇形的外观。 以下是一个使用OpenLayers绘制扇形的示例代码: ```javascript // 创建地图容器 var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ], view: new ol.View({ center: ol.proj.fromLonLat([0, 0]), zoom: 2 }) }); // 创建绘制交互工具 var draw = new ol.interaction.Draw({ source: new ol.source.Vector(), type: 'Circle' }); // 监听绘制结束 draw.on('drawend', function(event) { var circle = event.feature.getGeometry(); // 设置起始角度和结束角度(单位:弧度) var startAngle = 0 // 起始角度 var endAngle = Math.PI / 2; // 结束角度 // 创建扇形的几何图形 var sector = new ol.geom.Polygon([circle.getCoordinates()]); sector.appendLinearRing(circle.getLinearRing(0).clone()); // 设置扇形的起始角度和结束角度 sector.appendLinearRing(circle.getArc(startAngle, endAngle)); // 创建扇形的矢量要素 var sectorFeature = new ol.Feature(sector); // 设置扇形的样式 sectorFeature.setStyle(new ol.style.Style({ fill: new ol.style.Fill({ color: 'rgba(255, 0, 0, 0.5)' // 填充颜色和透明度 }), stroke: new ol.style.Stroke({ color: 'red', // 边框颜色 width: 2 // 边框宽度 }) })); // 将扇形添加到地图中显示 map.getLayers().item(0).getSource().addFeature(sectorFeature); }); // 添加绘制交互工具到地图中 map.addInteraction(draw); ``` 这段代码创建了一个基本的OpenLayers地图,并使用绘制交互工具绘制一个圆形。然后根据设置的起始角度和结束角度,通过创建扇形的几何图形和矢量要素,最后将扇形添加到地图中显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值