framework2
478 строк · 13.3 Кб
1/*
2* ofLight.cpp
3* openFrameworksLib
4*
5* Created by Memo Akten on 14/01/2011.
6* Copyright 2011 MSA Visuals Ltd. All rights reserved.
7*
8*/
9
10
11#include "ofLight.h"
12#include "of3dUtils.h"
13#include "ofGLBaseTypes.h"
14#include "ofGLUtils.h"
15#include "ofConstants.h"
16#include "ofColor.h"
17#include <glm/gtc/quaternion.hpp>
18#include <map>
19
20using std::weak_ptr;
21using std::vector;
22
23static ofFloatColor globalAmbient(0.2, 0.2, 0.2, 1.0);
24
25//----------------------------------------
26void ofEnableLighting() {
27ofGetGLRenderer()->enableLighting();
28}
29
30//----------------------------------------
31void ofDisableLighting() {
32ofGetGLRenderer()->disableLighting();
33}
34
35//----------------------------------------
36void ofEnableSeparateSpecularLight(){
37ofGetGLRenderer()->enableSeparateSpecularLight();
38}
39
40//----------------------------------------
41void ofDisableSeparateSpecularLight(){
42ofGetGLRenderer()->disableSeparateSpecularLight();
43}
44
45//----------------------------------------
46bool ofGetLightingEnabled() {
47return ofGetGLRenderer()->getLightingEnabled();
48}
49
50//----------------------------------------
51void ofSetSmoothLighting(bool b) {
52ofGetGLRenderer()->setSmoothLighting(b);
53}
54
55//----------------------------------------
56void ofSetGlobalAmbientColor(const ofFloatColor& c) {
57ofGetGLRenderer()->setGlobalAmbientColor(c);
58globalAmbient = c;
59}
60
61const ofFloatColor & ofGetGlobalAmbientColor(){
62return globalAmbient;
63}
64
65//----------------------------------------
66vector<weak_ptr<ofLight::Data> > & ofLightsData(){
67static vector<weak_ptr<ofLight::Data> > * lightsActive = ofIsGLProgrammableRenderer()?new vector<weak_ptr<ofLight::Data> >:new vector<weak_ptr<ofLight::Data> >(8);
68return *lightsActive;
69}
70
71ofLight::Data::Data(){
72glIndex = -1;
73isEnabled = false;
74attenuation_constant = 0.000001;
75attenuation_linear = 0.000001;
76attenuation_quadratic = 0.000001;
77spotCutOff = 45;
78exponent = 16;
79width = 1;
80height = 1;
81lightType = OF_LIGHT_POINT;
82}
83
84ofLight::Data::~Data(){
85if(glIndex==-1) return;
86if ( auto r = rendererP.lock() ){
87r->setLightAmbientColor( glIndex, ofColor( 0, 0, 0, 255 ) );
88r->setLightDiffuseColor( glIndex, ofColor( 0, 0, 0, 255 ) );
89r->setLightSpecularColor( glIndex, ofColor( 0, 0, 0, 255 ) );
90r->setLightPosition( glIndex, glm::vec4( 0, 0, 1, 0 ) );
91r->disableLight( glIndex );
92}
93}
94
95//----------------------------------------
96ofLight::ofLight()
97:data(new Data){
98setAmbientColor(ofColor(0,0,0));
99setDiffuseColor(ofColor(255,255,255));
100setSpecularColor(ofColor(255,255,255));
101setPointLight();
102
103// assume default attenuation factors //
104setAttenuation(1.f,0.f,0.f);
105}
106
107//----------------------------------------
108void ofLight::setup() {
109if(data->glIndex==-1){
110bool bLightFound = false;
111// search for the first free block
112for(size_t i=0; i<ofLightsData().size(); i++) {
113if(ofLightsData()[i].expired()) {
114data->glIndex = i;
115data->isEnabled = true;
116ofLightsData()[i] = data;
117bLightFound = true;
118break;
119}
120}
121if(!bLightFound && ofIsGLProgrammableRenderer()){
122ofLightsData().push_back(data);
123data->glIndex = ofLightsData().size() - 1;
124data->isEnabled = true;
125bLightFound = true;
126}
127if( bLightFound ){
128// run this the first time, since it was not found before //
129data->rendererP = ofGetGLRenderer();
130onPositionChanged();
131setAmbientColor( getAmbientColor() );
132setDiffuseColor( getDiffuseColor() );
133setSpecularColor( getSpecularColor() );
134setAttenuation( getAttenuationConstant(), getAttenuationLinear(), getAttenuationQuadratic() );
135if(getIsSpotlight()) {
136setSpotlightCutOff(getSpotlightCutOff());
137setSpotConcentration(getSpotConcentration());
138}
139if(getIsSpotlight() || getIsDirectional() || getIsAreaLight()) {
140onOrientationChanged();
141}
142}else{
143ofLogError("ofLight") << "setup(): couldn't get active GL light, maximum number of "<< ofLightsData().size() << " reached";
144}
145}
146}
147
148//----------------------------------------
149void ofLight::enable() {
150setup();
151data->isEnabled = true;
152onPositionChanged(); // update the position //
153onOrientationChanged();
154if ( auto r = data->rendererP.lock() ){
155r->enableLight( data->glIndex );
156}
157}
158
159//----------------------------------------
160void ofLight::disable() {
161data->isEnabled = false;
162if ( auto r = data->rendererP.lock() ){
163r->disableLight( data->glIndex );
164}
165}
166
167//----------------------------------------
168int ofLight::getLightID() const{
169return data->glIndex;
170}
171
172//----------------------------------------
173bool ofLight::getIsEnabled() const {
174return data->isEnabled;
175}
176
177//----------------------------------------
178void ofLight::setDirectional() {
179if( data->lightType != OF_LIGHT_DIRECTIONAL ) {
180data->lightType = OF_LIGHT_DIRECTIONAL;
181onOrientationChanged();
182}
183data->lightType = OF_LIGHT_DIRECTIONAL;
184shadow.setLightType( data->lightType );
185}
186
187//----------------------------------------
188bool ofLight::getIsDirectional() const {
189return data->lightType == OF_LIGHT_DIRECTIONAL;
190}
191
192//----------------------------------------
193void ofLight::setSpotlight(float spotCutOff, float exponent) {
194if( data->lightType != OF_LIGHT_SPOT ) {
195data->lightType = OF_LIGHT_SPOT;
196onPositionChanged();
197onOrientationChanged();
198}
199data->lightType = OF_LIGHT_SPOT;
200setSpotlightCutOff( spotCutOff );
201setSpotConcentration( exponent );
202shadow.setLightType( data->lightType );
203}
204
205//----------------------------------------
206bool ofLight::getIsSpotlight() const{
207return data->lightType == OF_LIGHT_SPOT;
208}
209
210//----------------------------------------
211void ofLight::setSpotlightCutOff( float spotCutOff ) {
212data->spotCutOff = ofClamp(spotCutOff, 0, 90);
213if ( auto r = data->rendererP.lock() ){
214r->setLightSpotlightCutOff( data->glIndex, spotCutOff );
215}
216}
217
218//----------------------------------------
219float ofLight::getSpotlightCutOff() const{
220if(!getIsSpotlight()) {
221ofLogWarning("ofLight") << "getSpotlightCutOff(): light " << data->glIndex << " is not a spot light";
222}
223return data->spotCutOff;
224}
225
226//----------------------------------------
227void ofLight::setSpotConcentration( float exponent ) {
228data->exponent = ofClamp(exponent, 0, 128);
229if ( auto r = data->rendererP.lock() ){
230r->setLightSpotConcentration( data->glIndex, exponent );
231}
232}
233
234//----------------------------------------
235float ofLight::getSpotConcentration() const{
236if(!getIsSpotlight()) {
237ofLogWarning("ofLight") << "getSpotConcentration(): light " << data->glIndex << " is not a spot light";
238}
239return data->exponent;
240}
241
242//----------------------------------------
243void ofLight::setPointLight() {
244if( data->lightType != OF_LIGHT_POINT ) {
245data->lightType= OF_LIGHT_POINT;
246onPositionChanged();
247onOrientationChanged();
248}
249data->lightType = OF_LIGHT_POINT;
250shadow.setLightType( data->lightType );
251}
252
253//----------------------------------------
254bool ofLight::getIsPointLight() const{
255return data->lightType == OF_LIGHT_POINT;
256}
257
258//----------------------------------------
259void ofLight::setAttenuation( float constant, float linear, float quadratic ) {
260// falloff = 0 -> 1, 0 being least amount of fallof, 1.0 being most //
261data->attenuation_constant = constant;
262data->attenuation_linear = linear;
263data->attenuation_quadratic = quadratic;
264if ( auto r = data->rendererP.lock() ){
265r->setLightAttenuation( data->glIndex, constant, linear, quadratic );
266}
267}
268
269//----------------------------------------
270float ofLight::getAttenuationConstant() const{
271return data->attenuation_constant;
272}
273
274//----------------------------------------
275float ofLight::getAttenuationLinear() const{
276return data->attenuation_linear;
277}
278
279//----------------------------------------
280float ofLight::getAttenuationQuadratic() const{
281return data->attenuation_quadratic;
282}
283
284void ofLight::setAreaLight(float width, float height){
285if( data->lightType != OF_LIGHT_AREA ) {
286data->lightType = OF_LIGHT_AREA;
287onPositionChanged();
288onOrientationChanged();
289}
290data->lightType = OF_LIGHT_AREA;
291data->width = width;
292data->height = height;
293shadow.setLightType( data->lightType );
294shadow.setAreaLightSize( width, height );
295}
296
297bool ofLight::getIsAreaLight() const{
298return data->lightType == OF_LIGHT_AREA;
299}
300
301//----------------------------------------
302int ofLight::getType() const{
303return data->lightType;
304}
305
306//----------------------------------------
307void ofLight::setAmbientColor(const ofFloatColor& c) {
308data->ambientColor = c;
309if ( auto r = data->rendererP.lock() ){
310r->setLightAmbientColor( data->glIndex, c );
311}
312}
313
314//----------------------------------------
315void ofLight::setDiffuseColor(const ofFloatColor& c) {
316data->diffuseColor = c;
317
318if ( auto r = data->rendererP.lock() ){
319r->setLightDiffuseColor( data->glIndex, c );
320}
321}
322
323//----------------------------------------
324void ofLight::setSpecularColor(const ofFloatColor& c) {
325data->specularColor = c;
326if ( auto r = data->rendererP.lock() ){
327r->setLightSpecularColor( data->glIndex, c );
328}
329}
330
331//----------------------------------------
332ofFloatColor ofLight::getAmbientColor() const {
333return data->ambientColor;
334}
335
336//----------------------------------------
337ofFloatColor ofLight::getDiffuseColor() const {
338return data->diffuseColor;
339}
340
341//----------------------------------------
342ofFloatColor ofLight::getSpecularColor() const {
343return data->specularColor;
344}
345
346//----------------------------------------
347void ofLight::customDraw(const ofBaseRenderer * renderer) const{
348if(getIsPointLight()) {
349renderer->drawSphere( 0,0,0, 10);
350ofDrawAxis(20);
351} else if (getIsSpotlight()) {
352float coneHeight = (sin(ofDegToRad(data->spotCutOff)) * 30.f) + 1;
353float coneRadius = (cos(ofDegToRad(data->spotCutOff)) * 30.f) + 8;
354const_cast<ofBaseRenderer*>(renderer)->rotateDeg(-90,1,0,0);
355renderer->drawCone(0, -(coneHeight*.5), 0, coneHeight, coneRadius);
356} else if (getIsAreaLight()) {
357const_cast<ofBaseRenderer*>(renderer)->pushMatrix();
358renderer->drawPlane(data->width,data->height);
359const_cast<ofBaseRenderer*>(renderer)->popMatrix();
360ofDrawArrow( glm::vec3(0,0,0), glm::vec3(0,0,-30), 10 );
361} else if( getIsDirectional() ) {
362renderer->drawBox(10);
363renderer->drawArrow(glm::vec3(0,0,0),glm::vec3(0,0,-40),10);
364}else{
365renderer->drawBox(10);
366ofDrawAxis(20);
367}
368}
369
370
371//----------------------------------------
372void ofLight::onPositionChanged() {
373if(data->glIndex==-1) return;
374// if we are a positional light and not directional, update light position
375if(getIsSpotlight() || getIsPointLight() || getIsAreaLight()) {
376data->position = {getGlobalPosition().x, getGlobalPosition().y, getGlobalPosition().z, 1.f};
377if ( auto r = data->rendererP.lock() ){
378r->setLightPosition( data->glIndex, data->position );
379}
380}
381}
382
383//----------------------------------------
384void ofLight::onOrientationChanged() {
385if(data->glIndex==-1) return;
386if(getIsDirectional()) {
387// if we are a directional light and not positional, update light position (direction)
388glm::vec3 lookAtDir(glm::normalize(getGlobalOrientation() * glm::vec4(0,0,-1, 1)));
389data->position = {lookAtDir.x,lookAtDir.y,lookAtDir.z,0.f};
390data->direction = lookAtDir;
391if ( auto r = data->rendererP.lock() ){
392r->setLightPosition( data->glIndex, data->position );
393}
394}else if(getIsSpotlight() || getIsAreaLight()) {
395// determines the axis of the cone light
396glm::vec3 lookAtDir(glm::normalize(getGlobalOrientation() * glm::vec4(0,0,-1, 1)));
397data->direction = lookAtDir;
398if ( auto r = data->rendererP.lock() ){
399r->setLightSpotDirection( data->glIndex, glm::vec4( data->direction, 0.0f ) );
400}
401}
402if(getIsAreaLight()){
403data->up = getUpDir();
404data->right = getXAxis();
405}
406}
407
408//-------------------------------
409bool ofLight::shouldRenderShadowDepthPass() {
410if( !ofIsGLProgrammableRenderer() ) {
411return false;
412}
413return getIsEnabled() && shadow.getIsEnabled();
414}
415
416//-------------------------------
417int ofLight::getNumShadowDepthPasses() {
418if( !ofIsGLProgrammableRenderer() ) {
419return 0;
420}
421return shadow.getNumShadowDepthPasses();
422}
423
424//-------------------------------
425bool ofLight::beginShadowDepthPass() {
426if(!shouldRenderShadowDepthPass()) {
427return false;
428}
429shadow.update(*this);
430shadow.beginDepth();
431if( getNumShadowDepthPasses() > 1 ) {
432ofLogWarning("ofLight :: beginShadowDepthPass : shadow has more than one depth pass! Call beginShadowDepthPass( GLenum aPassIndex ) instead. ");
433return false;
434}
435return true;
436}
437
438//-------------------------------
439bool ofLight::endShadowDepthPass() {
440if(!shouldRenderShadowDepthPass()) {
441return false;
442}
443shadow.endDepth();
444if( getNumShadowDepthPasses() > 1 ) {
445ofLogWarning("ofLight :: endShadowDepthPass : shadow has more than one depth pass! Call endShadowDepthPass( GLenum aPassIndex ) instead. ");
446return false;
447}
448return true;
449}
450
451//-------------------------------
452bool ofLight::beginShadowDepthPass( GLenum aPassIndex ) {
453if(!shouldRenderShadowDepthPass()) {
454return false;
455}
456if( aPassIndex == 0 ) {
457shadow.update(*this);
458}
459if( getNumShadowDepthPasses() < 2 ) {
460shadow.beginDepth();
461} else {
462shadow.beginDepth(aPassIndex);
463}
464return true;
465}
466
467//-------------------------------
468bool ofLight::endShadowDepthPass( GLenum aPassIndex ) {
469if(!shouldRenderShadowDepthPass()) {
470return false;
471}
472if( getNumShadowDepthPasses() < 2 ) {
473shadow.endDepth();
474} else {
475shadow.endDepth(aPassIndex);
476}
477return true;
478}
479