Source: Thing.Extend/Objects/Sector.js


/**
 * author luocharming
 * use to create sector
 * @export
 * @class Sector
 * @extends {THING.Mesh}
 */
module.exports = class Sector extends THING.Mesh{
    #degree = 0;
    #degreeDown = 0;
    #segment = 4;
    #radius = 1;
    #height = 0;
    #shape = null;
    constructor(params) {
        let shape = {data:{
            position: [0, 0, 0, 1, 0, 0, 0, 0, 1],
            normal: [0, 1, 0,  0, 1, 0,  0, 1, 0],
            uv: [0, 0, 0, 1, 1, 0],
            uv2: [0, 0, 0, 1, 1, 0],
            index: [0, 1, 2]
        }};
        if(params && params.material) {
            shape.material = params.material;
        }
        super(shape);
        this.#degree = THING.Math.clamp(THING.Utils.parseValue(params && params['degree'], 30), 0, 360);
        this.#degreeDown = THING.Math.clamp(THING.Utils.parseValue(params && params['degreeDown'], 0), 0, 89);
        this.#segment = THING.Math.max(THING.Utils.parseValue(params && params['segment'], 10), 4);
        this.#radius = THING.Math.max(THING.Utils.parseValue(params && params['radius'], 1), 0);
        this.#height = THING.Math.max(THING.Utils.parseValue(params && params['height'], 0),0);
        this.geometry.resource.setVertexData(this.#generateVertexData());
        this.node.$markRenderStateDirty();
    }

    set degree(value) {
        this.#degree = THING.Math.clamp(value, 0, 360);
        this.#updateMesh();
    }

    get degree() {
        return this.#degree;
    }

    set radius(value) {
        this.#radius = THING.Math.max(value,0);
        this.#updateMesh();
    }

    get radius() {
        return this.#radius;
    }

    set degreeDown(value) {
        this.#degreeDown = THING.Math.clamp(value, 0, 89);
        this.#updateMesh();
    }

    get degreeDown() {
        return this.#degreeDown;
    }

    set height(value) {
        if(value * this.#height === 0){
            this.#height = THING.Math.max(value, 0);
            this.#updateMesh(true);
        }else{
            this.#height = THING.Math.max(value, 0);
            this.#updateMesh();
        }
    }

    get height() {
        return this.#height;
    }

    #updateMesh(rebuildMesh = false){
        if(rebuildMesh){
            //TODO 后续支持修改Segment,重置网格
        }else{
            this.#updatePoints();
            this.setPosition(this.#shape.position);
        }
        this.node.$markRenderStateDirty();
    }

    #generateVertexData() {
        if(this.#height === 0){
            this.#shape = this.#createSection([0,1,0],0);
        }else{
            //TODO 后续支持设置厚度
            // shapeData = $createSection(params,false,shapeData);
            // shapeData = $createSection(params,true,shapeData);
            // shapeData = $createSide(params,shapeData);
        }
        let vertexData = {attributes:{},vertexBuffer:[],indices:[]};
        vertexData.attributes = {positions:0,normals:1,uvs:2,uvs2:3};
        let offset = this.#shape.index.length / 3;
        vertexData.vertexBuffer.push(this.#getVertexBuffer(this.#shape.position,offset),this.#getVertexBuffer(this.#shape.normal,offset),this.#getVertexBuffer(this.#shape.uv,offset),this.#getVertexBuffer(this.#shape.uv2,offset));
        vertexData.indices = [...this.#shape.index];
        return vertexData;
    }

    #getVertexBuffer(data,offset){
        return {array:[...data], stride: data.length / offset};
    }

    #createSection(axis,height) {
        let shape = {position:[],normal:[],uv:[],uv2:[],index:[]};
        let startQuat = THING.Math.multiplyQuat(THING.Math.getQuatFromUnitVectors([0,0,0],[0,0,1]),THING.Math.getQuatFromAxisAngle(axis,-this.#degree / 2));
        let unitDegree = this.#degree / this.#segment;
        for (let i = 0; i <= this.#segment; i++) {
            this.#generatePoints(startQuat,axis,i*unitDegree,height,shape);
            this.#generateUvs(i/this.#segment, shape.uv)
        }
        this.#computeNormals(0, shape);
        this.#generateSectionIndices(0, shape);
        shape.uv2 = shape.uv;
        return shape;
    }
    
    #generatePoints(startQuat,axis,degree,height,out) {
        out.position.push(0,0,0);
        let startDir = [0,0,1];
        let quat = THING.Math.multiplyQuat(startQuat, THING.Math.getQuatFromAxisAngle(axis, degree));
        let dir = THING.Math.vec3ApplyQuat(startDir,quat);
        dir = THING.Math.normalizeVector(dir);
        let point = THING.Math.scaleVector(dir,this.#radius);
        point = [point[0], point[1] + height - this.#radius * THING.Math.tan(THING.Math.degToRad(this.#degreeDown)), point[2]];
        out.position.push(...point);
    }
    
    #generateUvs(offset, out) {
        out.push(offset,0,offset,1);
    }

    #computeNormals(startIndex, out) {
        out.normal = [];
        let index = startIndex;
        for (let i = 0; i <= this.#segment; i++) {
            if(i == this.#segment){
                let n = [out.normal[out.normal.length - 3],out.normal[out.normal.length - 2],out.normal[out.normal.length - 1]];
                out.normal.push(...n,...n);
                continue;
            }
            let o = [out.position[index],out.position[index + 1],out.position[index + 2]];
            let a = [out.position[index + 3],out.position[index + 4],out.position[index + 5]];
            let b = [out.position[index + 9],out.position[index + 10],out.position[index + 11]];
            let oa = THING.Math.subVector(a,o);
            let ob = THING.Math.subVector(b,o);
            let n = THING.Math.crossVector(oa,ob);
            n = THING.Math.normalizeVector(n);
            out.normal.push(...n,...n);
            index += 6;
        }
    }

    #generateSectionIndices(startIndex, out) {
        for (let i = 0; i < this.#segment; i++) {
            out.index.push(startIndex, startIndex+1, startIndex+3);
            startIndex+=2;
        }
    }

    #updatePoints() {
        //TODO 目前不考虑厚度
        let axis = [0,1,0];
        let height = 0;
        let startQuat = THING.Math.multiplyQuat(THING.Math.getQuatFromUnitVectors([0,0,0],[0,0,1]),THING.Math.getQuatFromAxisAngle(axis,-this.#degree / 2));
        let unitDegree = this.#degree / this.#segment;
        this.#shape.position = [];
        for (let i = 0; i <= this.#segment; i++) {
            this.#generatePoints(startQuat,axis,i*unitDegree,height,this.#shape);
        }
        this.#computeNormals(0,this.#shape);
    }
}