用線段繪制球體(three.js webgl_lines_spere例子)

用線段繪制球體(three.js webgl_lines_spere例子)

Three.js中的webgl_lines_sphere例子使用線段渲染出3D球體,效果十分有趣。

實現(xiàn)過程

渲染過程比較簡單,先構(gòu)造出單位球體上(unit sphere)的點,隨后將點再對應(yīng)半徑上隨機伸縮坐標(biāo),每個半徑上相鄰的這兩個點構(gòu)成線段,為線段指定色彩后即可渲染出基本的lines sphere(線段球體)。

這里,我們模仿webgl_lines_sphere例子,使用C++和OpenGL ES 3.0獲得了如下的渲染效果,iOS版本實現(xiàn)源碼可以從github上獲取。

lines_sphere_anim.gif

用線段繪制一個基本的3D球體

這一過程的關(guān)鍵在于使用線段代替頂點形成球形幾何體數(shù)據(jù)。首先,我們使用隨機數(shù)分別產(chǎn)生范圍為[-1..1]的[x,y,z]^t各個坐標(biāo)部件的數(shù)值,然后把這些坐標(biāo)看作矢量,并進行標(biāo)準(zhǔn)化。隨后,我們再將這些矢量的坐標(biāo)看作點的坐標(biāo),那么這些點將位于中心為原點的單位球體之上。如此,我們就擁有了一個球體的頂點數(shù)據(jù),之后,再針對這個頂點沿著半徑方向(也是這個點的法線法線方向)向外在一定范圍內(nèi)隨機伸縮這個點形成單位球體外圍的點,將這個點和單位球體上同半徑的點連接為線段。這樣,我們就擁有了近似繪制球體的線段頂點數(shù)據(jù)。在渲染時,針對線段指定代表色彩和透明度的uniform變量即可渲染出一個線段球體。生成頂點數(shù)據(jù)的代碼如下:

vector<Cvec3f> createLinesSphereGeometry(float r){
    vector<Cvec3f> vertices;
    
    for(int i = 0; i < 1500; i++) {
        //生成范圍為[-1..1]的隨機坐標(biāo)部件值
        float x = rand()/(RAND_MAX/2.0) - 1;
        float y = rand()/(RAND_MAX/2.0) - 1;
        float z = rand()/(RAND_MAX/2.0) - 1;
        
        Cvec3f vertex(x,y,z);
        
        //標(biāo)準(zhǔn)化后,這些隨機點就變成了單位球體上的點,經(jīng)過縮放后,可以變成了不同尺寸球面上的點
        vertex.normalize();
        //縮放為半徑為r的球體
        vertex *= r;
        
        vertices.push_back(vertex);
        
        //在當(dāng)前半徑為r的球體上的點,被乘以固定方位的隨機因子
        Cvec3f vertexOuter = vertex * ((rand()/(float)RAND_MAX) * 0.09 + 1 );
        
        vertices.push_back(vertexOuter);
        
    }
    
    return vertices;
}

球體的多重繪制和移動

webgl_lines_sphere例子中進行了多重(9層)球體繪制,并且讓內(nèi)層的球體隨時間縮放變換,同時進行逆時針旋轉(zhuǎn),外側(cè)的球體則只進行順時針旋轉(zhuǎn)。還有,內(nèi)外側(cè)球體的色彩和透明度也進行對應(yīng)的設(shè)置。整體的展示效果比較有趣。部分代碼如下:


struct RenderingParameter{
    float scale;
    string color;
    float opacity;
};
//球體的初始大小,色彩和透明度信息
vector<RenderingParameter> parameters = {{0.25,"0xff7700", 1}, {0.5, "0xff9900", 1}, {0.75, "0xffaa00", 0.75}, {1, "0xffaa00", 0.5}, {1.25, "0x000833", 0.8},
    {3.0, "0xaaaaaa", 0.75}, {3.5,"0xffffff",0.5}, {4.5, "0xffffff", 0.25}, {5.5, "0xffffff", 0.125}};

//球體的初始化過程代碼
shared_ptr<Geometry> geometry;
vector<Cvec3f> lineSphereVertices = createLinesSphereGeometry(300.0);
geometry.reset(new Geometry(&lineSphereVertices[0],(int)lineSphereVertices.size()));
   
mainCamera.reset(new PerspectiveCamera());
mainCamera->updatePorjectonMatrix();
    
Cvec3 translationVec = Cvec3(0,0,-550);
    
for(size_t i=0;i<parameters.size();i++){
    shared_ptr<LinesSphereModel> ls = make_shared<LinesSphereModel>(LinesSphereModel(geometry,simpleShaderState));
        
    RenderingParameter para=parameters[i];
    //每個球體的初始大小
    ls->scale = Cvec3(para.scale,para.scale,para.scale);
    originalScale[i]=para.scale;
    ls->position = translationVec;
        
    //每個球體的色彩    
    Cvec3 lColor = hexStringToRGB(para.color);
    ls->lineColor = lColor;
        
    //每個球體的初始選擇角度(圍繞y軸)    
    float angleY = rand()/(RAND_MAX/180.0);
    ls->rotation = Cvec3(0,angleY,0);
        
    lsModels.push_back(ls);
}

//每次繪制時球體的運動設(shè)置

//全局變量,在每幀繪制時增加固定數(shù)量
delta+=0.1;

for(int i=0;i<lsModels.size();i++){
//        time_t timeInMill = time(NULL);
//        double time = (double)timeInMill/10;

    shared_ptr<LinesSphereModel> lsModel = lsModels[i];

    //設(shè)置內(nèi)外圈球體的旋轉(zhuǎn)角度
    int factor = i<4?(i+1):-(i+1);
    long rotationY = delta*(factor);
    lsModel->rotation = Cvec3(0,rotationY,0);

      //對內(nèi)圈球體在特定范圍內(nèi)以正弦方式循環(huán)縮放
    if (i < 5){
        float scale = originalScale[i] * (i/5.0 + 1) * (1 + 0.5 * sin(7 * delta * 0.05));
        lsModel->scale = Cvec3(scale,scale,scale);
    }

    lsModel->setPerspectiveCamera(mainCamera);
    lsModel->UpdateMatrixWorld();
    lsModel->Render();
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容