lecture 4 - brown universitycs.brown.edu/courses/cs195u/lectures/04.pdf · draw everything, why...

46
LECTURE 4 Announcements

Upload: trinhtuong

Post on 07-Apr-2018

218 views

Category:

Documents


5 download

TRANSCRIPT

LECTURE 4Announcements

Retries

• Email your grader email your grader email your graderemail your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader email your grader

Graphics Things

• To add textures– graphics->addTexture(“someName”, “:/images/someTexture.jpg”)

– Image needs to be placed in res/images and added

to images.qrc file

• By default, textures are filtered. This doesn’t look

great for Minecraft– graphics->getTexture(“someTexture”)->

setFilterMethod(Texture::FILTER_METHOD::NEAREST)

Minecraft 2

• More rendering optimizations

• More collisions

LECTURE 4Frustum Culling

THE VIEW FRUSTUM

Frustum Culling

What is it?• The volume of world objects that can

actually be seen by the camera

• Shaped like a pyramid, bounded by:

– Far plane (the “base” of the frustum)

– Near plane (the “cap” of the

frustum)

– Field of view/viewport size

(determine the “walls” of the

frustum)

What we’re doing now…

• During onDraw():

– We tell OpenGL to render

every single object

– Regardless of whether or

not it will appear in the

scene

• Can we avoid drawing

some things?

What we should do…• Instead of telling OpenGL to

draw everything, why don’t we avoid sending that we know won’t be drawn?

• What doesn’t need to be drawn?– Anything not in the view frustum!

• Only good if we can do this faster than it would take for OpenGL to draw everything

Extracting the View Frustum• Frustum is defined by 6 planes

• Planes can be derived directly from the rows of our camera matrices– You can get this using

• camera->getProjection() * camera->getView()

– Gives us a glm matrix

• Be careful– glm uses column-major order, so

use the coordinates given here to access the given cells / rows

0,1

0,0 1,0 2,0 3,0

1,1 2,1 3,1

0,2 1,2 2,2 3,2

0,3 1,3 2,3 3,3

r0

r1

r2

r3

Projection matrix • view matrix

Extracting the View Frustum

• Plane equation is given

by a 4D vector (a,b,c,d):

• ax + by + cz + d = 0

• The 6 clip planes of the

frustum are defined

below!

0,1

0,0 1,0 2,0 3,0

1,1 2,1 3,1

0,2 1,2 2,2 3,2

0,3 1,3 2,3 3,3

r0

r1

r2

r3

Projection matrix • view matrix

Clipping plane −x −y −z +x +y +z

Plane equation r3 − r0 r3 − r1 r3 − r2 r3 + r0 r3 + r1 r3 + r2

Frustum Culling Test - General• Compute 6 plane equations

– Should be updated whenever the camera changes!

• For each piece of scene geometry:

– Does the entire shape fall behind one of the planes?

• Skip rendering, it can’t be seen!

Frustum Culling Test - AABB

• AABB (axis-aligned bounding box)

– Faces parallel to xy, xz, and yz planes

– Defined by a position and dimensions (convenient!)

• Rejection test: are all 8 corners behind any one plane?

– For point (x,y,z), behind plane if ax + by + cz + d < 0

Frustum Culling Test - Sphere• Sphere

– Defined by a position and radius (which can just be one of your dimensions!)

• Rejection test: is the center (x,y,z) at least r units behind any one plane?

– If ax + by + cz + d < -r

– Planes must be normalized

• Divide (a,b,c,d) by 𝑎2 + 𝑏2 + 𝑐2

• You do not have to implement this!

– Minecraft is all about cubes!

– May be helpful later!

Implementation Notes

• Storing the r vectors

– In the camera?

• Only re-compute when camera changes

– Somewhere else?

• Up to you

• Design decisions – yay!

Implementation Notes• What should we cull?

• Individual blocks?– Fine-grained

– Faster to just draw everything

• Whole chunks?– Coarse-grained

– Far fewer culling tests

• Non-environment entities?– Depends on # vertices

– If we have AABB’s for them, depends on how many

• Required: per-chunk culling

QUESTIONS?

Frustum Culling

LECTURE 4Case Study – Occlusion

Culling

Occlusion Culling

• Frustum culling renders everything in the view frustum

• Occlusion culling renders only things that can be seen from camera, not just those inside the frustum (e.g. cuts out objects obscured by other objects)

• Unity Demo!

LECTURE 4Collisions II

COLLISIONS II

Collisions II

Last time on 3D Game Engines…

• If two shapes are overlapping

• Make them not overlapping anymore

• Called “non-continuous” collision detection– Objects teleport small

distances in one tick – there’s no “continuity” from start to end, it all happens immediately

The new model• Shapes are moving towards

each other

• Don’t want them to ever overlap

• Only move them as much as they can go before colliding

• Called continuous collision detection– Never allows shapes to be

overlapping, no teleportation required

Comparison to Non-Continuous Collision

• Continuous collision detection is often better for interacting with terrain (what we’re doing this week)

– Won’t “miss” any collisions

• This is good, because falling through the world is typically game breaking

– Typically depends on one of the objects being static

• Previous model is better for interactions of non-static objects

– May “miss” a few collisions

• Probably isn’t a huge deal

– Doesn’t know/care if either object is moving

Best of both worlds

• How can we mix and match?

– Make separate systems for terrain collision and object-

object collision

– CollisionSystem

• Collides objects with cylinder collision components

– VoxelSystem

• Collides moving player with static Chunks

Voxel Collision Detection

• Goal: collide the player with the terrain using

continuous collision detection

• How do we implement this?

Blocks in the world

Voxel Collision Detection• On a given tick

1. Choose a direction (x, y, or z)

2. Iterate over all blocks the player would pass through, moving in this direction

3. If you encounter an impassable block, move the player to the boundary of that block– If not, move them the full distance

4. Choose the next direction Starting position

Final position

Goal position

Example: X-axis Collision Sweep

Y

X

Solid block

PlayerBottom

TopTop

Check these firstCheck these secondMove player as far as it can go

Move player back by epsilon (0.00001)

Player

Example: X-axis Collision Sweep

• Things to note1. Amount that the player wants to move in x direction in one tick

is velocity.x * seconds• velocity.y * seconds for y direction

• velocity.z * seconds for z direction

2. The player passes through multiple cells in the y dimension, as it makes one step in the x direction• In three dimensions, the player will pass through multiple cells in the y

and z dimensions as it makes one step in the x direction

• Need to check all of these cells for impassable blocks

3. Player is moving in increasing x, so check cells in that order

Implementation Tips

• Need to sweep in x, y, and z, directions but implement the y-sweep first

– Easier to debug horizontal movement if you can stand on a floor

• If a collision is found, move the player away from the point of collision by small amount

– Along surface normal multiplied by small epsilon

Implementation Tips

• Be careful at chunk boundaries– Player may be colliding with blocks in multiple chunks

• Use your 3rd person camera to debug– Visualize the player’s shape to *see* collisions

• Don’t be afraid to restart– The actual code isn’t too long (can be as little as ~20

lines for each axis’ sweep test)

– Lots of places you can be off by 1 block or by epsilon

Pseudocode: Collision Sweep// Sweep test in y direction

void VoxelSystem::ySweep(float seconds, GameObject *obj) {

// TODO: initialize start and end x, z, positions (based on dimensions and position)

int startX, startX, endZ, endZ;

// TODO: initialize start and end y position (based on dimensions, position, velocity and seconds)

int startY, endY;

// TODO: initialize direction of y motion, +1 or -1

int step;

// Loop and check for collisions

for(y = startY; y != (endY + step); y += step) {

for(x = startX; x <= endX; x++) {

for(z = startZ; z <= endZ; z++) {

if(!VoxelSystem::isPassable(x, y, z)) {

// TODO: translate to collision point (minus small epsilon)

break;

}

}

}

}

// TODO: If no collision, move object full distance

}

QUESTIONS?

Collisions II

LECTURE 4Tips for Minecraft 2

Frustum Culling

• Can be incorporated into default DrawSystem,

or a DrawSystem just for Chunks

Collisions

• May be helpful to have isPassable(x, y, z)

method in your VoxelSystem

– For the Chunk that has the block at (x, y, z) in the

world, see if it is passable

– Can use this in your collision sweep methods instead

of checking specific Chunks

LECTURE 4C++ Tip of the Week

Static

• Very helpful C/C++ keyword

• Behavior of static can vary a lot depending on

use

– Member variable vs namespace variable vs local

variable causes different results

More Static

• Static variables exist for the "lifetime" of the translation unit that it's defined in

– Translation unit: simplest unit of compilation

– Consists of the contents of a single source file, plus the contents of any header files directly or indirectly included

• Result: static variables have a single instance (usually)

Namespace Static• If variable is outside of any

functions or class, it can't be accessed from any other translation unit– This is known as "internal

linkage"

• NEVER do this in headers– you end up with a separate

variable in each translation unit (i.e., every time you include the header)

static int x;

class Foo {

public:

void bar();

};

Member Variables and static

• A static member variable is shared between all

instances of the class

• Important: you need to both declare and

define static member variables

Bad Good//in .h fileclass Foo {public:

static int x; void bar();

};

//in .cpp filevoid Foo::bar(){

Foo::x = 10; };

//in .h fileclass Foo {public:

static int x; void bar();

};

//in .cpp fileint Foo::x = 0;

void Foo::bar(){Foo::x = 10;

};

Static functions

• Less confusing

– Same as in Java

• A static function can be

called without an

instance of a class

• Cannot access non-static

member variables

class Foo{private:

static int value;public:

static int getValue() {

return value; }

};

Const

• Another very helpful keyword

• Declares a constant– int x = 4; //normal int

– const int y = x; //value of y cannot be changed

– const int* foo = &y; //can’t change value of y

– int *const bar = &x; //can’t reassign bar

– const int *const yum = foo; //can’t change anything

Const++

• Const member functions

– void Entity::draw() const { … // can’t change Entity

– Very, very good style

• Using const references in functions

– void Entity::accelerate(const vec3 &acc) { …

– Only const functions can be called on const references

– Much cheaper than accelerate(vec3 acc)

MINECRAFT1 PLAYTESTING

To the Sunlab!