Showing posts with label game. Show all posts
Showing posts with label game. Show all posts

Sunday, March 20, 2016

Your guide to Antialiasing

If you play enough video games, you know that Antialiasing or AA is a software technique for diminishing jaggy-stairstep-like edges that should be smooth.
Even if you don't, here's a quick image comparison.


I recently discovered an old book of mine where I'd written down the different types of antialiasing and how they compare for my own reference. It was a handy little thing to have so I could know which type of antialiasing meant what (there are a lot of them out there, to be honest), and which ones I should use to get the best looks out of my game without taking a huge hit to performance.
I'm going to take this guide out mostly from what I'd written in that book, so depending on when you're reading this post, there is a chance that some new features might not be covered here. You can find the sources of most of the information here by following the links in the titles.

SSAA or FSAA


SS stands for 'supersampling', FS for 'full scene'.
The entire scene is rendered at a larger resolution, and the edge points from that render are used in the actual scene.

Type : Rendering
Performance Hit : Significant, since it involves upscale rendering.
Quality : Genuinely Antialiased

MSAA


MS stands for 'multisample'.
It is a special case of supersampling where only portions of the scene where aliasing might be noticeable are rendered at a higher resolution, like lines or edges.

Type : Rendering
Performance Hit : Tends to be much lower than SSAA, since upscale rendering is only performed to parts of the scene.
Quality : Looks the same as SSAA except in cases where certain edge polygons might go undetected.

CSAA or EQAA


CS stands for 'coverage sample', EQ stands for 'enhanced quality'.
CSAA is by Nvidia, EQAA is by AMD.
Designed to succeed MSAA, it adds more and better coverage sampling in order to produce quality like MSAA would at higher modes, but at only a small performance cost. 

Type : Rendering
Performance Hit : Slightly higher than MSAA at the same sample multiplier.
Quality : Increase in quality as compared to MSAA can range from some to none at all.

FXAA or MLAA


FX stands for 'fast approximation'. ML for 'morphological'.
FXAA is by Nvidia (but also used on other environments due to its popularity), MLAA is by AMD.
There is no rendering involved here. Edges are detected and directly smoothed or blurred.

Type : Post-Processing
Performance Hit : Least. Cheapest form of AA. (Certain benchmarks indicate FXAA to be faster than MLAA)
Quality : Successfully removes jaggies, but normal textures may also have a blurred quality to them.

SMAA


SM stands for 'subpixel morphological'.
It is an upgrade to MLAA where jaggies are removed with better detection without blurring too much.
In my opinion, this is best form of antialiasing due to its perfect balance of good quality for a low performance overhead.

Type : Post-Processing
Performance Hit : Slightly higher than FXAA. Most efficient in terms of performance to quality ratio.
Quality : Better than FXAA or MLAA. Morphs colors and textures appropriately.

TXAA


TX stands for 'temporal'.
It is a mix of filtering and sampling techniques in order to get the best quality at the expense of performance. It's also designed to remove crawling and flickering from moving scenes.

Type : Post-Processing and Rendering
Performance Hit : Most. Much higher than post-processing methods and might even be higher than MSAA.
Quality : Depends on implementation. Might look like a combination of MSAA and FXAA.

I have, to the best of my ability tried to maintain accuracy in this guide, but despite that if you feel something is out of place or needs to be changed, do not hesitate to let me know.
If this guide helped you, you are welcome, though I have a feeling that it is not going to be long before modern games do away with AA tweaking entirely and make it a standard feature of the game engines that they're built on.
Note : Some types of AA were not covered here because they were either too niche, or there was inadequate information available about them, such as TrAA or CFAA. That was intentional to keep things relevant and informative.

Saturday, December 15, 2012

Tic Tac Toe - Unbeatable Algorithm

This post is part of the "First Few Old Blog Posts" archive.
You could expect a certain lack of coherency/maturity from these posts.

For my Computer Project at school , I had to make a simple Java Program. The rules although simple, were very restricting since my class hadn't learnt as much in programming, The program had to be console based (i.e. no Graphics), I could not use any Library Classes apart from the ones that came along with java.lang and Console Input classes. Also, my class hadn't learnt about inheritance and other OOP stuff so I had to stay clear from those too.

The trouble now was to make a good enough project that fit the criteria.
My classmates had settled on making games such as hangman, crossword, calculators etc, but I had already made most of them before while I was getting into programming, and they didn't have much appeal to me.

In the end , I concluded that the project would have to be small anyway, so I decided to make Tic Tac Toe Singleplayer. I'd already made Tic Tac Toe mutliplayer last year as part of a larger package , so I thought that it would be a nice addition to have this as well.

The 3x3 grid was constructed using a 2 dimensional array.
You had to play against the computer in 3 modes - Easy , Medium and Hard respectively.

Easy mode was simple. I used Math.random() to decide the X and Y co-ordinates of the resulting move.

Medium randomly chose between playing easy or hard for that move.

And hard used an algorithm that was impossible to beat. Of course , tic tac toe isn't such a full blown game , and any person smart enough could play any number of matches and always make a tie. But anyway, here is the code for all 3 modes.

Note: This is a function that simply calculates the position that the computer plays in, in a given circumstance. It takes an integer value (int c) that contains the difficulty value (1,2 or 3 for easy,medium or hard). It also takes a 2 dimensional character array of length 3 and 3 (char[][] u) which contains 'X' (player value) , 'O' (computer value) or '-' (empty value). The function returns an integer array of size 2 which contains the x and y co-ordinates of the computed value.

To see the whole program , click here.

     
    public static int[] compute(int c,char[][] u){
        int ar[]=new int[2];
        if (c==1){
            int x=(int)(Math.random()*3);
            int y=(int)(Math.random()*3);
            if (u[x][y]=='-'){
                ar[0]=x;
                ar[1]=y;
                return ar;
            }
            else{
                return compute(1,u);
            }
        }
        if (c==2){
            return compute(((int)(Math.random()*3)+1),u);
        }
        if (c==3){
            boolean mark=false;
            int x=0,y=0;
            int count=0;
            for (int i=0;i<3;i++){
                for (int j=0;j<3;j++){
                    if (u[i][j]=='-'){
                        count++;
                        u[i][j]='X';
                        if (check(u)==2){
                            mark=true;
                            x=i;
                            y=j;
                        }
                        u[i][j]='-';
                    }
                }
            }
            for (int i=0;i<3;i++){
                for (int j=0;j<3;j++){
                    if (u[i][j]=='-'){
                        u[i][j]='O';
                        if (check(u)==1){
                            mark=true;
                            x=i;
                            y=j;
                        }
                        u[i][j]='-';
                    }
                }
            }
            if ((!mark)&&(predict(u,0,0)>1||predict(u,0,2)>1||predict(u,1,1)>1||predict(u,2,0)>1||predict(u,2,2)>1)){
                for (int i=0;i<3;i++){
                    for (int j=0;j<3;j++){
                        if (u[i][j]=='-'&&((i==0&&j==1)||(i==1&&j==0)||(i==1&&j==2)||(i==2&&j==1))){
                            u[i][j]='O';
                            for (int k=0;k<3;k++){
                                for (int l=0;l<3;l++){
                                    if (u[k][l]=='-'){
                                        u[k][l]='O';
                                        if (check(u)==1){
                                            mark=true;
                                            x=k;
                                            y=l;
                                        }
                                        u[k][l]='-';
                                    }
                                }
                            }
                            u[i][j]='-';
                        }
                    }
                }
            }
            if (!mark){
                if (count==9){
                    int ran=(int)(Math.random()*5);
                    switch(ran){
                        case 0 : x=0;
                                 y=0;
                                 break;
                        case 1 : x=1;
                                 y=1;
                                 break;
                        case 2 : x=2;
                                 y=2;
                                 break;
                        case 3 : x=0;
                                 y=2;
                                 break;
                        case 4 : x=2;
                                 y=0;
                                 break;
                    }
                }
                else if (count==8){
                    if (u[1][1]=='-'){
                        x=1;
                        y=1;
                    }
                    else{
                        int ran=(int)(Math.random()*4);
                        switch(ran){
                            case 0 : x=0;
                                     y=0;
                                     break;
                            case 1 : x=2;
                                     y=0;
                                     break;
                            case 2 : x=2;
                                     y=2;
                                     break;
                            case 3 : x=0;
                                     y=2;
                                     break;
                        }
                    }
                }
                else{
                    if (u[0][0]=='-'&&u[2][2]=='O'){
                        x=0;
                        y=0;
                    }
                    else if (u[2][2]=='-'&&u[0][0]=='O'){
                        x=2;
                        y=2;
                    }
                    else if (u[0][2]=='-'&&u[2][0]=='O'){
                        x=0;
                        y=2;
                    }
                    else if (u[2][0]=='-'&&u[0][2]=='O'){
                        x=2;
                        y=0;
                    }
                    else{
                        if (u[0][0]=='-'){
                            x=0;
                            y=0;
                        }
                        else if (u[2][2]=='-'){
                            x=2;
                            y=2;
                        }
                        else if (u[0][2]=='-'){
                            x=0;
                            y=2;
                        }
                        else if (u[2][0]=='-'){
                            x=2;
                            y=0;
                        }
                        else{
                            for (int i=0;i<3;i++){
                                for (int j=0;j<3;j++){
                                    if (u[i][j]=='-'){
                                        x=i;
                                        y=j;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (u[x][y]=='-'){
                ar[0]=x;
                ar[1]=y;
                return ar;
            }
            else{
                return compute(3,u);
            }
        }
        return ar;
    }


Well, I admit that this algorithm isn't the most efficient one out there, but I had functionality in mind, instead of efficiency, so I rolled with a makeshift solution.
But what's more fun is to tell everyone that you couldn't beat my program the next day at the computer lab. They enthusiastically take up the challenge at once, and their faces were worth being looked at when most of them lost to the computer at the second game.

It was great fun.