Aug
5
2013

FOV Using Recursive Shadowcasting

rogue_fov_shadow_casting_algorithm_unity_1

Converted this script to unity: FOV Using Recursive Shadowcasting, for a quick test..

Instructions:
– Attach the script to a plane
– use Unlit/Texture shader as material (then no need lights..)
– Move main camera so that it sees the plane

TODO:
– Use this to create Visibility/Shadow Mesh


Webplayer:
http://unitycoder.com/upload/demos/FOVShadowcasting1/

Source: (C# “FovShadow.cs”)


// Original Sources: http://roguebasin.roguelikedevelopment.org/index.php?title=FOV_using_recursive_shadowcasting
// Converted to Unity by http://unitycoder.com/blog/

using UnityEngine;
using System.Collections;

public class FovShadow : MonoBehaviour {

private Texture2D map;
private RaycastHit hit;
private int size = 256;
int[][] multipliers = new int[4][];
Color[] pix;
Color[] emptyMap;

void Start ()
{
map = new Texture2D(size, size, TextureFormat.ARGB32, false);
renderer.material.mainTexture = map;
renderer.material.mainTexture.filterMode = FilterMode.Point;
for (int y=0;y<map.height;y++)
{
for (int x=0;x<map.width;x++)
{
if (x==0 || y==0 || x==map.width-1 || y==map.height-1)
{
map.SetPixel(x,y,Color.white);
}else{
float p = Mathf.PerlinNoise(x*0.05f,y*0.05f);
if (p>0.5f)
{
map.SetPixel(x,y,Color.white);
}else{
map.SetPixel(x,y,Color.black);
}
}
}
}
map.Apply(false);
emptyMap = map.GetPixels();
pix = map.GetPixels();
multipliers[0] = new[]{1, 0, 0, -1, -1, 0, 0, 1};
multipliers[1] = new[]{0, 1, -1, 0, 0, -1, 1, 0};
multipliers[2] = new[]{0, 1, 1, 0, 0, -1, -1, 0};
multipliers[3] = new[]{1, 0, 0, 1, -1, 0, 0, -1};
}

void Update ()
{
map.SetPixels(emptyMap);
if (Physics.Raycast (Camera.main.ScreenPointToRay(Input.mousePosition), out hit))
{
Vector2 pixelUV = hit.textureCoord;
pixelUV.x *= map.width;
pixelUV.y *= map.height;
do_fov(map, (int)pixelUV.x, (int)pixelUV.y, 64);
map.Apply(false);
}
}

void cast_light(Texture2D map, int x, int y, int radius, int row,float start_slope, float end_slope, int xx, int xy, int yx,    int yy)
{
if (start_slope < end_slope) {
return;
}
float next_start_slope = start_slope;
for (int i = row; i <= radius; i++)
{
bool blocked = false;
for (int dx = -i, dy = -i; dx <= 0; dx++)
{
float l_slope = (dx - 0.5f) / (dy + 0.5f);
float r_slope = (dx + 0.5f) / (dy - 0.5f);
if (start_slope < r_slope) {
continue;
} else if (end_slope > l_slope) {
break;
}
int sax = dx * xx + dy * xy;
int say = dx * yx + dy * yy;
if ((sax < 0 && (int)Mathf.Abs(sax) > x) ||(say < 0 && (int)Mathf.Abs(say) > y))
{
continue;
}
int ax = x + sax;
int ay = y + say;
if (ax >= map.width || ay >= map.height)
{
continue;
}
int radius2 = radius * radius;
if ((int)(dx * dx + dy * dy) < radius2)
{
map.SetPixel(ax, ay, Color.yellow);
}
if (blocked)
{
if (pix[ax+ay*size].r>0)
{
next_start_slope = r_slope;
continue;
} else {
blocked = false;
start_slope = next_start_slope;
}
} else if (pix[ax+ay*size].r>0)
{
blocked = true;
next_start_slope = r_slope;
cast_light(map, x, y, radius, i + 1, start_slope, l_slope, xx,xy, yx, yy);
}
}
if (blocked) {break;}
}
}

void do_fov(Texture2D map, int x, int y, int radius)
{
for (int i = 0; i < 8; i++)
{
cast_light(map, x, y, radius, 1, 1.0f, 0.0f, multipliers[0][i],multipliers[1][i], multipliers[2][i], multipliers[3][i]);
}
}
}


Image#2: Testing GL for drawing visibility blocking mesh (left side: red area is not visible, right side: full map)
rogue_fov_shadow_casting_algorithm_unity_fog_of_war_GL


1 Comment + Add Comment

Leave a comment

Connect

Twitter View LinkedIn profile Youtube Github Join Discord Twitch Instagram BlueSky

UnityLauncherPro

Get UnityLauncherPRO and work faster with Unity Projects!
*free unity hub alternative

@unitycoder_com

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.