【问题标题】:Billboarding C++广告牌 C++
【发布时间】:2015-12-17 15:37:02
【问题描述】:

我从老师那里得到了一个代码,它目前显示了一个 3D 地球和一个 2D 粒子系统。摄像机绕圈移动。粒子系统应该面向相机。

根据我的讲义,我必须将广告牌与相机视图矩阵的倒数相乘。我很想尝试,但我无法使用视图矩阵的变量。

#include "pch.h"

#include <Kore/Application.h>
#include <Kore/IO/FileReader.h>
#include <Kore/Math/Core.h>
#include <Kore/Math/Random.h>
#include <Kore/System.h>
#include <Kore/Input/Keyboard.h>
#include <Kore/Input/Mouse.h>
#include <Kore/Audio/Mixer.h>
#include <Kore/Graphics/Image.h>
#include <Kore/Graphics/Graphics.h>
#include <Kore/Log.h>
#include "ObjLoader.h"

#include "Collision.h"
#include "PhysicsWorld.h"
#include "PhysicsObject.h"

using namespace Kore;

// A simple particle implementation
class Particle {
public:
    VertexBuffer* vb;
    IndexBuffer* ib;

    mat4 M;

    // The current position
    vec3 position;

    // The current velocity
    vec3 velocity;

    // The remaining time to live
    float timeToLive;

    // The total time time to live
    float totalTimeToLive;

    // Is the particle dead (= ready to be re-spawned?)
    bool dead;


    void init(const VertexStructure& structure) {
        vb = new VertexBuffer(4, structure,0);
        float* vertices = vb->lock();
        SetVertex(vertices, 0, -1, -1, 0, 0, 0);
        SetVertex(vertices, 1, -1, 1, 0, 0, 1);
        SetVertex(vertices, 2, 1, 1, 0, 1, 1); 
        SetVertex(vertices, 3, 1, -1, 0, 1, 0); 
        vb->unlock();

        // Set index buffer
        ib = new IndexBuffer(6);
        int* indices = ib->lock();
        indices[0] = 0;
        indices[1] = 1;
        indices[2] = 2;
        indices[3] = 0;
        indices[4] = 2;
        indices[5] = 3;
        ib->unlock();

        dead = true;
    }


    void Emit(vec3 pos, vec3 velocity, float timeToLive) {
        position = pos;
        this->velocity = velocity;
        dead = false;
        this->timeToLive = timeToLive;
        totalTimeToLive = timeToLive;
    }

    Particle() {
    }


    void SetVertex(float* vertices, int index, float x, float y, float z, float u, float v) {
        vertices[index* 8 + 0] = x;
        vertices[index*8 + 1] = y;
        vertices[index*8 + 2] = z;
        vertices[index*8 + 3] = u;
        vertices[index*8 + 4] = v;
        vertices[index*8 + 5] = 0.0f;
        vertices[index*8 + 6] = 0.0f;
        vertices[index*8 + 7] = -1.0f;
    }

    void render(TextureUnit tex, Texture* image) {
        Graphics::setTexture(tex, image);
        Graphics::setVertexBuffer(*vb);
        Graphics::setIndexBuffer(*ib);
        Graphics::drawIndexedVertices();
    }

    void Integrate(float deltaTime) {
        timeToLive -= deltaTime;

        if (timeToLive < 0.0f) {
            dead = true;
        }

        // Note: We are using no forces or gravity at the moment.

        position += velocity * deltaTime;

        // Build the matrix
        M = mat4::Translation(position.x(), position.y(), position.z()) * mat4::Scale(0.2f, 0.2f, 0.2f);
    }


};


class ParticleSystem {
public:

    // The center of the particle system
    vec3 position;

    // The minimum coordinates of the emitter box
    vec3 emitMin;

    // The maximal coordinates of the emitter box
    vec3 emitMax;

    // The list of particles
    Particle* particles;

    // The number of particles
    int numParticles;

    // The spawn rate
    float spawnRate;

    // When should the next particle be spawned?
    float nextSpawn;

    ParticleSystem(int maxParticles, const VertexStructure& structure ) {
        particles = new Particle[maxParticles];
        numParticles = maxParticles;
        for (int i = 0; i < maxParticles; i++) {
            particles[i].init(structure);
        }
        spawnRate = 0.05f;
        nextSpawn = spawnRate;

        position = vec3(0.5f, 1.3f, 0.5f);
        float b = 0.1f;
        emitMin = position + vec3(-b, -b, -b);
        emitMax = position + vec3(b, b, b);
    }


    void update(float deltaTime) {
        // Do we need to spawn a particle?
        nextSpawn -= deltaTime;
        bool spawnParticle = false;
        if (nextSpawn < 0) {
            spawnParticle = true;
            nextSpawn = spawnRate;
        }


        for (int i = 0; i < numParticles; i++) {

            if (particles[i].dead) {
                if (spawnParticle) {
                    EmitParticle(i);
                    spawnParticle = false;
                }
            }

            particles[i].Integrate(deltaTime);
        }
    }

    void render(TextureUnit tex, Texture* image, ConstantLocation mLocation, mat4 V) {
        Graphics::setBlendingMode(BlendingOperation::SourceAlpha, BlendingOperation::InverseSourceAlpha);
        Graphics::setRenderState(RenderState::DepthWrite, false);



        /************************************************************************/
        /* Exercise 7 1.1                                                       */
        /************************************************************************/
        /* Change the matrix V in such a way that the billboards are oriented towards the camera */


        /************************************************************************/
        /* Exercise 7 1.2                                                       */
        /************************************************************************/
        /* Animate using at least one new control parameter */      

        for (int i = 0; i < numParticles; i++) {
            // Skip dead particles
            if (particles[i].dead) continue;

            Graphics::setMatrix(mLocation, particles[i].M * V);
            particles[i].render(tex, image);
        }
        Graphics::setRenderState(RenderState::DepthWrite, true);
    }

    float getRandom(float minValue, float maxValue) {
        int randMax = 1000000;
        int randInt = Random::get(0, randMax);
        float r =  (float) randInt / (float) randMax;
        return minValue + r * (maxValue - minValue);
    }

    void EmitParticle(int index) {
        // Calculate a random position inside the box
        float x = getRandom(emitMin.x(), emitMax.x());
        float y = getRandom(emitMin.y(), emitMax.y());
        float z = getRandom(emitMin.z(), emitMax.z());

        vec3 pos;
        pos.set(x, y, z);

        vec3 velocity(0, 0.3f, 0);

        particles[index].Emit(pos, velocity, 3.0f);
    }


};










namespace {
    const int width = 1024;
    const int height = 768;
    double startTime;
    Shader* vertexShader;
    Shader* fragmentShader;
    Program* program;

    float angle = 0.0f;

    // null terminated array of MeshObject pointers
    MeshObject* objects[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };

    // null terminated array of PhysicsObject pointers
    PhysicsObject* physicsObjects[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };


    // The view projection matrix aka the camera
    mat4 P;
    mat4 View;
    mat4 PV;

    vec3 cameraPosition;

    MeshObject* sphere;
    PhysicsObject* po;

    PhysicsWorld physics;


    // uniform locations - add more as you see fit
    TextureUnit tex;
    ConstantLocation pvLocation;
    ConstantLocation mLocation;
    ConstantLocation tintLocation;

    Texture* particleImage;
    ParticleSystem* particleSystem;

    double lastTime;

    void update() {
        double t = System::time() - startTime;
        double deltaT = t - lastTime;
        //Kore::log(Info, "%f\n", deltaT);
        lastTime = t;
        Kore::Audio::update();

        Graphics::begin();
        Graphics::clear(Graphics::ClearColorFlag | Graphics::ClearDepthFlag, 0xff9999FF, 1000.0f);

        Graphics::setFloat4(tintLocation, vec4(1, 1, 1, 1));

        program->set();


        angle += 0.3f * deltaT;

        float x = 0 + 3 * Kore::cos(angle);
        float z = 0 + 3 * Kore::sin(angle);

        cameraPosition.set(x, 2, z);

        //PV = mat4::Perspective(60, (float)width / (float)height, 0.1f, 100) * mat4::lookAt(vec3(0, 2, -3), vec3(0, 2, 0), vec3(0, 1, 0));
        P = mat4::Perspective(60, (float)width / (float)height, 0.1f, 100);
        View = mat4::lookAt(vec3(x, 2, z), vec3(0, 2, 0), vec3(0, 1, 0));
        PV = P * View;


        Graphics::setMatrix(pvLocation, PV);





        // iterate the MeshObjects
        MeshObject** current = &objects[0];
        while (*current != nullptr) {
            // set the model matrix
            Graphics::setMatrix(mLocation, (*current)->M);

            (*current)->render(tex);
            ++current;
        } 



        // Update the physics
        physics.Update(deltaT);

        PhysicsObject** currentP = &physics.physicsObjects[0];
        while (*currentP != nullptr) {
            (*currentP)->UpdateMatrix();
            Graphics::setMatrix(mLocation, (*currentP)->Mesh->M);
            (*currentP)->Mesh->render(tex);
            ++currentP;
        }



        particleSystem->update(deltaT);
        particleSystem->render(tex, particleImage, mLocation, View);



        Graphics::end();
        Graphics::swapBuffers();

    }

    void SpawnSphere(vec3 Position, vec3 Velocity) {
        PhysicsObject* po = new PhysicsObject();
        po->SetPosition(Position);
        po->Velocity = Velocity;
        po->Collider.radius = 0.2f;

        po->Mass = 5;
        po->Mesh = sphere;

        // The impulse should carry the object forward
        // Use the inverse of the view matrix

        po->ApplyImpulse(Velocity);
        physics.AddObject(po);
    }

    void keyDown(KeyCode code, wchar_t character) {
        if (code == Key_Space) {

            // The impulse should carry the object forward
            // Use the inverse of the view matrix

            vec4 impulse(0, 0.4, 2, 0);
            mat4 viewI = View;
            viewI.Invert();
            impulse = viewI * impulse;

            vec3 impulse3(impulse.x(), impulse.y(), impulse.z());


            SpawnSphere(cameraPosition + impulse3 *0.2f, impulse3);
        }
    }

    void keyUp(KeyCode code, wchar_t character) {
        if (code == Key_Left) {
            // ...
        }
    }

    void mouseMove(int x, int y, int movementX, int movementY) {

    }

    void mousePress(int button, int x, int y) {

    }



    void mouseRelease(int button, int x, int y) {

    }

    void init() {
        FileReader vs("shader.vert");
        FileReader fs("shader.frag");
        vertexShader = new Shader(vs.readAll(), vs.size(), VertexShader);
        fragmentShader = new Shader(fs.readAll(), fs.size(), FragmentShader);

        // This defines the structure of your Vertex Buffer
        VertexStructure structure;
        structure.add("pos", Float3VertexData);
        structure.add("tex", Float2VertexData);
        structure.add("nor", Float3VertexData);

        program = new Program;
        program->setVertexShader(vertexShader);
        program->setFragmentShader(fragmentShader);
        program->link(structure);

        tex = program->getTextureUnit("tex");
        pvLocation = program->getConstantLocation("PV");
        mLocation = program->getConstantLocation("M");
        tintLocation = program->getConstantLocation("tint");

        objects[0] = new MeshObject("Base.obj", "Level/basicTiles6x6.png", structure);
        objects[0]->M = mat4::Translation(0.0f, 1.0f, 0.0f);

        sphere = new MeshObject("ball_at_origin.obj", "Level/unshaded.png", structure);

        SpawnSphere(vec3(0, 2, 0), vec3(0, 0, 0));



        Graphics::setRenderState(DepthTest, true);
        Graphics::setRenderState(DepthTestCompare, ZCompareLess);

        Graphics::setTextureAddressing(tex, U, Repeat);
        Graphics::setTextureAddressing(tex, V, Repeat);

        particleImage = new Texture("SuperParticle.png", true);
        particleSystem = new ParticleSystem(100, structure);



    }
}

int kore(int argc, char** argv) {
    Application* app = new Application(argc, argv, width, height, 0, false, "Exercise7");

    init();

    app->setCallback(update);

    startTime = System::time();
    lastTime = 0.0f;
    Kore::Mixer::init();
    Kore::Audio::init();


    Keyboard::the()->KeyDown = keyDown;
    Keyboard::the()->KeyUp = keyUp;
    Mouse::the()->Move = mouseMove;
    Mouse::the()->Press = mousePress;
    Mouse::the()->Release = mouseRelease;

    app->start();

    delete app;

    return 0;
}

有一条评论,老师要我们添加代码。 视图矩阵“视图”的变量位于“命名空间”中。我只使用过命名空间作为库,但这个没有名字。那么如何使用呢?

评论说我们应该使用矩阵 V。所以我只需在代码中添加 V = Inverse View Matrix * Model Matrix 并删除旋转?

对于这些愚蠢的问题,我很抱歉,这应该是一门针对初学者的课程,但它真的不是。讲义对编程部分的帮助不是很大,我只找到了 OpenGL、Unity 或 Direct X 的教程,并且没有使用任何教程。

请帮帮我,我需要在周六早上之前提交,而且我已经花了两天时间尝试代码,但到目前为止我什么也没有!

您可以在这里找到全部内容:https://github.com/TUDGameTechnology/Exercise7

【问题讨论】:

  • 您希望答案是什么样的? “这是代码,希望你得到满分”? Stackoverflow 不这样做。你需要问一个具体的问题,例如What is an anonymous namespace?。找一个(聪明的)合作伙伴一起做作业,stackoverflow 不适合做这个。
  • 亲爱的,我问了两个问题:如何使用变量“视图”,如果我只需要乘以视图矩阵和模型矩阵的逆矩阵是否正确。我在哪里请人做作业?
  • 如果这是我的意图,我已经发布了整个练习。这只是我需要做的一小部分。
  • 好的。显然你的问题很受欢迎。希望你能得到一个好的答案。

标签: c++ matrix system particles


【解决方案1】:

您无需执行任何特殊操作即可访问未命名的命名空间。这个thread 解释更多。

您很可能试图在无法看到您的命名空间的方法中引用 View,因为它们在您的文件中定义的顺序。

update 方法中的这一行:

particleSystem->render(tex, particleImage, mLocation, View);

已经将View 传递给render 方法。

void render(TextureUnit tex, Texture* image, ConstantLocation mLocation, mat4 V)

这意味着在这种情况下mat4 v 你的相机视图。

【讨论】:

  • 好的,很高兴知道^^。那么模型矩阵是什么?我以为它是 Particle 类中的“M”,但我收到错误,因为它不是静态的。
  • @Schokohuetchen 您在哪里以及如何尝试使用它? M 不是静态的,因此如果您尝试在不是 Particle 成员的方法中引用它,您将需要通过“粒子”实例访问它。
  • 它实际上看起来像这段代码删除了旋转,但我不确定这是一个优雅的解决方案:mat4 billboard = mat4::Identity(); mat4 vInv = V; vInv.Invert(); billboard = particles-&gt;M * vInv;
  • @Schokohuetchen 小心,粒子是一个数组,所以粒子->M 只是第一个粒子的矩阵!查看此现有行的渲染代码并考虑它当前在做什么。:Graphics::setMatrix(mLocation,particle[i].M * V);
  • 这就是问题所在,我不知道它的作用。这是那种没有任何进一步解释就直接弹出的代码。就像我说的那样,讲座并没有真正涵盖编程部分。我们得到了代码,就是这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多