glmark2代码分析7(scene Buffer)

分析glmark2的scene-buffer
这里面有三个类:WaveMesh、SceneBufferPrivate和SceneBuffer,组合关系依次为:SceneBuffer包含SceneBufferPrivate,SceneBufferPrivate包含WaveMesh。按照从大到小依次分析:

SceneBuffer类

用的是scene的接口,和其他的类一样,包含构造函数、析构函数、supported、load、unload、setup、teardown、update、draw和validate。

构造函数

new 一个 SceneBufferPrivate 给 priv_,然后是设置 option 参数,这里给的值还是默认值。

OptionValue描述范围
interleavefalse是否顶点属性数据放一个数组中false,true
update-methodmap顶点数据更新的方法false,true
update-fraction1.0mesh length 每次递增的小数范围0.0 到 1.0
update-dispersion0.0How dispersed the updates are [0.0 - 1.0]0.0 到 1.0
columns100The number of mesh subdivisions length-wise
rows20The number of mesh subdisivisions width-wise
buffer-usagestaticbuffer使用方式static,stream,dynamic

析构函数

删除priv_: delete priv_

supported

判断是否支持 glMapBuffer 和 glUnmapBuffer,返回true或false。判断条件:update-method 参数是 subdata,直接取 GLExtensions 中这两个函数指针,这两个在 gl-state 的 init_gl_extension 中判断,gl-state 根据不同egl、wgl和glx派生不同的子类,egl要读取extension,判断其中是否有GL_OES_mapbuffer,其他两个直接为true。

load

设置running_ : running_ = false;

unload

空函数

setup

  1. 调用 Scene::setup()
  2. 设置 option 参数 interleave 为 true
  3. 提取其他 option 参数的值,指定相关控制参数:update_method、 usage、update_fraction、update_dispersion、nlength 和 nwidth。
  4. 创建 WaveMesh 对象 priv_->wave = new WaveMesh,并设置相关参数:interleave、update_method 和 usage。
  5. 调用 priv_->wave->mesh().build_vbo() 创建vbo对象,并传输数据。数据在 vertex_arrays_ 中存放 ???????????
  6. priv_->wave->program().start() 使用program。
  7. 设置viewport:priv_->wave->program()[“Viewport”] = LibMatrix::vec2(canvas_.width(), canvas_.height());
  8. 关闭 cull face:glDisable(GL_CULL_FACE);
  9. 初始化帧数、running_ 和时间参数。

teardown

  1. 删除 priv_->wave
  2. 恢复 GL_CULL_FACE 状态
  3. 调用 Scene::teardown() 这个函数是空

update

  1. 调用 Scene::update(),这个更新时间和帧数。
  2. 更新时间 elapsed_time
  3. 调用 wave 的 update 函数:priv_->wave->update(elapsed_time);

draw

计算 ModelViewProjectionMatrix 并传入,然后调用 priv_->wave->mesh().render_vbo() 开始渲染。

validate

读坐标 (402, 189) 的像素值,和 ref(0x34, 0x99, 0xd7, 0xff) 比较判断。

SceneBufferPrivate

SceneBufferPrivate 是一个结构体,包含 WaveMesh

struct SceneBufferPrivate {
    WaveMesh *wave;
    SceneBufferPrivate() : wave(0) {}
    ~SceneBufferPrivate() { delete wave; }
};

WaveMesh 类

这个类创建 wave mesh,包含的方法有:update、mesh、program,剩下是私有方法:vertex_length_index、wave_func、displacement、create_program、create_mesh。

构造函数

作用: 构造函数生成wave。初始化wave相关参数,然后调用create_program和create_mesh。
输入参数:
length/width:total length/width of the grid (in model coordinates)
nlength/nwidth:the number of length-wise/width-wise grid subdivisions
模型网格的大小和纵横分割数
wavelength:the wave length as a proportion of the length 波形在网格中的长度
duty_cycle:占空比
初始化相关波形计算参数:
k = 2 π w a v e l e n g t h ∗ l e n g t h k=\frac{2\pi}{wavelength * length} k=wavelengthlength2π
p e r i o d = 2 π k = w a v e l e n g t h ∗ l e n g t h period=\frac{2\pi}{k}=wavelength * length period=k2π=wavelengthlength
f u l l _ p e r i o d = p e r i o d d u t y _ c y c l e full\_period=\frac{period}{duty\_cycle} full_period=duty_cycleperiod
速度: v e l o c i t y = 0.1 ∗ l e n g t h velocity=0.1*length velocity=0.1length
位移: d i s p l a c e m e n t = n l e n g t h + 1 displacement=nlength + 1 displacement=nlength+1

create_program

加载 buffer-wireframe.vert/frag
vertex shader:

attribute vec3 position;
// Coordinates of the triangle vertices this vertex belongs to
attribute vec3 tvertex0;
attribute vec3 tvertex1;
attribute vec3 tvertex2;

uniform vec2 Viewport;
uniform mat4 ModelViewProjectionMatrix;

varying vec4 dist;

void main(void)
{
    // Get the clip coordinates of all vertices
    vec4 pos  = ModelViewProjectionMatrix * vec4(position, 1.0);
    vec4 pos0 = ModelViewProjectionMatrix * vec4(tvertex0, 1.0);
    vec4 pos1 = ModelViewProjectionMatrix * vec4(tvertex1, 1.0);
    vec4 pos2 = ModelViewProjectionMatrix * vec4(tvertex2, 1.0);

    // Get the screen coordinates of all vertices
    vec3 p  = vec3(0.5 * Viewport * (pos.xy / pos.w), 0.0);
    vec3 p0 = vec3(0.5 * Viewport * (pos0.xy / pos0.w), 0.0);
    vec3 p1 = vec3(0.5 * Viewport * (pos1.xy / pos1.w), 0.0);
    vec3 p2 = vec3(0.5 * Viewport * (pos2.xy / pos2.w), 0.0);

    // Get the vectors representing the edges of the current
    // triangle primitive. 'vN' is the edge opposite vertex N.
    vec3 v0 = p2 - p1;
    vec3 v1 = p2 - p0;
    vec3 v2 = p1 - p0;

    // Calculate the distance of the current vertex from all
    // the triangle edges. The distance of point p from line
    // v is length(cross(p - p1, v)) / length(v), where
    // p1 is any of the two edge points of v.
    float d0 = length(cross(p - p1, v0)) / length(v0);
    float d1 = length(cross(p - p2, v1)) / length(v1);
    float d2 = length(cross(p - p0, v2)) / length(v2);

    // OpenGL(ES) performs perspective-correct interpolation
    // (it divides by .w) but we want linear interpolation. To
    // work around this, we premultiply by pos.w here and then
    // multiple with the inverse (stored in dist.w) in the fragment
    // shader to undo this operation.
    dist = vec4(pos.w * d0, pos.w * d1, pos.w * d2, 1.0 / pos.w);

    gl_Position = pos;
}

fragment shader:

varying vec4 dist;

const vec4 LINE_COLOR = vec4(1.0);
const vec4 TRIANGLE_COLOR = vec4(0.0, 0.5, 0.8, 0.8);

void main(void)
{
    // Get the minimum distance of this fragment from a triangle edge.
    // We need to multiply with dist.w to undo the workaround we had
    // to perform to get linear interpolation (instead of perspective correct).
    float d = min(dist.x * dist.w, min(dist.y * dist.w, dist.z * dist.w));

    // Get the intensity of the wireframe line
    float I = exp2(-2.0 * d * d);

    gl_FragColor = mix(TRIANGLE_COLOR, LINE_COLOR, I);
}

create_mesh

创建 grid mesh ,传递顶点参数和性数,调用的是mesh类,这列最顶点属性和参数做了管理:
vertex_format:glVertexpointer中垫高点的数据数,vec3、vec4等
attrib_locations:顶点属性的location,从program中拿去
对应使用方法:

std::vector<int> vertex_format;
vertex_format.push_back(3);  
mesh_.set_vertex_format(vertex_format);
std::vector<GLint> attrib_locations;
attrib_locations.push_back(program_["position"].location());
mesh_.set_attrib_locations(attrib_locations);

然后调用 mesh_.make_grid(nlength, nwidth, length, width, 0.0, wave_grid_conf) 生成顶点数据。参数的含义:x、y方向的grid分割数量,x、y两个方向上grid的总长度,两个cell之间的间隔,grid配置函数。

void
Mesh::make_grid(int n_x, int n_y, double width, double height,
                double spacing, grid_configuration_func conf_func)
{
    double side_width = (width - (n_x - 1) * spacing) / n_x;
    double side_height = (height - (n_y - 1) * spacing) / n_y;

    for (int i = 0; i < n_x; i++) {
        for (int j = 0; j < n_y; j++) {
            LibMatrix::vec3 a(-width / 2 + i * (side_width + spacing),
                              height / 2 - j * (side_height + spacing), 0);
            LibMatrix::vec3 b(a.x(), a.y() - side_height, 0);
            LibMatrix::vec3 c(a.x() + side_width, a.y(), 0);
            LibMatrix::vec3 d(a.x() + side_width, a.y() - side_height, 0);

            if (!conf_func) {
                std::vector<float> ul(vertex_size_);
                std::vector<float> ur(vertex_size_);
                std::vector<float> ll(vertex_size_);
                std::vector<float> lr(vertex_size_);

                set_attrib(0, a, &ul);
                set_attrib(0, c, &ur);
                set_attrib(0, b, &ll);
                set_attrib(0, d, &lr);

                next_vertex(); vertices_.back() = ul;
                next_vertex(); vertices_.back() = ll;
                next_vertex(); vertices_.back() = ur;
                next_vertex(); vertices_.back() = ll;
                next_vertex(); vertices_.back() = lr;
                next_vertex(); vertices_.back() = ur;
            }
            else {
                conf_func(*this, i, j, n_x, n_y, a, b, c, d);
            }
        }
    }
}

顶点生成步骤:按照从左上到右下的顺序,计算四个点的位置,考虑每个 cell 的间距。调用wave_grid_conf 是将四边形分成两个三角形,按照顺序存放顶点。

析构函数

调用reset函数,中止和释放program,然后reset mesh的参数。

update

更新 wave 的顶点值。计算方法如下:

  1. 按照时间计算位移量,将位移方向用索引存储在一个ranges的pair数组vector总,将位移量存储在数组displacement_中。
for (size_t n = 0; n <= nlength_; n++) {
        double d(displacement(n, elapsed));

        if (d != displacement_[n]) {
            if (ranges.size() > 0 && ranges.back().second == n - 1) {
                ranges.back().second = n;
            }
            else {
                ranges.push_back(
                        std::pair<size_t, size_t>(n > 0 ? n - 1 : 0, n)
                        );
            }
        }

        displacement_[n] = d;
    }
  1. 按照三角形顶点的排序,对ranges遍历,然后取出displacement_存入vertices中。
    for (std::vector<std::pair<size_t, size_t> >::iterator iter = ranges.begin();
         iter != ranges.end();
         iter++)
    {
        /* First vertex of length index range */
        size_t vstart(iter->first * nwidth_ * 6 + (iter->first % 2));
        /*
         * First vertex not included in the range. We should also update all
         * vertices of triangles touching index i.
         */
        size_t vend((iter->second + (iter->second < nlength_)) * nwidth_ * 6);

        for (size_t v = vstart; v < vend; v++) {
            size_t vt = 3 * (v / 3);
            vertices[v][0 * 3 + 2] = displacement_[vertex_length_index(v)];
            vertices[v][1 * 3 + 2] = displacement_[vertex_length_index(vt)];
            vertices[v][2 * 3 + 2] = displacement_[vertex_length_index(vt + 1)];
            vertices[v][3 * 3 + 2] = displacement_[vertex_length_index(vt + 2)];
        }

        /* Update pair with actual vertex range */
        iter->first = vstart;
        iter->second = vend - 1;
    }

    mesh_.update_vbo(ranges);
}
  1. 调用mesh_.update_vbo(ranges)更新顶点数据,创建vbo。

mesh

返回 mesh_

program

返回program_

reset

前面已经介绍

vertex_length_index

Calculates the length index of a vertex.计算一个顶点的在X方向的index
计算公式

v / (6 * nwidth_) + (v % 2)

wave_func

wave的三角函数

    double r(fmod(x, wave_full_period_));
    if (r < 0)
        r += wave_full_period_;

    /*
     * Return either the sine value or 0.0, depending on the
     * wave duty cycle.
     */
    if (r > wave_period_)
    {
        return 0;
    }
    else
    {
        return 0.2 * std::sin(wave_k_ * r);
    }

displacement

计算wave的位移
* @param n the length index
* @param elapsed the time elapsed since the beginning of the rendering
*
* @return the displacement at point n at time elapsed
*/
double displacement(size_t n, double elapsed)
{
double x(n * length_ / nlength_);
return wave_func(x - wave_velocity_ * elapsed);
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值