⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 make_world.cpp

📁 国外游戏开发者杂志2003年第七期配套代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "framework.h"

#include "mesh.h"
#include "mesh/mesh_builder.h"
#include "make_world.h"
#include "mesh_reducer.h"
#include "mesh_topology_handler.h"

#include "tangent_frames.h"
#include "seam_database.h"
#include "mesh_seam.h"

#include <float.h>
#include <math.h>
#include <stdio.h> // @Refactor for terrain loading; remove?

Elevation_Map *make_elevation_map();

// Find the bounding box of a mesh... we store this bounding box
// on the terrain block.

void find_bounding_box(Triangle_List_Mesh *mesh, Vector3 *bbox_min, Vector3 *bbox_extents) {
    Vector3 max;
    Vector3 *bbox_max = &max;

    *bbox_min = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
    *bbox_max = Vector3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    
    int i;
    for (i = 0; i < mesh->num_vertices; i++) {
        float x = mesh->vertices[i].x;
        float y = mesh->vertices[i].y;
        float z = mesh->vertices[i].z;

        if (x < bbox_min->x) bbox_min->x = x;
        if (y < bbox_min->y) bbox_min->y = y;
        if (z < bbox_min->z) bbox_min->z = z;

        if (x > bbox_max->x) bbox_max->x = x;
        if (y > bbox_max->y) bbox_max->y = y;
        if (z > bbox_max->z) bbox_max->z = z;
    }

    *bbox_extents = *bbox_max - *bbox_min;
}


// 'fill_result' copies geometry from the mesh 'source' into the
// mesh 'result'.  This is a helper function used by 'merge_meshes'
// below.

void fill_result(Triangle_List_Mesh *result, Triangle_List_Mesh *source,
                 int vertex_cursor, int index_cursor, 
                 int triangle_list_cursor, Vector3 offset,
                 int *index_map) {
    int i;
    for (i = 0; i < source->num_vertices; i++) {
        int di = i + vertex_cursor;

        result->vertices[di] = source->vertices[i] + offset;
        result->tangent_frames[di] = source->tangent_frames[i];
        result->uvs[di] = source->uvs[i];
        result->canonical_vertex_map[di] = source->canonical_vertex_map[i] + vertex_cursor;

        index_map[i] = di;
    }

    for (i = 0; i < source->num_indices; i++) {
        int di = i + index_cursor;
        result->indices[di] = source->indices[i] + vertex_cursor;
    }

    for (i = 0; i < source->num_triangle_lists; i++) {
        int di = i + triangle_list_cursor;
        Triangle_List_Info *src_info = &source->triangle_list_info[i];
        Triangle_List_Info *dest_info = &result->triangle_list_info[di];

        dest_info->material_index = src_info->material_index;
        dest_info->num_vertices = src_info->num_vertices;
        dest_info->start_of_list = src_info->start_of_list + index_cursor;
    }
}

// This version of 'fill_result' copies seam triangles into a mesh,
// instead of a mesh into a mesh as above.  You want to put seam
// triangles into the mesh when you are building your LOD hierarchy --
// to combine 4 blocks into 1, you want to include not only the geometry
// of those blocks but the seams between them as well.
void fill_result(Triangle_List_Mesh *result, Mesh_Seam *seam,
                 int index_cursor, int triangle_list_cursor, 
                 int **index_maps) {

    assert(result->num_triangle_lists > 0);  // So we can copy a material info out.  @Improvement: Eventually seams will have their own material info and we should use that instead of this hack


    int i;
    Triangle_List_Info *dest_info = &result->triangle_list_info[triangle_list_cursor];
    
    int num_indices = seam->num_faces * 3;

    dest_info->num_vertices = num_indices;
    dest_info->material_index = 0;  // XXX This is the hacky seam material to be replaced
    dest_info->start_of_list = index_cursor;

    for (i = 0; i < num_indices; i++) {
        int di = i + index_cursor;

        Seam_Index *seam_index = &seam->indices[i];

        int pre_mapped_index = seam_index->vertex_index;

        World_Block *block = seam->block_membership[seam_index->which_mesh];
        assert(block);
        int *index_map = index_maps[block->temporary_integer_storage];

        int mapped_index;
        assert(pre_mapped_index < block->mesh->num_vertices);
        mapped_index = index_map[pre_mapped_index];

        result->indices[di] = mapped_index;
    }
}


// 'merge_meshes' does the work of taking an array of meshes and seams
// plopping them together into one bigger mesh.
Triangle_List_Mesh *merge_meshes(int num_meshes, Triangle_List_Mesh **meshes, 
                                 Vector3 *offsets, int **index_maps,
                                 Auto_Array <Mesh_Seam *> *seams) {
    // XXX for now assumes identical material list
    // We will have to fix this before we're done, but for now
    // we leave it this way.

    int total_indices = 0;
    int total_vertices = 0;
    int total_triangle_lists = 0;
    int total_faces = 0;

    int i;
    for (i = 0; i < num_meshes; i++) {
        Triangle_List_Mesh *mesh = meshes[i];
        if (mesh) {
            total_vertices += mesh->num_vertices;
            total_indices += mesh->num_indices;
            total_triangle_lists += mesh->num_triangle_lists;
            total_faces += mesh->num_faces;
        }
    }

    Mesh_Seam *seam;
    Array_Foreach(seams, seam) {
        total_indices += seam->num_faces * 3;
        total_triangle_lists++;
        total_faces += seam->num_faces;
    } Endeach;

    Triangle_List_Mesh *result = new Triangle_List_Mesh();
    assert(meshes[0]); // AAA
    result->allocate_materials(meshes[0]->num_materials);
    
    result->allocate_geometry(total_vertices, total_faces);

    result->triangle_list_info = new Triangle_List_Info[total_triangle_lists];
    result->num_triangle_lists = total_triangle_lists;

    int vertices_cursor = 0;
    int indices_cursor = 0;
    int triangle_list_cursor = 0;

    for (i = 0; i < result->num_materials; i++) {
        copy_material_info(&result->material_info[i], &meshes[0]->material_info[i]);
    }

    for (i = 0; i < num_meshes; i++) {
        Triangle_List_Mesh *mesh = meshes[i];
        if (mesh == NULL) continue;

        int *index_map = new int[mesh->num_vertices];
        index_maps[i] = index_map;

        fill_result(result, mesh, vertices_cursor, indices_cursor, triangle_list_cursor, offsets[i], index_map);

        vertices_cursor += mesh->num_vertices;
        indices_cursor += mesh->num_indices;
        triangle_list_cursor += mesh->num_triangle_lists;

        int j;
        for (j = 0; j < triangle_list_cursor; j++) {
            assert(result->triangle_list_info[j].material_index >= 0);
        }
    }

    Array_Foreach(seams, seam) {
        fill_result(result, seam, indices_cursor, triangle_list_cursor, 
                    index_maps);

        int num_indices = seam->num_faces * 3;
        indices_cursor += num_indices;
        triangle_list_cursor++;
    } Endeach;

    return result;
}

void xref_block_index_map(World_Block *block, Mesh_Reducer *reducer) {

    int i;
    for (i = 0; i < block->mesh->num_vertices; i++) {
        int old_index = block->index_map_into_parent[i];
        block->index_map_into_parent[i] = reducer->topology_handler->old_index_to_new_index[old_index];
    }
}

Vector3 get_position(Mesh_Seam *seam, 
                     World_Block *b0, World_Block *b1,
                     Seam_Index *index) {
    if (index->which_mesh == 0) return b0->mesh->vertices[index->vertex_index] + b0->position;
    return b1->mesh->vertices[index->vertex_index] + b1->position;
}

void validate_seam(Mesh_Seam *seam, World_Block *b0, World_Block *b1) {
    int i;
    for (i = 0; i < seam->num_faces; i++) {
        Seam_Index *index0 = &seam->indices[i*3+0];
        Seam_Index *index1 = &seam->indices[i*3+1];
        Seam_Index *index2 = &seam->indices[i*3+2];

        Vector3 v0, v1, v2;
        v0 = get_position(seam, b0, b1, index0);
        v1 = get_position(seam, b0, b1, index1);
        v2 = get_position(seam, b0, b1, index2);

        float d0 = distance(v0, v1);
        float d1 = distance(v1, v2);
        float d2 = distance(v0, v2);

        assert(d0 < 10.0f);
        assert(d1 < 10.0f);
        assert(d2 < 10.0f);
    }
}


inline int vertex_index(int i, int j, int verts_per_ring, int num_rings) {
    return j * verts_per_ring + (i % verts_per_ring);
}

Elevation_Map::Elevation_Map(int _num_samples_x, int _num_samples_y) {
    num_samples_x = _num_samples_x;
    num_samples_y = _num_samples_y;

    num_squares_x = num_samples_x - 1;
    num_squares_y = num_samples_y - 1;

    samples = new float[num_samples_x * num_samples_y];
    corner.set(0, 0, 0);

    tangent_frames = NULL;
}



Elevation_Map::~Elevation_Map() {
    delete [] samples;
}

Elevation_Map *make_dummy_elevation_map(float units_per_sample, int elevation_map_samples,
                                        float bump_f1, float bump_f2, float bump_height) {
    float s = units_per_sample;

    int samples = elevation_map_samples;
    Elevation_Map *map = new Elevation_Map(samples, samples);

    map->square_size.set(s, s, 0);
    map->map_size.set(s * map->num_squares_x, s*map->num_squares_y, 0);
    map->corner.set(0, 0, 0);

    float K = 4;
    int i, j;
    for (j = 0; j < map->num_samples_y; j++) {
        for (i = 0; i < map->num_samples_x; i++) {
            float x = map->corner.x + map->square_size.x * i;
            float y = map->corner.y + map->square_size.y * j;

            float f1 = cos((i / (float)(map->num_samples_x)) * bump_f1*K * (2*M_PI));
            float f2 = cos((j / (float)(map->num_samples_y)) * bump_f2*K * (2*M_PI));
            float z = f1 * f2 * bump_height;

            int index = map->get_index(x, y);
            map->samples[index] = z;
        }
    }

    return map;
}


Vector3 get_position(Elevation_Map *map, int i, int j) {
    float x = map->corner.x + map->square_size.x * i;
    float y = map->corner.y + map->square_size.y * j;

    int sample_index = map->get_index(i, j);
    float z = map->samples[sample_index];

    return Vector3(x, y, z);
}

Vector3 get_uv(Elevation_Map *map, int i, int j) {
    float u = (float)i;
    float v = (float)j;
    float w = 0;

    return Vector3(u, v, w);
}

Vector3 get_position(Elevation_Map *map, int index) {
    int i = index % map->num_samples_x;
    int j = index / map->num_samples_x;

    return get_position(map, i, j);
}

Vector3 get_uv(Elevation_Map *map, int index) {
    int i = index % map->num_samples_x;
    int j = index / map->num_samples_x;

    return get_uv(map, i, j);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -