扇形
参考:
.html
文本代码 中的第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 || 1segments = 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;// vertexvertex.x = radius * Math.cos(segment);vertex.y = radius * Math.sin(segment);vertices.push(vertex.x, vertex.y, vertex.z);// normalnormals.push(0, 0, 1);// uvsuv.x = (vertices[i] / radius + 1) / 2;uv.y = (vertices[i + 1] / radius + 1) / 2;uvs.push(uv.x, uv.y);}// indicesfor (i = 1; i <= segments; i++) {indices.push(i, i + 1, 0);}this.indices = indicesthis.normal = normalsthis.position = verticesthis.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);
}
`
最后效果:
<全文结束>
扇形
参考:
.html
文本代码 中的第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 || 1segments = 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;// vertexvertex.x = radius * Math.cos(segment);vertex.y = radius * Math.sin(segment);vertices.push(vertex.x, vertex.y, vertex.z);// normalnormals.push(0, 0, 1);// uvsuv.x = (vertices[i] / radius + 1) / 2;uv.y = (vertices[i + 1] / radius + 1) / 2;uvs.push(uv.x, uv.y);}// indicesfor (i = 1; i <= segments; i++) {indices.push(i, i + 1, 0);}this.indices = indicesthis.normal = normalsthis.position = verticesthis.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);
}
`
最后效果:
<全文结束>