00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "polylightEffect.h"
00016 #include "polylightNode.h"
00017 #include "config_pgraph.h"
00018 #include "nodePath.h"
00019 #include "pmap.h"
00020 #include "colorScaleAttrib.h"
00021 #include "cullTraverserData.h"
00022 #include "cullTraverser.h"
00023
00024 #include <math.h>
00025
00026 TypeHandle PolylightEffect::_type_handle;
00027
00028
00029
00030
00031
00032
00033 CPT(RenderEffect) PolylightEffect::
00034 make() {
00035 PolylightEffect *effect = new PolylightEffect;
00036 effect->_contribution_type = CT_proximal;
00037 effect->_weight = 1.0;
00038 effect->_effect_center = LPoint3(0.0,0.0,0.0);
00039 return return_new(effect);
00040 }
00041
00042
00043
00044
00045
00046
00047 CPT(RenderEffect) PolylightEffect::
00048 make(PN_stdfloat weight, ContribType contrib, const LPoint3 &effect_center) {
00049 PolylightEffect *effect = new PolylightEffect;
00050 effect->_contribution_type = contrib;
00051 effect->_weight = weight;
00052 effect->_effect_center = effect_center;
00053 return return_new(effect);
00054 }
00055
00056
00057
00058
00059
00060
00061 CPT(RenderEffect) PolylightEffect::
00062 make(PN_stdfloat weight, ContribType contrib, const LPoint3 &effect_center,
00063 const LightGroup &lights) {
00064 PolylightEffect *effect = new PolylightEffect;
00065 effect->_contribution_type = contrib;
00066 effect->_weight = weight;
00067 effect->_effect_center = effect_center;
00068 effect->_lightgroup = lights;
00069 return return_new(effect);
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 bool PolylightEffect::
00082 has_cull_callback() const {
00083 return !_lightgroup.empty();
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 void PolylightEffect::
00104 cull_callback(CullTraverser *trav, CullTraverserData &data,
00105 CPT(TransformState) &node_transform,
00106 CPT(RenderState) &node_state) const {
00107
00108 CPT(RenderAttrib) poly_light_attrib = do_poly_light(trav->get_scene(), &data, node_transform);
00109 CPT(RenderState) poly_light_state = RenderState::make(poly_light_attrib);
00110 node_state = node_state->compose(poly_light_state);
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 CPT(RenderAttrib) PolylightEffect::
00124 do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const TransformState *node_transform) const {
00125
00126 PN_stdfloat dist;
00127 PN_stdfloat r,g,b;
00128 PN_stdfloat min_dist;
00129 int num_lights = 0;
00130 PN_stdfloat light_scale;
00131 PN_stdfloat weight_scale = 1.0f;
00132 PN_stdfloat Rcollect, Gcollect, Bcollect;
00133
00134 const NodePath &root = scene->get_scene_root();
00135
00136 const NodePath &camera = scene->get_cull_center();
00137
00138
00139 r = g = b = 1.0;
00140 Rcollect = Gcollect = Bcollect = 0.0;
00141
00142
00143 LColor scene_color = root.get_color_scale();
00144 if (polylight_info) {
00145 pgraph_cat.debug() << "scene color scale = " << scene_color << endl;
00146 }
00147 min_dist = 100000.0;
00148
00149 LightGroup::const_iterator light_iter;
00150 for (light_iter = _lightgroup.begin(); light_iter != _lightgroup.end(); light_iter++){
00151 const PolylightNode *light = DCAST(PolylightNode, (*light_iter).node());
00152
00153
00154 if (light->is_enabled()) {
00155 PN_stdfloat light_radius = light->get_radius();
00156
00157
00158 const NodePath lightnp = *light_iter;
00159 LPoint3 relative_point = data->_node_path.get_node_path().get_relative_point(lightnp, light->get_pos());
00160
00161 if (_effect_center[2]) {
00162 dist = (relative_point - _effect_center).length();
00163 } else {
00164
00165 LVector2 xz(relative_point[0], relative_point[1]);
00166 dist = xz.length();
00167 }
00168
00169 if (dist <= light_radius) {
00170
00171 LPoint3 light_position = light->get_pos();
00172
00173 LPoint3 camera_position = lightnp.get_relative_point(camera, LPoint3(0,0,0));
00174 LPoint3 avatar_position = lightnp.get_relative_point(data->_node_path.get_node_path(), LPoint3(0,0,0));
00175 LVector3 light_camera = camera_position - light_position;
00176 LVector3 light_avatar = avatar_position - light_position;
00177 light_camera.normalize();
00178 light_avatar.normalize();
00179 PN_stdfloat intensity = light_camera.dot(light_avatar);
00180
00181 if (polylight_info) {
00182 pgraph_cat.debug() << "light position = " << light_position << endl;
00183 pgraph_cat.debug() << "relative avatar position = " << avatar_position << endl;
00184 pgraph_cat.debug() << "relative camera position = " << camera_position << endl;
00185 pgraph_cat.debug() << "light->camera " << light_camera << endl;
00186 pgraph_cat.debug() << "light->avatar " << light_avatar << endl;
00187 pgraph_cat.debug() << "light->camera.light->avatar = " << intensity << endl;
00188 pgraph_cat.debug() << "effect center = " << _effect_center << endl;
00189
00190 pgraph_cat.debug() << "dist = " << dist << ";radius = " << light_radius << endl;
00191 }
00192
00193
00194 intensity = 1.0 - ((intensity + 1.0) * 0.5);
00195 if (polylight_info) {
00196 pgraph_cat.debug() << "remapped intensity = " << intensity << endl;
00197 }
00198
00199 PolylightNode::Attenuation_Type light_attenuation = light->get_attenuation();
00200 LColor light_color;
00201 if (light->is_flickering()) {
00202 light_color = light->flicker();
00203 } else {
00204 light_color = light->get_color();
00205
00206 }
00207
00208 PN_stdfloat ratio = dist/light_radius;
00209 if (light_attenuation == PolylightNode::ALINEAR) {
00210 light_scale = 1.0 - ratio;
00211 } else if (light_attenuation == PolylightNode::AQUADRATIC) {
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 ratio = 1 - ratio;
00229 if (ratio <= 0.8)
00230 light_scale = (ratio*ratio)*(3-2*ratio);
00231 else
00232 light_scale = 1.0;
00233 } else {
00234 light_scale = 1.0;
00235 }
00236
00237 light_scale *= intensity;
00238
00239 if (min_dist > dist) {
00240 min_dist = dist;
00241
00242
00243
00244
00245 weight_scale = _weight * (1.0 - light_scale);
00246 }
00247
00248 if (polylight_info) {
00249 pgraph_cat.debug() << "weight_scale = " << weight_scale
00250 << "; light_scale " << light_scale << endl;
00251 }
00252
00253 Rcollect += light_color[0] * light_scale;
00254 Gcollect += light_color[1] * light_scale;
00255 Bcollect += light_color[2] * light_scale;
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 num_lights++;
00269 }
00270 }
00271 }
00272
00273 if ( _contribution_type == CT_all) {
00274
00275
00276
00277 num_lights = _lightgroup.size();
00278 }
00279
00280 if (num_lights) {
00281
00282
00283 if (polylight_info)
00284 pgraph_cat.debug() << "num lights = " << num_lights << endl;
00285
00286
00287 r = Rcollect;
00288 g = Gcollect;
00289 b = Bcollect;
00290
00291 if (polylight_info)
00292 pgraph_cat.debug() << "avg: r=" << r << "; g=" << g << "; b=" << b << endl;
00293
00294
00295 r += scene_color[0] * weight_scale;
00296 g += scene_color[1] * weight_scale;
00297 b += scene_color[2] * weight_scale;
00298 if (polylight_info)
00299 pgraph_cat.debug() << "weighed: r=" << r << "; g=" << g << "; b=" << b << endl;
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 r = (r > 1.0)? 1.0 : r;
00315 g = (g > 1.0)? 1.0 : g;
00316 b = (b > 1.0)? 1.0 : b;
00317
00318 if (polylight_info)
00319 pgraph_cat.debug() << "capped: r=" << r << "; g=" << g << "; b=" << b << endl;
00320
00321
00322
00323
00324 if (scene_color[0] >= 0.01)
00325 r /= scene_color[0];
00326 if (scene_color[1] >= 0.01)
00327 g /= scene_color[1];
00328 if (scene_color[2] >= 0.01)
00329 b /= scene_color[2];
00330
00331 if (polylight_info)
00332 pgraph_cat.debug() << "final: r=" << r << "; g=" << g << "; b=" << b << endl;
00333
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 return ColorScaleAttrib::make(LVecBase4(r, g, b, 1.0));
00347 }
00348
00349
00350
00351
00352
00353
00354 void PolylightEffect::
00355 output(ostream &out) const {
00356 out << get_type() << ":";
00357
00358 LightGroup::const_iterator li;
00359 for (li = _lightgroup.begin(); li != _lightgroup.end(); ++li) {
00360 NodePath light = (*li);
00361 out << " " << light;
00362 }
00363 out << " weight " << _weight << " contrib " << _contribution_type
00364 << " center " << _effect_center;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 int PolylightEffect::
00384 compare_to_impl(const RenderEffect *other) const {
00385 const PolylightEffect *ta;
00386 DCAST_INTO_R(ta, other, 0);
00387
00388 if (_contribution_type != ta->_contribution_type) {
00389 return _contribution_type < ta->_contribution_type ? -1 : 1;
00390 }
00391
00392 if (_weight != ta->_weight) {
00393 return _weight < ta->_weight ? -1 :1;
00394 }
00395
00396 if (_lightgroup != ta->_lightgroup) {
00397 return _lightgroup < ta->_lightgroup ? -1 : 1;
00398 }
00399
00400 return 0;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 CPT(RenderEffect) PolylightEffect::
00412 add_light(const NodePath &newlight) const {
00413 PolylightEffect *effect = new PolylightEffect(*this);
00414 effect->_lightgroup.push_back(newlight);
00415 return return_new(effect);
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425 CPT(RenderEffect) PolylightEffect::
00426 remove_light(const NodePath &newlight) const {
00427 PolylightEffect *effect = new PolylightEffect(*this);
00428 LightGroup::iterator light_iter;
00429 light_iter = find(effect->_lightgroup.begin(),effect->_lightgroup.end(), newlight);
00430 if (light_iter == effect->_lightgroup.end()) {
00431 pgraph_cat.debug()
00432 << "Attempt to remove Polylight " << newlight << "; not found.\n";
00433 } else {
00434
00435 effect->_lightgroup.erase(light_iter);
00436 }
00437 return return_new(effect);
00438
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 CPT(RenderEffect) PolylightEffect::
00451 set_weight(PN_stdfloat w) const {
00452 PolylightEffect *effect = new PolylightEffect(*this);
00453 effect->_weight = w;
00454 return return_new(effect);
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 CPT(RenderEffect) PolylightEffect::
00467 set_contrib(ContribType ct) const {
00468 PolylightEffect *effect = new PolylightEffect(*this);
00469 effect->_contribution_type = ct;
00470 return return_new(effect);
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 CPT(RenderEffect) PolylightEffect::
00483 set_effect_center(const LPoint3 &ec) const{
00484 PolylightEffect *effect = new PolylightEffect(*this);
00485 effect->_effect_center = ec;
00486 return return_new(effect);
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 bool PolylightEffect::
00496 has_light(const NodePath &light) const {
00497 LightGroup::const_iterator li;
00498 li = find(_lightgroup.begin(), _lightgroup.end(), light);
00499 return (li != _lightgroup.end());
00500 }
00501
00502 ostream &
00503 operator << (ostream &out, PolylightEffect::ContribType ct) {
00504 switch (ct) {
00505 case PolylightEffect::CT_proximal:
00506 return out << "proximal";
00507
00508 case PolylightEffect::CT_all:
00509 return out << "all";
00510 }
00511
00512 return out << "**Invalid ContribType(" << (int)ct << ")**";
00513 }