Untitled

 avatar
unknown
plain_text
5 months ago
7.8 kB
6
Indexable
#include "OceanGenerator.h"
#include "geomVertexWriter.h"
#include "geomVertexRewriter.h"
#include "geomVertexFormat.h"
#include "geomTriangles.h"
#include "geomNode.h"
#include "genericAsyncTask.h"
#include "asyncTaskManager.h"
#include "texturepool.h"
#include "shader.h"
#include <cmath>
#include <memory>
#include <QDebug>
#include <QDir>

PT(GeomVertexData) OceanGenerator::vertex_data = nullptr;
float OceanGenerator::time_elapsed = 0.0f;

const LVector2f OceanGenerator::wave1Direction(1.0f, 0.5f);
const float OceanGenerator::wave1Speed = 1.0f;
const float OceanGenerator::wave1Amplitude = 0.2f;
const float OceanGenerator::wave1Frequency = 0.9f;

const LVector2f OceanGenerator::wave2Direction(0.7f, -0.7f);
const float OceanGenerator::wave2Speed = 0.5f;
const float OceanGenerator::wave2Amplitude = 0.1f;
const float OceanGenerator::wave2Frequency = 1.2f;

OceanGenerator::OceanGenerator(WindowFramework* window) : window(window)
{}

OceanGenerator::~OceanGenerator()
{}

NodePath OceanGenerator::generate(int size, float spacing, const std::string& texture_path, const std::string& normal_map_path)
{
    PT(GeomVertexFormat) format = const_cast<GeomVertexFormat*>(GeomVertexFormat::get_v3t2());
    vertex_data = new GeomVertexData("wave_data", format, Geom::UH_dynamic);

    GeomVertexWriter vertex_writer(vertex_data, "vertex");
    GeomVertexWriter texcoord_writer(vertex_data, "texcoord");

    PT(GeomTriangles) triangles = new GeomTriangles(Geom::UH_static);

    int idx = 0;

    for (int x = 0; x <= size; ++x)
    {
        for (int y = 0; y <= size; ++y)
        {
            vertex_writer.add_data3(x * spacing, y * spacing, 0.0f);
            texcoord_writer.add_data2(x / static_cast<float>(size), y / static_cast<float>(size));

            if (x < size && y < size)
            {
                int top_left = idx;
                int top_right = idx + 1;
                int bottom_left = idx + size + 1;
                int bottom_right = idx + size + 2;

                triangles->add_vertices(top_left, bottom_left, bottom_right);
                triangles->add_vertices(top_left, bottom_right, top_right);
            }
            ++idx;
        }
    }

    PT(Geom) geom = new Geom(vertex_data);
    geom->add_primitive(triangles);

    PT(GeomNode) node = new GeomNode("ocean_grid");
    node->add_geom(geom);

    NodePath grid = window->get_render().attach_new_node(node);

    PT(Texture) texture = TexturePool::load_texture(texture_path);
    PT(Texture) normal_map = TexturePool::load_texture(normal_map_path);

    grid.set_texture(texture);
    grid.set_shader_input("texture_map", texture);
    grid.set_shader_input("normal_map", normal_map);
    grid.set_shader_input("time_elapsed", LVecBase4(time_elapsed, 0, 0, 0));

    PT(Shader) shader = Shader::load(Shader::SL_GLSL,
                          "water_shader.vert",
                          "water_shader.frag");

    grid.set_shader(shader);
    grid.set_shader_input("texture_map", texture);
    grid.set_shader_input("normal_map", normal_map);
    grid.set_shader_input("light_pos", LVecBase3(10, 10, 10));
    grid.set_shader_input("view_pos", window->get_camera_group().get_pos());

    NodePath moving_object = window->get_render().attach_new_node("moving_object");
    moving_object.set_pos(size * spacing / 2.0f, size * spacing / 2.0f, 0.0f);

    auto task_data = std::make_unique<std::pair<OceanGenerator*, NodePath>>(this, grid);
    AsyncTaskManager::get_global_ptr()->add(new GenericAsyncTask("update_wave", updateWave, task_data.release()));

    return grid;
}

float OceanGenerator::calculateWaveHeight(float x, float y) const
{
    float projected_x1 = x * wave1Direction.get_x() + y * wave1Direction.get_y();
    float projected_y1 = y * wave1Direction.get_x() - x * wave1Direction.get_y();

    float projected_x2 = x * wave2Direction.get_x() + y * wave2Direction.get_y();
    float projected_y2 = y * wave2Direction.get_x() - x * wave2Direction.get_y();

    float wave1_height = std::sin(wave1Frequency * projected_x1 + time_elapsed) *
                         std::cos(wave1Frequency * projected_y1 + time_elapsed) *
                         wave1Amplitude;

    float wave2_height = std::sin(wave2Frequency * projected_x2 + time_elapsed) *
                         std::cos(wave2Frequency * projected_y2 + time_elapsed) *
                         wave2Amplitude;

    return wave1_height + wave2_height;
}

AsyncTask::DoneStatus OceanGenerator::updateWave(GenericAsyncTask* task, void* data)
{
    float dt = ClockObject::get_global_clock()->get_dt();
    time_elapsed += dt * wave1Speed;

    GeomVertexRewriter vertex_rewriter(vertex_data, "vertex");

    while (!vertex_rewriter.is_at_end())
    {
        LPoint3f vertex = vertex_rewriter.get_data3();

        float projected_x1 = vertex.get_x() * wave1Direction.get_x() + vertex.get_y() * wave1Direction.get_y();
        float projected_y1 = vertex.get_y() * wave1Direction.get_x() - vertex.get_x() * wave1Direction.get_y();

        float projected_x2 = vertex.get_x() * wave2Direction.get_x() + vertex.get_y() * wave2Direction.get_y();
        float projected_y2 = vertex.get_y() * wave2Direction.get_x() - vertex.get_x() * wave2Direction.get_y();

        float wave1_height = std::sin(wave1Frequency * projected_x1 + time_elapsed) *
                             std::cos(wave1Frequency * projected_y1 + time_elapsed) *
                             wave1Amplitude;

        float wave2_height = std::sin(wave2Frequency * projected_x2 + time_elapsed) *
                             std::cos(wave2Frequency * projected_y2 + time_elapsed) *
                             wave2Amplitude;

        float wave_height = wave1_height + wave2_height;

        vertex.set_z(wave_height);
        vertex_rewriter.set_data3(vertex);
    }

    auto* ocean_data = static_cast<std::pair<OceanGenerator*, NodePath>*>(data);
    OceanGenerator* ocean = ocean_data->first;
    NodePath* grid = &ocean_data->second;

    grid->set_shader_input("time_elapsed", LVecBase4(time_elapsed, 0, 0, 0));

    NodePath platform = grid->find("**/oil_rig");
    if (!platform.is_empty())
    {
        float obj_x = platform.get_x();
        float obj_y = platform.get_y();
        float new_z = ocean->calculateWaveHeight(obj_x, obj_y);
        platform.set_z(new_z);
    }

    return AsyncTask::DS_cont;
}



#ifndef OCEANGENERATOR_H
#define OCEANGENERATOR_H

#include "pandaFramework.h"
#include "nodePath.h"
#include "geomVertexData.h"
#include <string>
#include <utility>
#include <memory>

class OceanGenerator {
    struct size_spacing_data
    {
        OceanGenerator* ocean_generator;
        NodePath grid;
        int size;
        float spacing;
    };

public:
    OceanGenerator(WindowFramework* window);
    ~OceanGenerator();

    NodePath generate(int size, float spacing, const std::string& texture_path, const std::string& normal_map_path);
    static AsyncTask::DoneStatus updateWave(GenericAsyncTask* task, void* data);

private:
    WindowFramework* window;
    void* data = nullptr;
    static PT(GeomVertexData) vertex_data;
    static float time_elapsed;

    float calculateWaveHeight(float x, float y) const;

    static const float wave1Speed;
    static const float wave1Amplitude;
    static const float wave1Frequency;
    static const LVector2f wave1Direction;

    static const float wave2Speed;
    static const float wave2Amplitude;
    static const float wave2Frequency;
    static const LVector2f wave2Direction;

    int size = 10;
    float spacing = 10.0f;
};

#endif // OCEANGENERATOR_H
Editor is loading...
Leave a Comment