Jump to content

  • Log In with Google      Sign In   
  • Create Account

SyncViews

Member Since 06 Feb 2011
Offline Last Active Nov 05 2014 03:22 AM

Topics I've Started

D3D11 Frustum Culling issue

09 September 2014 - 05:02 PM

This seems to be occasionally culling things that are visible on screen when rendering with all world coordinates within the AABB and the same view and projection matrix... The code is pretty straight forward, so not sure what the issue is?

XMMATRIX xmproj = XMMatrixPerspectiveFovLH(fov, aspectRatio, 0.1f, 1000.0f);

XMMATRIX xmview;
xmview = XMMatrixTranslation(-x, -y, -z);
xmview *= XMMatrixRotationY(-yaw);
xmview *= XMMatrixRotationX(-pitch);
...
class Frustum
{
public:
    void update(XMMATRIX projection, XMMATRIX view)
    {
        frustum.CreateFromMatrix(frustum, projection);
        frustum.Transform(frustum, view);
    }
    bool contains(const AxisAlignedBoundaryBox3F &aabb)const
    {
        //AxisAlignedBoundaryBox3 is (min,max) but DirectX::BoundingBox is (centre,extents)!
        Vector3F p1 = aabb.p1;
        Vector3F p2 = aabb.p2;
        
        Vector3F size = p2 - p1;
        Vector3F centre = p1 + size / 2.f;
        
        XMFLOAT3 xsize(size.x, size.y, size.z);
        XMFLOAT3 xcentre(centre.x, centre.y, centre.z);
        bool ret = frustum.Contains(BoundingBox(xcentre, xsize)) != DISJOINT;
        assert(ret || frustum.Intersects(BoundingBox(xcentre, xsize)) == DISJOINT);
        return ret;
    }
private:
    BoundingFrustum frustum;
};

Current options for dynamic 3D lighting in a dynamic world

30 August 2014 - 05:26 PM

Currently I have something similar to Minecraft's lighting in my dynamic world, which I am considering rewriting yet again to fix issues related to chunk/region borders and performance issues when lights or voxels change...

 

 

But wondering if there are any other practical options? In the past I have mostly just used whatever the engine provided, and even that often had a lot of caveats that are not suitable here (slow/expensive light map creation process, a limit on dynamic lights in an area, no support for day-night cycles, little/no indirect lighting, etc.) so not really sure if there is much better out there.

 

At the very least a fairly comprehensive explanation of the minecraft style voxel lighting would be nice (how to minimise how much needs to be recalculated, how to handle chunk boundaries without issues, etc.), but if there is a generic lighting system these days I am much more inclined to put effort into implementing/integrating that since I really would like angled lights (rather than only vertical sunlight for example), full colored lighting, dynamic/moving lights, etc.

 

My main concern with just going straight to shadow mapping etc. is the potentially large number of light sources in each region, and the relatively large area covered by a single draw call, since it currently groups and batches by texture, but that results in each draw call being fairly spread out, with many having a very low "density" faces, and with the majority of faces behind hidden behind something, whereas with non-voxel games with BSP and such the engines seemed very capable of only rendering local/visible stuff, and not things hidden behind walls etc..


3D Coordinate Systems confusion

30 August 2014 - 12:35 PM

So I seem to have made somewhat of a mess with 3D coordinates and rotations between my code, D3D11 and Bullet, and want to try and get back to having a common understanding of the maths involved (not try this, ok wrong, try inveresing the yaw passed to an API, etc.).

 

 

How I logically have various parts of the game currently setup

  • +x is east
  • +y is up
  • +z is north
  • a yaw of 0 is facing north
  • yaw goes clockwise, so north, east, south, west, north (so same as compass bearings)
  • pitch, not really sure, 0 is obviously flat, from there positive seems to be down

And so with D3D11 my matrices are

XMMATRIX xmproj = XMMatrixPerspectiveFovLH(fov, aspectRatio, near, far);


XMMATRIX xmview;
xmview = XMMatrixTranslation(-x, -y, -z);
xmview *= XMMatrixRotationY(-yaw);
xmview *= XMMatrixRotationX(-pitch);

XMMATRIX xmviewProj = xmview * xmproj;

//...multiply with world matrix as needed, can also use xmproj and xmview as is for DirectX::BoundingFrustum
xmShaderTransform = XMMatrixTranspose(xmShaderTransform);
//store in constant buffer for shader output.pos = mul(input.pos, transform)

So far so good, things seem to render as expected fine, but then once looking at logic...

Vector3F Camera::getForwardVec()const
{
    auto c = std::cosf(-pitch);
    Vector3F facing(
        c * std::sinf(yaw),
        std::sinf(-pitch),
        c * std::cosf(yaw));
    return facing;
}

Vector2F Player::getMovementVec(Vector2F move)const
{
    //move is such that +z is forward, +x is strafe right
    //only rotates on XZ plane (pitch is camera only and slopes/steps handled later)
    auto c = std::cosf(-yaw);
    auto s = std::sinf(-yaw);
    return Vector2F(moveX * c - moveZ * s, moveX * s + moveZ * c);
}

...drawing some object...
btTransform transform;
motionstate.getworldTransform(transform);
XMFLOAT4X4 world;
transform.getOpenGLMatrix((float&)world.m);
XMMATRIX xmworld = XMLoadFloat4x4(&world);
XMMATRIX xmmatrix = xmworld * xmviewProj;
xmmatrix = XMMatrixTranspose(xmmatrix);
//use xmmatrix in shader


I am really not happy with having to have the -yaw and -pitch there to make those work... I also get a similar thing with my currently simple integration with bullet, e.g. I have to pass -yaw as the rotation to ghost object for my btKinematicCharacterController, yet if I use the Bullet getOpenGLMatrix to get a world matrix and then do "world * view * proj" I seem to get correct results?

 

Are those to be expected, I am kind of feeling I stuffed something up somewhere, especially with how I am handling yaw? But simply saying it goes the other way I am still not sure is correct (and leaves -yaw in getForwardVec instead...), since that changes the view matrix, and on the grounds that I am "rotating the world around the camera" being my understanding there, an inverse value makes sense (rotate the entire world counterclockwise rather than the screen/camera clockwise)...

 


Graphical user interfaces in a multithreaded environment

29 November 2013 - 11:50 AM

So I have two main threads in my game. One managing the window and rendering, and another thread doing all the logic.
 
The logic thread is then filling out state buffers with relevant bits of the world data that the render thread can then render (interpolating between the two most recent buffers). The window thread forwards the keyboard and mouse input events to the logic thread to keep player movement and such simple.
 
My current idea is to follow the same system as the main game world, and keep all interactions on the logic thread, while telling the render thread what it needs to render. However a solution that lets all the ingame UI stuff not care about threads so much would be nice.

I am also thinking about breaking some of the logic stuff out more (e.g. clickedOnSlot and the functions it works with) to help with working on multiplayer, but that still seems to leave me with this problem where that stuff is on a different thread to the actual rendering, even if I moved the UI's user input events back to the render thread...
 
 

    /**@brief Abstract class for interacting with and rendering an inventory.*/
    class BaseInventoryUi
    {
    public:
        /**Will be constructed on the logic thread when the player does
         * something that needs a UI.
         */
        BaseInventoryUi(
            grf::HudRenderer &renderer,
            Inventory &inventory);
        virtual ~BaseInventoryUi(){}

        /**Must be called on the render thread!*/
        void init();

        void render(int stateIndex);
        /**Must be called by the logic thread since it access the inventory
         * reference.
         */
        void logicUpdate(int stateIndex);

        /**Must be called on the logic thread!*/
        void onMouseDown(const MouseEvent &evt);
        /**Called by render thread to handle tool tips*/
        ItemStack getRenderStackAt(int x, int y, int stateIndex)const;
    protected:
        Inventory &inventory;
        const unsigned size;

        virtual Vector2I getSlotPos(unsigned slot)const=0;
        virtual int getSlotAt(int x, int y)const=0;
        virtual ItemStack getHeldStack()const=0;
        virtual void setHeldStack(ItemStack itemStack)=0;
        /**In UI's screens with 2 inventories, move this stack to the other
         * inventory.
         * @return The number of units that could not be moved.
         */
        virtual uint16_t moveToOtherInventory(unsigned from, ItemStack itemStack)=0;
    private:
        ItemSlotsRenderer itemSlotsRenderer;

        //A better way?
        struct State
        {
            Inventory inventory;
        };
        State states[3];

        /**Must be called on the logic thread!
         * - Shift click to move stack to other inventory
         * - Left click to place held stack, and pick up existing stack if different
         * - Right click when holding nothing to pick up half the stack
         * - Right click when holding something to place 1
         * 
         * Calls:
         * - Any methods using the this->inventory reference
         * - getHeldStack
         * - setHeldStack
         * - moveToOtherInventory
         */
        void clickedOnSlot(
            unsigned slot,
            bool left,
            bool shift);
    };
#include "Precompiled.hpp"
#include "BaseInventoryUi.hpp"
#include "../ItemStack.hpp"
#include "../Items.hpp"
namespace game
{
BaseInventoryUi::BaseInventoryUi(
        grf::HudRenderer &renderer,
        Inventory &inventory)
    : inventory(inventory)
    , size((unsigned)inventory.getSize())
    , itemSlotsRenderer(renderer)
{

}

void BaseInventoryUi::init()
{
    std::vector<Vector2I> slots;
    for (unsigned i = 0; i < size; ++i)
    {
        slots.push_back(getSlotPos(i));
    }
    itemSlotsRenderer.init(slots);
}

void BaseInventoryUi::render(int stateIndex)
{
    const auto& state = states[stateIndex];
    itemSlotsRenderer.renderItems(state.inventory);
}
void BaseInventoryUi::logicUpdate(int stateIndex)
{
    states[stateIndex].inventory = inventory;
}

void BaseInventoryUi::onMouseDown(const MouseEvent &evt)
{
    int slot = getSlotAt(evt.pos.x, evt.pos.y);
    if (slot < 0) return;
    //TODO: Multiplayer?
    clickedOnSlot((unsigned)slot, evt.button == VK_LBUTTON, evt.shiftDown);
}


void BaseInventoryUi::clickedOnSlot(
    unsigned slot,
    bool left,
    bool shift)
{
    ...logic...
}
}

Multithreading a games logic

21 August 2013 - 10:53 AM

So I really want to get my game to a state where it can fully take advantage of multiple threads, and make use of the extra power, e.g. to improve view distance.

Getting things like say audio to largely use another thread is fairly straight forward, as it the slower part of auto saves (compression and writing to disk) or loading in data (e.g. additional chunks in an open world).

For rendering I went with the concept of each object having 3 blocks/copies of all the state data required to render the object, such that the render thread could read 1, the update thread could write 1, and at the end of the update the update thread can have a different 1 and leave the newly updated 1 to render next. Interpolation is then used to greatly smooth the rendering out (basically everything is currently only simulated at 20Hz).

struct RenderStateForSomeObjectType
{
    Vector3I prevPos, pos;
    float prevPitch, pitch;
    float prevYaw yaw;
    ...
};

However what I really want to do is get the heavy lifting in the logic loop to make the best use of the additional threads (since at present at least everything else is still only on average around a single core). Actually getting logic to run in multiple threads seems like an incredibly difficult thing to do.

So my idea is to run the logic as essentially 1 thread, but at each stage of the logic step if the task can be completed with multiple threads (without a tonne of locks) then to give the task out to the worker threads, then wait for the task to complete before doing the next thing.

 

Attached File  threads.png   21.12KB   16 downloads

Is that a good plan, or is there some easy way to actually run all the logic on 3 or 4 threads all the time, or a better way to split the work up?

 

 


PARTNERS