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\$
0
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.