0
\$\begingroup\$

I'm making a game with marching cubes terrain (I know very original idea) and I don't exactly know how to color it. I have a system to do it, I just need to know how to interpolate it where it's not all smoothed out.

I just want flat colors, I think it boils down to this function (this is this guys code http://www.paulbourke.net/geometry/polygonise/):

glm::vec3 VertexInterp(const float& isolevel,const glm::vec3& p1,const glm::vec3& p2, const float& valp1, const float& valp2) {
    float mu;
    glm::vec3 p;

    if (ABS(isolevel-valp1) < 0.00001)
        return(p1);
    if (ABS(isolevel-valp2) < 0.00001)
        return(p2);
    if (ABS(valp1-valp2) < 0.00001)
        return(p1);
    mu = (isolevel - valp1) / (valp2 - valp1);
    p.x = p1.x + mu * (p2.x - p1.x);
    p.y = p1.y + mu * (p2.y - p1.y);
    p.z = p1.z + mu * (p2.z - p1.z);

    return p;
}

So if anyone could help me implement a flatter or smoother variant of that function it would be very much appreciated (I know all the rest of the things I need to do I just need help with this)

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Once I have generated all of the triangles, I weld the vertices, and get face and vertex normals.

Once that's done, I stuff the vertex data (including position, colour) into a buffer and call glDrawArrays.

Here are some codes:

void get_vertices_and_normals_from_triangles(vector<triangle> &t, vector<vec3> &fn, vector<vec3> &v, vector<vec3> &vn)
{
    fn.clear();
    v.clear();
    vn.clear();
    
    if(0 == t.size())
        return;

    cout << "Triangles: " << t.size() << endl;
    
    cout << "Welding vertices" << endl;
 
    // Insert unique vertices into set.
    set<indexed_vertex_3> vertex_set;
 
    for(vector<triangle>::const_iterator i = t.begin(); i != t.end(); i++)
    {
        vertex_set.insert(i->vertex[0]);
        vertex_set.insert(i->vertex[1]);
        vertex_set.insert(i->vertex[2]);
    }
 
    cout << "Vertices: " << vertex_set.size() << endl;

    cout << "Generating vertex indices" << endl;
 
    vector<indexed_vertex_3> vv;

    // Add indices to the vertices.
    for(set<indexed_vertex_3>::const_iterator i = vertex_set.begin(); i != vertex_set.end(); i++)
    {
        size_t index = vv.size();
        vv.push_back(*i);
        vv[index].index = index;
    }

    for (size_t i = 0; i < vv.size(); i++)
    {
        vec3 vv_element(vv[i].x, vv[i].y, vv[i].z);
        v.push_back(vv_element);
    }
 
    vertex_set.clear();

    // Re-insert modifies vertices into set.
    for(vector<indexed_vertex_3>::const_iterator i = vv.begin(); i != vv.end(); i++)
        vertex_set.insert(*i);
 
    cout << "Assigning vertex indices to triangles" << endl;
   
    // Find the three vertices for each triangle, by index.
    set<indexed_vertex_3>::iterator find_iter;
 
    for(vector<triangle>::iterator i = t.begin(); i != t.end(); i++)
    {
        find_iter = vertex_set.find(i->vertex[0]);
        i->vertex[0].index = find_iter->index;
 
        find_iter = vertex_set.find(i->vertex[1]);
        i->vertex[1].index = find_iter->index;
 
        find_iter = vertex_set.find(i->vertex[2]);
        i->vertex[2].index = find_iter->index;
    }

    vertex_set.clear();

    cout << "Calculating normals" << endl;
    fn.resize(t.size());
    vn.resize(v.size());

    for(size_t i = 0; i < t.size(); i++)
    {
        vec3 v0;// = t[i].vertex[1] - t[i].vertex[0];
        v0.x = t[i].vertex[1].x - t[i].vertex[0].x;
        v0.y = t[i].vertex[1].y - t[i].vertex[0].y;
        v0.z = t[i].vertex[1].z - t[i].vertex[0].z;

        vec3 v1;// = t[i].vertex[2] - t[i].vertex[0];
        v1.x = t[i].vertex[2].x - t[i].vertex[0].x;
        v1.y = t[i].vertex[2].y - t[i].vertex[0].y;
        v1.z = t[i].vertex[2].z - t[i].vertex[0].z;

        fn[i] = cross(v0, v1);
        fn[i] = normalize(fn[i]);

        vn[t[i].vertex[0].index] = vn[t[i].vertex[0].index] + fn[i];
        vn[t[i].vertex[1].index] = vn[t[i].vertex[1].index] + fn[i];
        vn[t[i].vertex[2].index] = vn[t[i].vertex[2].index] + fn[i];
    }

    for (size_t i = 0; i < vn.size(); i++)
        vn[i] = normalize(vn[i]);
}


bool read_triangles_from_binary_stereo_lithography_file(vector<triangle> &triangles, const char *const file_name)
{
    triangles.clear();
    
    // Write to file.
    ifstream in(file_name, ios_base::binary);
 
    if(in.fail())
        return false;

    const size_t header_size = 80;
    vector<char> buffer(header_size, 0);
    unsigned int num_triangles = 0; // Must be 4-byte unsigned int.
    indexed_vertex_3 normal;

    // Read header.
    in.read(reinterpret_cast<char *>(&(buffer[0])), header_size);
    
    if(header_size != in.gcount())
        return false;

    // Read number of triangles.
    in.read(reinterpret_cast<char *>(&num_triangles), sizeof(unsigned int));
    
    if(sizeof(unsigned int) != in.gcount())
        return false;

    triangles.resize(num_triangles);

    // Enough bytes for twelve 4-byte floats plus one 2-byte integer, per triangle.
    const size_t data_size = (12*sizeof(float) + sizeof(short unsigned int)) * num_triangles;
    buffer.resize(data_size, 0);

    in.read(reinterpret_cast<char *>(&buffer[0]), data_size);

    if(data_size != in.gcount())
        return false;

    // Use a pointer to assist with the copying.
    // Should probably use std::copy() instead, but memcpy() does the trick, so whatever...
    char *cp = &buffer[0];

    for(vector<triangle>::iterator i = triangles.begin(); i != triangles.end(); i++)
    {
        // Skip face normal.
        cp += 3*sizeof(float);
        
        // Get vertices.
        memcpy(&i->vertex[0].x, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[0].y, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[0].z, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[1].x, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[1].y, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[1].z, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[2].x, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[2].y, cp, sizeof(float)); cp += sizeof(float);
        memcpy(&i->vertex[2].z, cp, sizeof(float)); cp += sizeof(float);

        // Skip attribute.
        cp += sizeof(short unsigned int);
    }

    in.close();
 
    return true;
} 

where:

void draw_mesh(void)
{
    glUseProgram(render.get_program());


    glUniformMatrix4fv(uniforms.render.proj_matrix, 1, GL_FALSE, &main_camera.projection_mat[0][0]);
    glUniformMatrix4fv(uniforms.render.mv_matrix, 1, GL_FALSE, &main_camera.view_mat[0][0]);
    glUniform1f(uniforms.render.shading_level, 1.0f);

    vector<float> vertex_data;

    for (size_t i = 0; i < triangles.size(); i++)
    {
        vec3 colour(0.0f, 0.8f, 1.0f);

        size_t v0_index = triangles[i].vertex[0].index;
        size_t v1_index = triangles[i].vertex[1].index;
        size_t v2_index = triangles[i].vertex[2].index;

        vec3 v0_fn(vertex_normals[v0_index].x, vertex_normals[v0_index].y, vertex_normals[v0_index].z);
        vec3 v1_fn(vertex_normals[v1_index].x, vertex_normals[v1_index].y, vertex_normals[v1_index].z);
        vec3 v2_fn(vertex_normals[v2_index].x, vertex_normals[v2_index].y, vertex_normals[v2_index].z);

        vec3 v0(triangles[i].vertex[0].x, triangles[i].vertex[0].y, triangles[i].vertex[0].z);
        vec3 v1(triangles[i].vertex[1].x, triangles[i].vertex[1].y, triangles[i].vertex[1].z);
        vec3 v2(triangles[i].vertex[2].x, triangles[i].vertex[2].y, triangles[i].vertex[2].z);

        vertex_data.push_back(v0.x);
        vertex_data.push_back(v0.y);
        vertex_data.push_back(v0.z);
        vertex_data.push_back(v0_fn.x);
        vertex_data.push_back(v0_fn.y);
        vertex_data.push_back(v0_fn.z);
        vertex_data.push_back(colour.x);
        vertex_data.push_back(colour.y);
        vertex_data.push_back(colour.z);

        vertex_data.push_back(v1.x);
        vertex_data.push_back(v1.y);
        vertex_data.push_back(v1.z);
        vertex_data.push_back(v1_fn.x);
        vertex_data.push_back(v1_fn.y);
        vertex_data.push_back(v1_fn.z);
        vertex_data.push_back(colour.x);
        vertex_data.push_back(colour.y);
        vertex_data.push_back(colour.z);

        vertex_data.push_back(v2.x);
        vertex_data.push_back(v2.y);
        vertex_data.push_back(v2.z);
        vertex_data.push_back(v2_fn.x);
        vertex_data.push_back(v2_fn.y);
        vertex_data.push_back(v2_fn.z);
        vertex_data.push_back(colour.x);
        vertex_data.push_back(colour.y);
        vertex_data.push_back(colour.z);
    }


    GLuint components_per_vertex = 9;
    const GLuint components_per_normal = 3;
    GLuint components_per_position = 3;
    const GLuint components_per_colour = 3;

    GLuint triangle_buffer;

    glGenBuffers(1, &triangle_buffer);

    GLuint num_vertices = static_cast<GLuint>(vertex_data.size()) / components_per_vertex;

    glBindBuffer(GL_ARRAY_BUFFER, triangle_buffer);
    glBufferData(GL_ARRAY_BUFFER, vertex_data.size() * sizeof(GLfloat), &vertex_data[0], GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "position"));
    glVertexAttribPointer(glGetAttribLocation(render.get_program(), "position"),
        components_per_position,
        GL_FLOAT,
        GL_FALSE,
        components_per_vertex * sizeof(GLfloat),
        NULL);

    glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "normal"));
    glVertexAttribPointer(glGetAttribLocation(render.get_program(), "normal"),
        components_per_normal,
        GL_FLOAT,
        GL_TRUE,
        components_per_vertex * sizeof(GLfloat),
        (const GLvoid*)(components_per_position * sizeof(GLfloat)));

    glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "colour"));
    glVertexAttribPointer(glGetAttribLocation(render.get_program(), "colour"),
        components_per_colour,
        GL_FLOAT,
        GL_TRUE,
        components_per_vertex * sizeof(GLfloat),
        (const GLvoid*)(components_per_normal * sizeof(GLfloat) + components_per_position * sizeof(GLfloat)));

    glDrawArrays(GL_TRIANGLES, 0, num_vertices);

    glDeleteBuffers(1, &triangle_buffer);
}

Hopefully this will help.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .