1、圆锥的几何构造
从上面看:是一个圆,严格说是一个正N多边形,N值越大,越接近圆。绘制时要用三角函数计算正N多边形的N个顶点坐标。

从侧面看是个三角形:最下面是一个顶点,和上面的正N多边形顶点相连构成圆锥网格。

2、WebGL代码实现
1)顶点着色器:
const VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_MvpMatrix;
varying vec4 v_Color;
void main() {
gl_Position = u_MvpMatrix * a_Position;
v_Color = a_Color;
}`;
2)片元着色器:
const FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}`;
3)初始化顶点坐标缓冲区
function initVertexBuffers(gl) {
let radius = 1;
let height = 2;
let divideNum = 60;
let theta = Math.PI * 2 / divideNum;
/**
*
* 4
* /
* 3 1
* /
* 2 /
* /
*/ 0
let vertices = [0, -height / 2, 0];
for (let i = 0; i < divideNum; i++) {
let x = radius * Math.cos(theta * i);
let z = radius * Math.sin(theta * i);
vertices.push(x, height / 2, z);
}
let colors = [];
let baseColor = [[1.0, 0.4, 0.4], [0.4, 1.0, 0.4], [0.4, 0.4, 1.0], [0.2, 0.4, 0.0], [0.4, 0.3, 0.8],[0.8, 1, 0.1] ];
colors.push(1.0, 0.4, 0.4);
for(let i=1; i<vertices.length; i++) {
// let color = baseColor[Math.floor(Math.random()*6)];
// colors = colors.concat(color);
colors.push(0.4, 1.0, 0.4);
}
let indices = [];
for(let i=1; i<=divideNum; i++) {
if(i===divideNum){
indices.push(0, i, 1);
}else{
indices.push(0, i, i+1);
}
}
vertices = Float32Array.from(vertices);
colors = Float32Array.from(colors);
indices = Uint8Array.from(indices);
// Create a buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer)
return -1;
// Write the vertex coordinates and color to the buffer object
if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position'))
return -1;
if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color'))
return -1;
// Write the indices to the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
function initArrayBuffer(gl, data, num, type, attribute) {
var buffer = gl.createBuffer(); // Create a buffer object
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Assign the buffer object to the attribute variable
var a_attribute = gl.getAttribLocation(gl.program, attribute);
if (a_attribute < 0) {
console.log('Failed to get the storage location of ' + attribute);
return false;
}
gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);
return true;
}
3)初始化WebGL上下文,绘制圆锥
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Set the vertex information
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the vertex information');
return;
}
// Set the clear color and enable the depth test
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Get the storage location of u_MvpMatrix
var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
if (!u_MvpMatrix) {
console.log('Failed to get the storage location of u_MvpMatrix');
return;
}
// Set the eye point and the viewing volume
var mvpMatrix = new Matrix4();
mvpMatrix.setPerspective(30, 1, 1, 100);
// mvpMatrix.lookAt(0, 2, 8, 0, 0, 0, 0, 2, 0);
// mvpMatrix.lookAt(0, 6, 0, 0, 0, 0, 0, 0, -2); //view from top
// mvpMatrix.lookAt(0, 1, 5, 0, 0, 0, 0, 1, 0); //view from front
mvpMatrix.lookAt(0, 2, 5, 0, 0, 0, 0, 1, 0); //view from front and more high
// Pass the model view projection matrix to u_MvpMatrix
gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Draw the cube
// gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
gl.drawElements(gl.LINE_LOOP, n, gl.UNSIGNED_BYTE, 0);
}
4)HTML文件,这里的部分WebGL封装代码引用之《WebGL编程指南》
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Cone</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
<script src="cone.js"></script>
</body>
</html>
3、效果展示:
