GL02-02:OpenGL球体绘制

球体的渲染效果比较突出,所以本主题完成一个球体的绘制,并利用一些基本的渲染技巧实现渲染。
  1. 球体绘制的数学模型;
  2. 球体绘制的实现;
  3. 球体的渲染的改进效果;


球体绘制的数学模型

球体绘制的数学模型
  1. 第一步:计算z坐标

    • 球面绘制,首先按z方向,切分成多节,每节就是一个圆周;就是上图的1截出来的部分就是2所示的圆周。
    • 截出的圆周有一个高,就是z-坐标;
    • 圆周的高,其实就是这个圆周与圆心形成的锥形的角度决定了圆周的截断高度。这样可以轻松计算出z = cos u
  2. 第二步:等高截的圆周的半径r

    • 这个圆周半径也容易计算r= sin u
  3. 第三步:计算圆周上的x,y

    • 圆周半径确定的情况下,x,y容易计算
      • x = sin u \cdot cos v
      • y = sin u \cdot sin v

代码实现

线计算u,v确定下的球面点坐标

  • 代码中添加了一个球面总得半径,这个半径不影响上面的球面坐标的计算原理,但决定了球的大小。
glm::vec3  getPoint(GLfloat u, GLfloat v){
    GLfloat r = 0.9f;
    GLfloat pi = glm::pi<GLfloat>();
    GLfloat z = r * std::cos(pi * u);
    GLfloat x = r * std::sin(pi * u) * std::cos(2 * pi * v);
    GLfloat y = r * std::sin(pi * u) * std::sin(2 * pi * v);
    // std::cout << x << "," << y << "," << z << std::endl;
    return glm::vec3(x, y, z); 
}

循环u,v计算球面上的多个点

  • 注意:
    • u的取值区间[0,180],v的取值区间[0,360]
    • 计算的4个点,形成两个三角形的6个点。
    • 我们假设u,v是[0, 1],然后转换为[0, 180][0, 360]
    • 计算出来的点放入数组(其中内存拷贝的时候,内存地址的偏移基本单位与指针类型有关)
void createSphere(GLfloat *sphere, GLuint Longitude, GLuint Latitude){
    // Longitude:经线切分个数
    // Latitude:纬线切分个数
    GLfloat lon_step = 1.0f/Longitude;
    GLfloat lat_step = 1.0f/Latitude;
    GLuint offset = 0;
    for(int lat = 0; lat < Latitude; lat++){  // 纬线u
        for(int lon = 0;lon < Longitude; lon++){ // 经线v
            // 一次构造4个点,两个三角形,
            glm::vec3 point1 = getPoint(lat * lat_step, lon * lon_step);
            glm::vec3 point2 = getPoint((lat + 1) * lat_step, lon * lon_step);
            glm::vec3 point3 = getPoint((lat + 1) * lat_step, (lon + 1) * lon_step);
            glm::vec3 point4 = getPoint(lat * lat_step, (lon + 1) * lon_step);
            memcpy(sphere + offset, glm::value_ptr(point1), 3 * sizeof(GLfloat));
            offset += 3;
            memcpy(sphere + offset, glm::value_ptr(point4), 3 * sizeof(GLfloat));
            offset += 3;
            memcpy(sphere + offset, glm::value_ptr(point3), 3 * sizeof(GLfloat));
            offset += 3;

            memcpy(sphere + offset, glm::value_ptr(point1), 3 * sizeof(GLfloat));
            offset += 3;
            memcpy(sphere + offset, glm::value_ptr(point3), 3 * sizeof(GLfloat));
            offset += 3;
            memcpy(sphere + offset, glm::value_ptr(point2), 3 * sizeof(GLfloat));
            offset += 3;
        } 
    }
    // std::cout<<"offset:" << offset << std::endl;
}

调用代码

  • 其中z等分,这里定义为:
    • GLuint lats = 30;
  • 每个圆周上的点的个数定义为:
    • GLuint lons = 60;
    GLfloat vertices[6 * 3 * lats * lons ]; 
    std::cout<< "total:" << sizeof(vertices) << std::endl;
    createSphere(vertices, lons, lats);
    data.addData(vertices, sizeof(vertices), 0, 3);     // 开启Shader第一个参数位置,顶点3个一组。
  • 顶点着色器是缺省的
    • 其中添加了简单的世界坐标变换mode,照相机坐标view,与透视变换perspective。
#version 410 core
layout (location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;

void main(){

    gl_Position = perspective * view * model * vec4(aPos, 1.0);
}

  • 片着色器是缺省的
#version 410 core
out vec4 FragColor;

void main(){
    FragColor =  vec4(1.0f, 0.0f, 0.0f, 1.0f);
}

  • 效果- 绘制方式:glDrawArrays(GL_LINE_LOOP, 0, 6 * lats * lons);
    球体的网格线绘制
  • 效果-绘制方式:glDrawArrays(GL_POINTS, 0, 6 * lats * lons);
    球体的网格点绘制
  • 效果-绘制方式:glDrawArrays(GL_TRIANGLES, 0, 6 * lats * lons);
    球体的三角面绘制

改进与变化

颜色

  • 使用球面坐标作为颜色
    GLfloat vertices[6 * 3 * lats * lons ]; 
    std::cout<< "total:" << sizeof(vertices) << std::endl;
    createSphere(vertices, lons, lats);
    data.addData(vertices, sizeof(vertices), 0, 3);     // 开启Shader第一个参数位置,顶点3个一组。
    // 直接使用切面坐标做颜色坐标
    data.addData(vertices, sizeof(vertices), 1, 3);     // 开启Shader第一个参数位置,顶点3个一组。
  • 效果:代码中做了一个Model的缩小矩阵变换model = glm::scale(model, glm::vec3(0.5f, 0.5f, 0.5f));
球体的颜色渲染

纹理

  1. 顶点着色器
#version 410 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 perspective;
out vec4 vColor;
void main(){
    vColor = vec4(aColor, 1.0f);
    gl_Position = perspective * view * model * vec4(aPos, 1.0);
}

  1. 片着色器
#version 410 core
uniform sampler2D aTexture;
out vec4 FragColor;
in vec4 vColor;
void main(){
    // FragColor = vColor;
    vec2 vTexture = vec2(vColor.x, vColor.y);  // 因为x,y有正负,这个这里不处理,就形成对称纹理效果
    FragColor = texture(aTexture, vTexture) * vColor;
}

  1. 纹理添加代码
   ///////////////////////////////////////////////////
    // 添加纹理对象
    GLint w = 0, h = 0, d = 0;
    data.addTexture("texture.png",&w, &h, &d);
    ///////////////////////////////////////////////////
    shader.initProgram();
    shader.compileShaderFromFile("./glsl_script/glsl04_v_sphere_texture.glsl", GL_VERTEX_SHADER);
    shader.compileShaderFromFile("./glsl_script/glsl04_f_sphere_texture.glsl", GL_FRAGMENT_SHADER);
    shader.link();
    shader.setUniform_1i("aTexture",0);
  1. 效果


    球体的纹理渲染

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容