More 3D Work

-=-=-=-=-=-

-ESM Shadow Mapping for softer and less glitchy shadows
-HDR Pipeline (convert to Linear on texture import, convert to SRGB at the end)
-Fix to xml parse bug
This commit is contained in:
Juan Linietsky
2014-06-16 10:22:26 -03:00
parent 64e83bfd14
commit 703004f830
40 changed files with 1114 additions and 116 deletions

View File

@ -40,7 +40,9 @@ static const char* _light_param_names[VS::LIGHT_PARAM_MAX]={
"params/attenuation",
"shadow/darkening",
"shadow/z_offset",
"shadow/z_slope_scale"
"shadow/z_slope_scale",
"shadow/esm_multiplier",
"shadow/blur_passes"
};
void Light::set_parameter(Parameter p_param, float p_value) {
@ -479,6 +481,8 @@ void Light::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/esm_multiplier", PROPERTY_HINT_RANGE, "1.0,512.0,0.1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_ESM_MULTIPLIER);
ADD_PROPERTYI( PropertyInfo( Variant::INT, "shadow/blur_passes", PROPERTY_HINT_RANGE, "0,4,1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_BLUR_PASSES);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "projector",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_projector"), _SCS("get_projector"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "operator",PROPERTY_HINT_ENUM,"Add,Sub"), _SCS("set_operator"), _SCS("get_operator"));
@ -511,6 +515,8 @@ Light::Light(VisualServer::LightType p_type) {
set_parameter(PARAM_SHADOW_DARKENING,0.0);
set_parameter(PARAM_SHADOW_Z_OFFSET,0.05);
set_parameter(PARAM_SHADOW_Z_SLOPE_SCALE,0);
set_parameter(PARAM_SHADOW_ESM_MULTIPLIER,60);
set_parameter(PARAM_SHADOW_BLUR_PASSES,1);
set_color( COLOR_AMBIENT, Color(0,0,0));
set_color( COLOR_DIFFUSE, Color(1,1,1));

View File

@ -53,6 +53,8 @@ public:
PARAM_SHADOW_DARKENING=VisualServer::LIGHT_PARAM_SHADOW_DARKENING,
PARAM_SHADOW_Z_OFFSET=VisualServer::LIGHT_PARAM_SHADOW_Z_OFFSET,
PARAM_SHADOW_Z_SLOPE_SCALE=VisualServer::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE,
PARAM_SHADOW_ESM_MULTIPLIER=VisualServer::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER,
PARAM_SHADOW_BLUR_PASSES=VisualServer::LIGHT_PARAM_SHADOW_BLUR_PASSES,
PARAM_MAX=VisualServer::LIGHT_PARAM_MAX
};

View File

@ -1078,6 +1078,18 @@ void Node::remove_from_group(const StringName& p_identifier) {
}
Array Node::_get_groups() const {
Array groups;
List<GroupInfo> gi;
get_groups(&gi);
for (List<GroupInfo>::Element *E=gi.front();E;E=E->next()) {
groups.push_back(E->get().name);
}
return groups;
}
void Node::get_groups(List<GroupInfo> *p_groups) const {
const StringName *K=NULL;
@ -1712,6 +1724,7 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("remove_from_group","group"),&Node::remove_from_group);
ObjectTypeDB::bind_method(_MD("is_in_group","group"),&Node::is_in_group);
ObjectTypeDB::bind_method(_MD("move_child","child_node:Node","to_pos"),&Node::move_child);
ObjectTypeDB::bind_method(_MD("get_groups"),&Node::_get_groups);
ObjectTypeDB::bind_method(_MD("raise"),&Node::raise);
ObjectTypeDB::bind_method(_MD("set_owner","owner:Node"),&Node::set_owner);
ObjectTypeDB::bind_method(_MD("get_owner:Node"),&Node::get_owner);

View File

@ -125,6 +125,7 @@ private:
void _duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_reown_map) const;
Array _get_children() const;
Array _get_groups() const;
friend class SceneMainLoop;

View File

@ -140,6 +140,7 @@
#include "scene/resources/mesh_library.h"
#include "scene/resources/image_path_finder.h"
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/sample.h"
#include "scene/audio/sample_player.h"
@ -536,6 +537,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<StyleBoxImageMask>();
ObjectTypeDB::register_type<Theme>();
ObjectTypeDB::register_type<ImagePathFinder>();
ObjectTypeDB::register_type<PolygonPathFinder>();
ObjectTypeDB::register_type<BitMap>();
OS::get_singleton()->yield(); //may take time to init

View File

@ -140,8 +140,8 @@ void Environment::_bind_methods() {
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/brightness",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_BRIGHTNESS);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/contrast",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_CONTRAST);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/saturation",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_SATURATION);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"gamma/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_GAMMA);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"gamma/gamma",PROPERTY_HINT_EXP_EASING,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GAMMA);
ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"srgb/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_SRGB);
@ -194,7 +194,7 @@ void Environment::_bind_methods() {
BIND_CONSTANT( FX_HDR );
BIND_CONSTANT( FX_FOG );
BIND_CONSTANT( FX_BCS);
BIND_CONSTANT( FX_GAMMA );
BIND_CONSTANT( FX_SRGB );
BIND_CONSTANT( FX_MAX );
@ -226,7 +226,6 @@ void Environment::_bind_methods() {
BIND_CONSTANT( FX_PARAM_BCS_BRIGHTNESS );
BIND_CONSTANT( FX_PARAM_BCS_CONTRAST );
BIND_CONSTANT( FX_PARAM_BCS_SATURATION );
BIND_CONSTANT( FX_PARAM_GAMMA );
BIND_CONSTANT( FX_PARAM_MAX );
}
@ -269,7 +268,7 @@ Environment::Environment() {
fx_set_param(FX_PARAM_BCS_BRIGHTNESS,1.0);
fx_set_param(FX_PARAM_BCS_CONTRAST,1.0);
fx_set_param(FX_PARAM_BCS_SATURATION,1.0);
fx_set_param(FX_PARAM_GAMMA,1.0);
}
Environment::~Environment() {

View File

@ -67,7 +67,7 @@ public:
FX_HDR=VS::ENV_FX_HDR,
FX_FOG=VS::ENV_FX_FOG,
FX_BCS=VS::ENV_FX_BCS,
FX_GAMMA=VS::ENV_FX_GAMMA,
FX_SRGB=VS::ENV_FX_SRGB,
FX_MAX=VS::ENV_FX_MAX,
};
@ -102,7 +102,6 @@ public:
FX_PARAM_BCS_BRIGHTNESS=VS::ENV_FX_PARAM_BCS_BRIGHTNESS,
FX_PARAM_BCS_CONTRAST=VS::ENV_FX_PARAM_BCS_CONTRAST,
FX_PARAM_BCS_SATURATION=VS::ENV_FX_PARAM_BCS_SATURATION,
FX_PARAM_GAMMA=VS::ENV_FX_PARAM_GAMMA,
FX_PARAM_MAX=VS::ENV_FX_PARAM_MAX
};
private:

View File

@ -0,0 +1,413 @@
#include "polygon_path_finder.h"
#include "geometry.h"
bool PolygonPathFinder::_is_point_inside(const Vector2& p_point) {
int crosses=0;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
const Edge& e=E->get();
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
if (Geometry::segment_intersects_segment_2d(a,b,p_point,outside_point,NULL)) {
crosses++;
}
}
return crosses&1;
}
void PolygonPathFinder::setup(const Vector<Vector2>& p_points, const Vector<int>& p_connections) {
ERR_FAIL_COND(p_connections.size()&1);
points.clear();
edges.clear();
//insert points
int point_count=p_points.size();
points.resize(point_count+2);
for(int i=0;i<p_points.size();i++) {
points[i].pos=p_points[i];
outside_point.x = i==0?p_points[0].x:(MAX( p_points[i].x, outside_point.x ));
outside_point.y = i==0?p_points[0].y:(MAX( p_points[i].y, outside_point.y ));
}
outside_point.x+=20.451+Math::randf()*10.2039;
outside_point.y+=21.193+Math::randf()*12.5412;
//insert edges (which are also connetions)
for(int i=0;i<p_connections.size();i+=2) {
Edge e(p_connections[i],p_connections[i+1]);
ERR_FAIL_INDEX(e.points[0],point_count);
ERR_FAIL_INDEX(e.points[1],point_count);
points[p_connections[i]].connections.insert(p_connections[i+1]);
points[p_connections[i+1]].connections.insert(p_connections[i]);
edges.insert(e);
}
//fill the remaining connections based on visibility
for(int i=0;i<point_count;i++) {
for(int j=i+1;j<point_count;j++) {
if (edges.has(Edge(i,j)))
continue; //if in edge ignore
Vector2 from=points[i].pos;
Vector2 to=points[j].pos;
if (!_is_point_inside(from*0.5+to*0.5)) //connection between points in inside space
continue;
bool valid=true;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
const Edge& e=E->get();
if (e.points[0]==i || e.points[1]==i || e.points[0]==j || e.points[1]==j )
continue;
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
if (Geometry::segment_intersects_segment_2d(a,b,from,to,NULL)) {
valid=false;
break;
}
}
if (valid) {
points[i].connections.insert(j);
points[j].connections.insert(i);
}
}
}
}
Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector2& p_to) {
Vector<Vector2> path;
if (!_is_point_inside(p_from))
return path;
if (!_is_point_inside(p_to))
return path;
//test direct connection
{
bool can_see_eachother=true;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
const Edge& e=E->get();
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
if (Geometry::segment_intersects_segment_2d(a,b,p_from,p_to,NULL)) {
can_see_eachother=false;
break;
}
}
if (can_see_eachother) {
path.push_back(p_from);
path.push_back(p_to);
return path;
}
}
//add to graph
int aidx = points.size()-2;
int bidx = points.size()-1;
points[aidx].pos=p_from;
points[bidx].pos=p_to;
points[aidx].distance=0;
points[bidx].distance=0;
points[aidx].distance=0;
points[bidx].distance=0;
for(int i=0;i<points.size()-2;i++) {
bool valid_a=true;
bool valid_b=true;
points[i].prev=-1;
points[i].distance=0;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
const Edge& e=E->get();
if (e.points[0]==i || e.points[1]==i)
continue;
Vector2 a = points[e.points[0]].pos;
Vector2 b = points[e.points[1]].pos;
if (valid_a) {
if (Geometry::segment_intersects_segment_2d(a,b,p_from,points[i].pos,NULL)) {
valid_a=false;
}
}
if (valid_b) {
if (Geometry::segment_intersects_segment_2d(a,b,p_to,points[i].pos,NULL)) {
valid_b=false;
}
}
if (!valid_a && !valid_b)
continue;
}
if (valid_a) {
points[i].connections.insert(aidx);
points[aidx].connections.insert(i);
}
if (valid_b) {
points[i].connections.insert(bidx);
points[bidx].connections.insert(i);
}
}
//solve graph
Set<int> open_list;
points[aidx].distance=0;
points[aidx].prev=aidx;
for(Set<int>::Element *E=points[aidx].connections.front();E;E=E->next()) {
open_list.insert(E->get());
points[E->get()].distance=p_from.distance_to(points[E->get()].pos);
points[E->get()].prev=aidx;
}
bool found_route=false;
while(true) {
if (open_list.size()==0) {
break;
}
//check open list
int least_cost_point=-1;
float least_cost=1e30;
//this could be faster (cache previous results)
for (Set<int>::Element *E=open_list.front();E;E=E->next()) {
const Point& p =points[E->get()];
float cost = p.distance;
cost+=p.pos.distance_to(p_to);
if (cost<least_cost) {
least_cost_point=E->get();
least_cost=cost;
}
}
Point &np = points[least_cost_point];
//open the neighbours for search
for(Set<int>::Element *E=np.connections.front();E;E=E->next()) {
Point& p =points[E->get()];
float distance = np.pos.distance_to(p.pos) + np.distance;
if (p.prev!=-1) {
//oh this was visited already, can we win the cost?
if (p.distance>distance) {
p.prev=least_cost_point; //reasign previous
p.distance=distance;
}
} else {
//add to open neighbours
p.prev=least_cost_point;
p.distance=distance;
open_list.insert(E->get());
if (E->get()==bidx) {
//oh my reached end! stop algorithm
found_route=true;
break;
}
}
}
if (found_route)
break;
open_list.erase(least_cost_point);
}
if (found_route) {
int at = bidx;
path.push_back(points[at].pos);
do {
at=points[at].prev;
path.push_back(points[at].pos);
} while (at!=aidx);
path.invert();;
}
for(int i=0;i<points.size()-2;i++) {
points[i].connections.erase(aidx);
points[i].connections.erase(bidx);
points[i].prev=-1;
points[i].distance=0;
}
points[aidx].connections.clear();
points[aidx].prev=-1;
points[aidx].distance=0;
points[bidx].connections.clear();
points[bidx].prev=-1;
points[bidx].distance=0;
return path;
}
void PolygonPathFinder::_set_data(const Dictionary& p_data) {
ERR_FAIL_COND(!p_data.has("points"));
ERR_FAIL_COND(!p_data.has("connections"));
ERR_FAIL_COND(!p_data.has("segments"));
DVector<Vector2> p=p_data["points"];
Array c=p_data["connections"];
ERR_FAIL_COND(c.size()!=p.size());
if (c.size())
return;
int pc = p.size();
points.resize(pc+2);
DVector<Vector2>::Read pr=p.read();
for(int i=0;i<pc;i++) {
points[i].pos=pr[i];
DVector<int> con=c[i];
DVector<int>::Read cr=con.read();
int cc=con.size();
for(int j=0;j<cc;j++) {
points[i].connections.insert(cr[j]);
}
}
DVector<int> segs=p_data["segments"];
int sc=segs.size();
ERR_FAIL_COND(sc&1);
DVector<int>::Read sr = segs.read();
for(int i=0;i<sc;i+=2) {
Edge e(sr[i],sr[i+1]);
edges.insert(e);
}
}
Dictionary PolygonPathFinder::_get_data() const{
Dictionary d;
DVector<Vector2> p;
DVector<int> ind;
Array connections;
p.resize(points.size()-2);
connections.resize(points.size()-2);
ind.resize(edges.size()*2);
{
DVector<Vector2>::Write wp=p.write();
for(int i=0;i<points.size()-2;i++) {
wp[i]=points[i].pos;
DVector<int> c;
c.resize(points[i].connections.size());
{
DVector<int>::Write cw=c.write();
int idx=0;
for (Set<int>::Element *E=points[i].connections.front();E;E=E->next()) {
cw[idx++]=E->get();
}
}
connections[i]=c;
}
}
{
DVector<int>::Write iw=ind.write();
int idx=0;
for (Set<Edge>::Element *E=edges.front();E;E=E->next()) {
iw[idx++]=E->get().points[0];
iw[idx++]=E->get().points[1];
}
}
d["points"]=p;
d["connections"]=connections;
d["segments"]=ind;
return d;
}
void PolygonPathFinder::_bind_methods() {
ObjectTypeDB::bind_method(_MD("setup","points","connections"),&PolygonPathFinder::setup);
ObjectTypeDB::bind_method(_MD("find_path","from","to"),&PolygonPathFinder::find_path);
ObjectTypeDB::bind_method(_MD("_set_data"),&PolygonPathFinder::_set_data);
ObjectTypeDB::bind_method(_MD("_get_data"),&PolygonPathFinder::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data"));
}
PolygonPathFinder::PolygonPathFinder()
{
}

View File

@ -0,0 +1,58 @@
#ifndef POLYGON_PATH_FINDER_H
#define POLYGON_PATH_FINDER_H
#include "resource.h"
class PolygonPathFinder : public Resource {
OBJ_TYPE(PolygonPathFinder,Resource);
struct Point {
Vector2 pos;
Set<int> connections;
float distance;
int prev;
};
struct Edge {
int points[2];
_FORCE_INLINE_ bool operator<(const Edge& p_edge) const {
if (points[0]==p_edge.points[0])
return points[1]<p_edge.points[1];
else
return points[0]<p_edge.points[0];
}
Edge(int a=0, int b=0) {
if (a>b) {
SWAP(a,b);
}
}
};
Vector2 outside_point;
Vector<Point> points;
Set<Edge> edges;
bool _is_point_inside(const Vector2& p_point);
void _set_data(const Dictionary& p_data);
Dictionary _get_data() const;
protected:
static void _bind_methods();
public:
void setup(const Vector<Vector2>& p_points, const Vector<int>& p_connections);
Vector<Vector2> find_path(const Vector2& p_from, const Vector2& p_to);
PolygonPathFinder();
};
#endif // POLYGON_PATH_FINDER_H