2012-04-05 23:09:41 +00:00
//
// KRPointLight.cpp
// KREngine
//
// Created by Kearwood Gilbert on 12-04-05.
// Copyright (c) 2012 Kearwood Software. All rights reserved.
//
# include <iostream>
2012-06-10 06:24:04 +00:00
# include <math.h>
2012-04-05 23:09:41 +00:00
# import "KRPointLight.h"
2012-04-26 09:06:45 +00:00
# import "KRMat4.h"
# import "KRVector3.h"
# import "KRCamera.h"
# import "KRContext.h"
# import "KRBoundingVolume.h"
2012-09-19 20:26:30 +00:00
# import "KRStockGeometry.h"
2012-09-13 20:09:19 +00:00
# import "assert.h"
2012-04-05 23:09:41 +00:00
2012-08-29 21:43:11 +00:00
KRPointLight : : KRPointLight ( KRScene & scene , std : : string name ) : KRLight ( scene , name )
2012-04-05 23:09:41 +00:00
{
2012-04-26 09:06:45 +00:00
m_sphereVertices = NULL ;
m_cVertices = 0 ;
2012-04-05 23:09:41 +00:00
}
KRPointLight : : ~ KRPointLight ( )
{
2012-04-26 09:06:45 +00:00
if ( m_sphereVertices ) {
delete m_sphereVertices ;
m_cVertices = 0 ;
}
2012-04-05 23:09:41 +00:00
}
2012-04-12 00:43:53 +00:00
std : : string KRPointLight : : getElementName ( ) {
return " point_light " ;
}
2012-04-26 09:06:45 +00:00
# if TARGET_OS_IPHONE
2012-09-11 03:06:35 +00:00
void KRPointLight : : render ( KRCamera * pCamera , KRContext * pContext , KRBoundingVolume & frustrumVolume , KRMat4 & viewMatrix , KRVector3 & cameraPosition , KRVector3 & lightDirection , KRMat4 * pShadowMatrices , GLuint * shadowDepthTextures , int cShadowBuffers , KRNode : : RenderPass renderPass ) {
2012-04-26 09:06:45 +00:00
2012-09-11 03:06:35 +00:00
KRLight : : render ( pCamera , pContext , frustrumVolume , viewMatrix , cameraPosition , lightDirection , pShadowMatrices , shadowDepthTextures , cShadowBuffers , renderPass ) ;
2012-06-15 00:05:56 +00:00
2012-09-11 07:23:54 +00:00
bool bVisualize = renderPass = = KRNode : : RENDER_PASS_FORWARD_TRANSPARENT & & pCamera - > bShowDeferred ;
if ( renderPass = = KRNode : : RENDER_PASS_DEFERRED_LIGHTS | | bVisualize ) {
2012-04-26 09:06:45 +00:00
// Lights are rendered on the second pass of the deferred renderer
2012-06-15 00:05:56 +00:00
2012-04-26 09:06:45 +00:00
KRMat4 projectionMatrix = pCamera - > getProjectionMatrix ( ) ;
KRVector3 light_position = getLocalTranslation ( ) ;
float influence_radius = sqrt ( ( m_intensity / 100.0 ) / KRLIGHT_MIN_INFLUENCE - 1.0 ) + m_decayStart ;
m_modelMatrix = KRMat4 ( ) ;
m_modelMatrix . scale ( influence_radius ) ;
m_modelMatrix . translate ( light_position . x , light_position . y , light_position . z ) ;
KRMat4 mvpmatrix = m_modelMatrix * viewMatrix * projectionMatrix ;
KRMat4 matModelToView = viewMatrix * m_modelMatrix ;
matModelToView . transpose ( ) ;
matModelToView . invert ( ) ;
2012-06-15 00:05:56 +00:00
2012-04-26 09:06:45 +00:00
KRMat4 matModelToView2 = KRMat4 ( ) * m_modelMatrix * viewMatrix ;
KRMat4 matViewToModel = m_modelMatrix * viewMatrix ;
matViewToModel . invert ( ) ;
2012-06-10 06:38:31 +00:00
KRVector3 view_space_light_position = KRMat4 : : Dot ( matModelToView2 , KRVector3 : : Zero ( ) ) ; // Origin point of model space is the light source position. No perspective, so no w divide required
2012-04-26 09:06:45 +00:00
KRBoundingVolume influence_extents = KRBoundingVolume ( KRVector3 ( - 1.0 ) , KRVector3 ( 1.0 ) , m_modelMatrix ) ;
KRBoundingVolume frustrumVolumeNoNearClip = KRBoundingVolume ( viewMatrix , pCamera - > perspective_fov , pCamera - > m_viewportSize . x / pCamera - > m_viewportSize . y , 0.0 , pCamera - > perspective_farz ) ;
if ( influence_extents . test_intersect ( frustrumVolumeNoNearClip ) ) {
// Cull out any lights not within the view frustrum
2012-09-11 06:45:02 +00:00
KRVector3 view_light_position = KRMat4 : : Dot ( viewMatrix , light_position ) ;
bool bInsideLight = view_light_position . sqrMagnitude ( ) < = ( influence_radius + pCamera - > perspective_nearz ) * ( influence_radius + pCamera - > perspective_nearz ) ;
2012-09-11 07:23:54 +00:00
KRShader * pShader = pContext - > getShaderManager ( ) - > getShader ( bVisualize ? " visualize_overlay " : ( bInsideLight ? " light_point_inside " : " light_point " ) , pCamera , false , false , false , 0 , false , false , false , false , false , false , false , false , false , renderPass ) ;
2012-06-14 19:33:17 +00:00
pShader - > bind ( pCamera , matModelToView , mvpmatrix , cameraPosition , lightDirection , pShadowMatrices , shadowDepthTextures , 0 , renderPass ) ;
2012-09-11 07:23:54 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform3f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_COLOR ] ,
m_color . x ,
m_color . y ,
m_color . z
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform1f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_INTENSITY ] ,
m_intensity / 100.0f
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform1f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_DECAY_START ] ,
getDecayStart ( )
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform1f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_CUTOFF ] ,
KRLIGHT_MIN_INFLUENCE
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform3f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_POSITION ] ,
light_position . x ,
light_position . y ,
light_position . z
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniform3f (
2012-04-26 09:06:45 +00:00
pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_LIGHT_POSITION_VIEW_SPACE ] ,
view_space_light_position . x ,
view_space_light_position . y ,
view_space_light_position . z
2012-09-13 20:09:19 +00:00
) ) ;
2012-04-26 09:06:45 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniformMatrix4fv ( pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_V2M ] , 1 , GL_FALSE , matViewToModel . getPointer ( ) ) ) ;
GLDEBUG ( glUniformMatrix4fv ( pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_M2V ] , 1 , GL_FALSE , matModelToView2 . getPointer ( ) ) ) ;
2012-04-26 09:06:45 +00:00
KRMat4 matInvProjection ;
matInvProjection = pCamera - > getProjectionMatrix ( ) ;
matInvProjection . invert ( ) ;
2012-09-13 20:09:19 +00:00
GLDEBUG ( glUniformMatrix4fv ( pShader - > m_uniforms [ KRShader : : KRENGINE_UNIFORM_INVP ] , 1 , GL_FALSE , matInvProjection . getPointer ( ) ) ) ;
2012-04-26 09:06:45 +00:00
2012-09-11 07:23:54 +00:00
if ( bVisualize ) {
// Enable additive blending
2012-09-13 20:09:19 +00:00
GLDEBUG ( glEnable ( GL_BLEND ) ) ;
GLDEBUG ( glBlendFunc ( GL_ONE , GL_ONE ) ) ;
2012-09-11 07:23:54 +00:00
}
2012-04-26 09:06:45 +00:00
// Disable z-buffer write
2012-09-13 20:09:19 +00:00
GLDEBUG ( glDepthMask ( GL_FALSE ) ) ;
2012-04-26 09:06:45 +00:00
2012-09-19 20:26:30 +00:00
2012-09-11 06:45:02 +00:00
if ( bInsideLight ) {
// Disable z-buffer test
2012-09-13 20:09:19 +00:00
GLDEBUG ( glDisable ( GL_DEPTH_TEST ) ) ;
2012-09-11 06:45:02 +00:00
// Render a full screen quad
2012-09-19 20:26:30 +00:00
m_pContext - > getModelManager ( ) - > bindVBO ( ( void * ) KRENGINE_VBO_2D_SQUARE , KRENGINE_VBO_2D_SQUARE_SIZE , true , false , false , true , false ) ;
2012-09-13 20:09:19 +00:00
GLDEBUG ( glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ) ;
2012-09-11 06:45:02 +00:00
} else {
2012-09-19 20:26:30 +00:00
m_pContext - > getModelManager ( ) - > configureAttribs ( true , false , false , false , false ) ;
2012-09-11 06:45:02 +00:00
// Render sphere of light's influence
generateMesh ( ) ;
2012-04-26 09:06:45 +00:00
2012-09-11 06:45:02 +00:00
// Enable z-buffer test
2012-09-13 20:09:19 +00:00
GLDEBUG ( glEnable ( GL_DEPTH_TEST ) ) ;
GLDEBUG ( glDepthFunc ( GL_LEQUAL ) ) ;
GLDEBUG ( glDepthRangef ( 0.0 , 1.0 ) ) ;
2012-09-11 06:45:02 +00:00
2012-09-13 20:09:19 +00:00
GLDEBUG ( glVertexAttribPointer ( KRShader : : KRENGINE_ATTRIB_VERTEX , 3 , GL_FLOAT , 0 , 0 , m_sphereVertices ) ) ;
GLDEBUG ( glDrawArrays ( GL_TRIANGLES , 0 , m_cVertices ) ) ;
2012-09-11 06:45:02 +00:00
}
2012-09-11 07:23:54 +00:00
if ( bVisualize ) {
// Enable alpha blending
2012-09-13 20:09:19 +00:00
GLDEBUG ( glEnable ( GL_BLEND ) ) ;
GLDEBUG ( glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ) ;
2012-09-11 07:23:54 +00:00
}
2012-04-26 09:06:45 +00:00
}
}
}
void KRPointLight : : generateMesh ( ) {
// Create a triangular facet approximation to a sphere
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
int iterations = 3 ;
int facet_count = pow ( 4 , iterations ) * 8 ;
if ( m_cVertices ! = facet_count * 3 ) {
if ( m_sphereVertices ) {
free ( m_sphereVertices ) ;
m_sphereVertices = NULL ;
}
m_cVertices = facet_count * 3 ;
class Facet3 {
public :
Facet3 ( ) {
}
~ Facet3 ( ) {
}
KRVector3 p1 ;
KRVector3 p2 ;
KRVector3 p3 ;
} ;
std : : vector < Facet3 > f = std : : vector < Facet3 > ( facet_count ) ;
int i , it ;
double a ;
KRVector3 p [ 6 ] = {
KRVector3 ( 0 , 0 , 1 ) ,
KRVector3 ( 0 , 0 , - 1 ) ,
KRVector3 ( - 1 , - 1 , 0 ) ,
KRVector3 ( 1 , - 1 , 0 ) ,
KRVector3 ( 1 , 1 , 0 ) ,
KRVector3 ( - 1 , 1 , 0 )
} ;
KRVector3 pa , pb , pc ;
int nt = 0 , ntold ;
/* Create the level 0 object */
a = 1 / sqrt ( 2.0 ) ;
for ( i = 0 ; i < 6 ; i + + ) {
p [ i ] . x * = a ;
p [ i ] . y * = a ;
}
f [ 0 ] . p1 = p [ 0 ] ; f [ 0 ] . p2 = p [ 3 ] ; f [ 0 ] . p3 = p [ 4 ] ;
f [ 1 ] . p1 = p [ 0 ] ; f [ 1 ] . p2 = p [ 4 ] ; f [ 1 ] . p3 = p [ 5 ] ;
f [ 2 ] . p1 = p [ 0 ] ; f [ 2 ] . p2 = p [ 5 ] ; f [ 2 ] . p3 = p [ 2 ] ;
f [ 3 ] . p1 = p [ 0 ] ; f [ 3 ] . p2 = p [ 2 ] ; f [ 3 ] . p3 = p [ 3 ] ;
f [ 4 ] . p1 = p [ 1 ] ; f [ 4 ] . p2 = p [ 4 ] ; f [ 4 ] . p3 = p [ 3 ] ;
f [ 5 ] . p1 = p [ 1 ] ; f [ 5 ] . p2 = p [ 5 ] ; f [ 5 ] . p3 = p [ 4 ] ;
f [ 6 ] . p1 = p [ 1 ] ; f [ 6 ] . p2 = p [ 2 ] ; f [ 6 ] . p3 = p [ 5 ] ;
f [ 7 ] . p1 = p [ 1 ] ; f [ 7 ] . p2 = p [ 3 ] ; f [ 7 ] . p3 = p [ 2 ] ;
nt = 8 ;
/* Bisect each edge and move to the surface of a unit sphere */
for ( it = 0 ; it < iterations ; it + + ) {
ntold = nt ;
for ( i = 0 ; i < ntold ; i + + ) {
pa . x = ( f [ i ] . p1 . x + f [ i ] . p2 . x ) / 2 ;
pa . y = ( f [ i ] . p1 . y + f [ i ] . p2 . y ) / 2 ;
pa . z = ( f [ i ] . p1 . z + f [ i ] . p2 . z ) / 2 ;
pb . x = ( f [ i ] . p2 . x + f [ i ] . p3 . x ) / 2 ;
pb . y = ( f [ i ] . p2 . y + f [ i ] . p3 . y ) / 2 ;
pb . z = ( f [ i ] . p2 . z + f [ i ] . p3 . z ) / 2 ;
pc . x = ( f [ i ] . p3 . x + f [ i ] . p1 . x ) / 2 ;
pc . y = ( f [ i ] . p3 . y + f [ i ] . p1 . y ) / 2 ;
pc . z = ( f [ i ] . p3 . z + f [ i ] . p1 . z ) / 2 ;
pa . normalize ( ) ;
pb . normalize ( ) ;
pc . normalize ( ) ;
f [ nt ] . p1 = f [ i ] . p1 ; f [ nt ] . p2 = pa ; f [ nt ] . p3 = pc ; nt + + ;
f [ nt ] . p1 = pa ; f [ nt ] . p2 = f [ i ] . p2 ; f [ nt ] . p3 = pb ; nt + + ;
f [ nt ] . p1 = pb ; f [ nt ] . p2 = f [ i ] . p3 ; f [ nt ] . p3 = pc ; nt + + ;
f [ i ] . p1 = pa ;
f [ i ] . p2 = pb ;
f [ i ] . p3 = pc ;
}
}
m_sphereVertices = ( GLfloat * ) malloc ( sizeof ( GLfloat ) * m_cVertices * 3 ) ;
GLfloat * pDest = m_sphereVertices ;
for ( int facet_index = 0 ; facet_index < facet_count ; facet_index + + ) {
* pDest + + = f [ facet_index ] . p1 . x ;
* pDest + + = f [ facet_index ] . p1 . y ;
* pDest + + = f [ facet_index ] . p1 . z ;
* pDest + + = f [ facet_index ] . p2 . x ;
* pDest + + = f [ facet_index ] . p2 . y ;
* pDest + + = f [ facet_index ] . p2 . z ;
* pDest + + = f [ facet_index ] . p3 . x ;
* pDest + + = f [ facet_index ] . p3 . y ;
* pDest + + = f [ facet_index ] . p3 . z ;
}
}
}
# endif