bool LightMapGenerator::ComputeRay( Ray &vRay, ILightObject * l, int bounces, float energy, int curbounce, floatColor &color) { POTENTIAL_INTERSECTION_SORT sortedIntersections; if( curbounce < 0 )return false; if( energy <= ENERGY_CUTOFF )return false; Vec3 triVerts[3]; Vec3 Normals[ 3 ]; float meshU[ 3 ]; float meshV[ 3 ]; double t, u, v; Ray rRay; Vec3 LightOrigin; float attenuationDistance = l->GetAttenuationDistance(); //add to lightposition //check meshes IntersectWithWorld( vRay, sortedIntersections ); if( sortedIntersections.size() > 0 ) { POTENTIAL_INTERSECTION_SORT::iterator iter = sortedIntersections.begin(); PotentialIntersection &firstIntersection = iter->second; u = firstIntersection.u; v = firstIntersection.v; t = firstIntersection.t; int face = firstIntersection.faceIndex; rRay = firstIntersection.transformedRay; static CHashString meshType(_T("MeshParameterization") ); CHashString &meshName = firstIntersection.mesh; GETPARAMETERIZEDTRIANGLESMSG meshFaces; GETPARAMETERIZEDVERTICESMSG meshVertices; static DWORD msgHash_GetTriangleFaces = CHashString(_T("GetTriangleFaces")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetTriangleFaces, sizeof( GETPARAMETERIZEDTRIANGLESMSG), &meshFaces, &meshName, &meshType ); static DWORD msgHash_GetCollapsedMesh = CHashString(_T("GetCollapsedMesh")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetCollapsedMesh, sizeof( GETPARAMETERIZEDVERTICESMSG), &meshVertices, &meshName, &meshType ); if( meshFaces.outList == NULL || meshVertices.outList == NULL ) { return false; } TriangleFace &tri = (*meshFaces.outList)[ face ]; for( int a = 0; a < 3; a++ ) { Vec3 &v = (* meshVertices.outList)[ tri.index [ a ] ].originalPosition; triVerts[ a ].x = v.x; triVerts[ a ].y = v.y; triVerts[ a ].z = v.z; } //we intersected, find point of intersection, find texel it maps to, color for( int a = 0; a < 3; a++ ) { meshU[ a ] = (* meshVertices.outList)[ tri.index [ a ] ].generatedU; meshV[ a ] = (* meshVertices.outList)[ tri.index [ a ] ].generatedV; Normals[ a ] = (* meshVertices.outList)[ tri.index [ a ] ].normal; } Vec3 intersect; intersect.x = (float)(rRay.m_Origin.x + rRay.m_Direction.x*t); intersect.y = (float)(rRay.m_Origin.y + rRay.m_Direction.y*t); intersect.z = (float)(rRay.m_Origin.z + rRay.m_Direction.z*t); //calculate average normal Normals[ 0 ] = Normals[ 0 ]*(1 - (float)u) + Normals[ 0 ]*(1 - (float)v) + Normals[1]* (float)u + Normals[2]* (float)v; Normals[ 0 ].Normalize(); //now take the dot with light ray float value = Normals[ 0 ].Dot( -rRay.m_Direction ); //write to KD Tree //attenuate value based on distance if( curbounce < bounces ) { attenuationDistance = 4000; //hack attenuate to prevent artifacts for now } float intensity = 1.f - ((float)t / attenuationDistance); if( intensity > 1.f ) { intensity = 1.f; } else if( intensity < 0 ) { intensity = 0; } value *= intensity*energy; if( value <= 0.f ) { value = 0.f; return false; } //linearly interpolate the color based on distance floatColor OutColor; float fogFactor = ( (float)t - m_FogStart ) / ( m_FogEnd - m_FogStart ); if( fogFactor < 0 ) { fogFactor = 0.f; } else if( fogFactor > 1.f ) { fogFactor = 1.f; } OutColor.r = m_FogColor.r*fogFactor + color.r*(1.f - fogFactor ); OutColor.g = m_FogColor.g*fogFactor + color.g*(1.f - fogFactor ); OutColor.b = m_FogColor.b*fogFactor + color.b*(1.f - fogFactor ); Matrix4x4 meshTransform; static DWORD msgHash_GetMeshTransform = CHashString(_T("GetMeshTransform")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetMeshTransform, sizeof( Matrix4x4 ), &meshTransform, &meshName, &meshType ); intersect = meshTransform*intersect; //Only need rotation component for normal Matrix3x3 matRotate; matRotate.SetFrom4x4( meshTransform.GetMatrix() ); Vec3 vWorldSpaceNormals = matRotate*Normals[ 0 ]; vWorldSpaceNormals.Normalize(); if( curbounce < bounces ) { Vec3 color( value*OutColor.r, value*OutColor.g, value*OutColor.b ); m_PhotonMap->store( intersect, vWorldSpaceNormals, vRay.m_Direction, color ); //incoming direction must be stored as well m_KDCounter++; } #if 0 //DEBUG code to output bounce rays static int num2 = 0; num2++; if( curbounce < bounces ) { static CHashString h(_T("linename")); ADDLINEPARAMS LineParam; LineParam.name = &h; LineParam.start = vRay.m_Origin; LineParam.end = vRay.m_Origin + vRay.m_Direction*50;//intersect; LineParam.green = 255; LineParam.blue = 0; LineParam.red = 0; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); LineParam.start = intersect; LineParam.end = intersect - vRay.m_Direction*50;//intersect; LineParam.blue = 0; LineParam.green = 0; LineParam.red = 255; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } #endif //Get bounce color float finalU = (float)( meshU[0]*( 1 - u - v ) + meshU[1]*u + meshU[2]*v); float finalV = (float)( meshV[0]*( 1 - u - v ) + meshV[1]*u + meshV[2]*v); floatColor bounceColor; MESHPARAMGETBASECOLORATTRIANGLEINTERSECTIONMSG getColorMsg; getColorMsg.inFace = face; getColorMsg.inUBaryCentric = finalU; getColorMsg.inVBaryCentric = finalV; static DWORD msgHash_GetBaseColorAtTriangleIntersection = CHashString(_T("GetBaseColorAtTriangleIntersection")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetBaseColorAtTriangleIntersection, sizeof( MESHPARAMGETBASECOLORATTRIANGLEINTERSECTIONMSG), &getColorMsg, &meshName, &meshType ); bounceColor = getColorMsg.outColor; bounceColor.a *= OutColor.a; bounceColor.r *= OutColor.r; bounceColor.g *= OutColor.g; bounceColor.b *= OutColor.b; //bounceColor = OutColor; //if( bounceColor.a >= 0)x { //Calculate bounces Ray rNewRay; rNewRay.m_Origin = intersect; float currentIntensity = value*energy_loss; if( value > ENERGY_CUTOFF && curbounce > 0 && rand()%SPECULAR_CHANCE == 0) { CastSpecularRay( rNewRay, vWorldSpaceNormals ); ComputeRay( rNewRay, l, bounces, currentIntensity, curbounce - 1, bounceColor); } bool diffuseFound = false; int bounceTests = 0; while( currentIntensity > ENERGY_CUTOFF && curbounce > 0 && !diffuseFound && bounceTests < MAX_BOUNCE_TEST ) { bounceTests++; CastDiffuseRay( rNewRay, vWorldSpaceNormals ); diffuseFound = ComputeRay( rNewRay, l, bounces, currentIntensity, curbounce - 1, bounceColor); } } return true; } return false; }
void LightMapGenerator::IntersectWithWorld( Ray &vRay, POTENTIAL_INTERSECTION_SORT &sortedIntersections ) { float rayTmin, rayTMax; Vec3 LightOrigin; double t, u, v; Ray rRay; static CHashString meshType(_T("MeshParameterization") ); for( int j = 0; j < (int)m_MeshObjects.size(); j++ ) { //now check each mesh's triangles CHashString &meshName= m_MeshObjects[ j ]; Matrix4x4 meshTransform; Matrix4x4 meshInverseTransform; static DWORD msgHash_GetMeshTransform = CHashString(_T("GetMeshTransform")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetMeshTransform, sizeof( Matrix4x4 ), &meshTransform, &meshName, &meshType ); static DWORD msgHash_GetMeshInverseTransform = CHashString(_T("GetMeshInverseTransform")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetMeshInverseTransform, sizeof( Matrix4x4 ), &meshInverseTransform, &meshName, &meshType ); AABB meshBounds; static DWORD msgHash_GetAABB = CHashString(_T("GetAABB")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetAABB, sizeof( AABB ), &meshBounds, &meshName, &meshType ); //transform this by inverse matrix LightOrigin = meshInverseTransform*vRay.m_Origin; Matrix3x3 matRotate; matRotate.SetFrom4x4( meshInverseTransform.GetMatrix() ); Vec3 transformedDir = matRotate*vRay.m_Direction; transformedDir.Normalize(); rRay = Ray( LightOrigin, transformedDir ); if( meshBounds.IntersectRay( rRay, rayTmin, rayTMax ) ) { //cull mesh away that need not be tested int face = 0; //test intersection MESHPARAMINTERSECTRAYTRIANGLEMSG intersectMsg; intersectMsg.inRay = &rRay; static DWORD msgHash_IntersectRayTriangle = CHashString(_T("IntersectRayTriangle")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_IntersectRayTriangle, sizeof( MESHPARAMINTERSECTRAYTRIANGLEMSG ), &intersectMsg, &meshName, &meshType ); if( intersectMsg.outCollided == true) { face = intersectMsg.outFaceIndex; t = intersectMsg.outIntersectionDistance; u = intersectMsg.outULength; v = intersectMsg.outVLength; if( t < 0 ) { continue; } PotentialIntersection pIntersection; pIntersection.faceIndex = face; pIntersection.t = t; pIntersection.u = u; pIntersection.v = v; pIntersection.mesh = meshName; pIntersection.transformedRay = rRay; sortedIntersections.insert( POTENTIAL_INTERSECTION_SORT_PAIR( (float)t, pIntersection ) ); } } } }
void LightMapGenerator::IntersectWithWorld( Ray &vRay, POTENTIAL_INTERSECTION_SORT &sortedIntersections ) { float rayTmin, rayTMax; Vec3 LightOrigin; MeshParameterization * m = NULL; double t, u, v; Ray rRay; for( int j = 0; j < (int)m_MeshObjects.size(); j++ ) { //now check each mesh's triangles m = m_MeshObjects[ j ]; //transform this by inverse matrix if( m->m_InverseTransform ) { LightOrigin = (*m->m_InverseTransform)*vRay.m_Origin; Matrix3x3 matRotate; matRotate.SetFrom4x4( m->m_InverseTransform->GetMatrix() ); Vec3 transformedDir = matRotate*vRay.m_Direction; transformedDir.Normalize(); rRay = Ray( LightOrigin, transformedDir ); }else { OutputDebugString("No transform!!!!!!\n"); continue; } if( m->m_BoundingBox.IntersectRay( rRay, rayTmin, rayTMax ) ) { //cull mesh away that need not be tested int face = 0; //test intersection if( m->IntersectRayTriangle( rRay, face, &t, &u, &v ) ) { if( t < 0 ) { continue; } //bug from before: //t is still in transformed inverse space, must invert back! Vec3 point = rRay.m_Origin + rRay.m_Direction*(float)t; //now transfrom thsi to original matrix Vec3 oldspace_point = (*(m->m_Transform))*point; Vec3 difference = oldspace_point - vRay.m_Origin; float sortT = difference.Length(); //BUG, not sure: u and v are still in modelspace space? PotentialIntersection pIntersection; pIntersection.faceIndex = face; pIntersection.t = sortT; pIntersection.u = u; pIntersection.v = v; pIntersection.mesh = m; pIntersection.transformedRay = rRay; #if 0 //draw all intersections static CHashString h(_T("none")); if( (rand()%40) == 0 ) { ADDLINEPARAMS LineParam; LineParam.name = &h; LineParam.start = rRay.m_Origin; LineParam.end = rRay.m_Origin + rRay.m_Direction*(float)t; LineParam.blue = 0; LineParam.green = 0; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } #endif sortedIntersections.insert( POTENTIAL_INTERSECTION_SORT_PAIR( sortT, pIntersection ) ); } } } }
void LightMapGenerator::WriteTextureDataFromPhotonMap() { // Set pointers for the array of ranges static Matrix3x3 matRot; CHashString meshType(_T("MeshParameterization") ); char buf[1024]; static int num = 0; static CHashString h(_T("none")); static Vec3 last(0,0,0); int imin = 33; int imax = 36;//m_MeshObjects.size(); for( int i = imin; i < imax; i++ ) { CHashString &meshName = m_MeshObjects[ i ]; GETPARAMETERIZEDTRIANGLESMSG meshFaces; GETPARAMETERIZEDVERTICESMSG meshVertices; Matrix4x4 meshTransform; Matrix4x4 meshInverseTransform; static DWORD msgHash_GetMeshTransform = CHashString(_T("GetMeshTransform")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetMeshTransform, sizeof( Matrix4x4 ), &meshTransform, &meshName, &meshType ); static DWORD msgHash_GetMeshInverseTransform = CHashString(_T("GetMeshInverseTransform")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetMeshInverseTransform, sizeof( Matrix4x4 ), &meshInverseTransform, &meshName, &meshType ); matRot.SetFrom4x4( meshTransform.GetMatrix() ); DWORD meshTextureSize; static DWORD msgHash_OnGetTextureSize = CHashString(_T("OnGetTextureSize")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_OnGetTextureSize, sizeof( meshTextureSize ), &meshTextureSize, &meshName, &meshType ); static DWORD msgHash_GetTriangleFaces = CHashString(_T("GetTriangleFaces")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_GetTriangleFaces, sizeof( GETPARAMETERIZEDTRIANGLESMSG), &meshFaces, &meshName, &meshType ); if( meshFaces.outList == NULL || meshVertices.outList == NULL ) { continue; } int sizeTexture = meshTextureSize*meshTextureSize; for( int j = 0; j < (int)meshFaces.outList->size(); j++ ) { if( j%100 == 0 ) { sprintf( buf, "Gathering data for mesh#%d triangles %d-%d\n", i, j/100, j/100+100 ); OutputDebugString( buf ); } //TODO: /*triMapping = &((*meshFaces.outList)[ j ].m_Pixels); floatColor * buffer = m->GetTextureBuffer(); floatColor * indirectLightBuffer = m->GetIndirectLightBuffer(); for( int k = 0; k < (int)triMapping->size(); k++ ) { TriangleTextureMapping &triMap = (*triMapping)[ k ]; int index = triMap.v*m->GetTextureSize() + triMap.u; if( index >= 0 && index < sizeTexture ) { int indexOut = -1; float usedRange = PHOTON_WEIGHT_RANGE; //check if a closest point is within range, if not, we have to extend range Vec3 transformed = (*m->m_Transform)*triMap.localSpaceCoord; //Vec3 transformed = triMap.localSpaceCoord; num++; Vec3 transformedNormal = matRot*triMap.localNormal; transformedNormal.Normalize(); float accumMaxLightIntensity = 0; static int skiptest = 0; skiptest++; //Direct pass if( buffer[ index ].a < 0 // && skiptest%100==0 ) { for( int a = 0; a< (int)m_Lights.size(); a++ ) { static floatColor lightColor; static float fcolor[4]; ILightObject * light = m_Lights[ a ]; if( light ) { light->GetColorIntensity(fcolor); lightColor.a = fcolor[3]; lightColor.r = 1.f;//fcolor[0]; lightColor.g = 1.f;//fcolor[1]; lightColor.b = 1.f;//fcolor[2]; if( ComputeDirectLightAtPoint( transformed, transformedNormal, buffer[ index ], light , lightColor ) ) { accumMaxLightIntensity += lightColor.a; } } } } if( accumMaxLightIntensity <= 0 ) { accumMaxLightIntensity = 1; } ComputeIrradianceAtPoint2( transformed, transformedNormal, accumMaxLightIntensity, indirectLightBuffer[ index ] ); #if 0 if( (num % 40) == 0 ) { ADDLINEPARAMS LineParam; LineParam.name = &h; //LineParam.start = last; //LineParam.end = transformed; LineParam.start = transformed + transformedNormal*40; LineParam.end = transformed; LineParam.blue = 0; LineParam.green = 0; last = transformed; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); m_ToolBox->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } #endif } }*/ } } }
void LightMapGenerator::WriteTextureDataFromPhotonMap() { vector< TriangleTextureMapping > * triMapping; Range *range = new Range[3]; float *rdata = new float[3*2]; // Set pointers for the array of ranges for(int i=0; i < 3;i++) range[i] = rdata+i*2; static Matrix3x3 matRot; char buf[1024]; static int num = 0; static CHashString h(_T("none")); static Vec3 last(0,0,0); int imin = 0; int imax = m_MeshObjects.size(); for( int i = imin; i < imax; i++ ) { MeshParameterization * m = m_MeshObjects[ i ]; if( m ) { matRot.SetFrom4x4( m->m_Transform->GetMatrix() ); int sizeTexture = m->GetTextureSize()*m->GetTextureSize(); vector< ILightObject * > AffectingLights; for( int a = 0; a< (int)m_Lights.size(); a++ ) { ILightObject * light = m_Lights[ a ]; if( light ) { //Check light with object bounds Vec3 curLPos; light->GetPosition( curLPos ); Vec3 transformedCenter = (*m->m_Transform)*m->m_BoundingBox.m_Center; Vec3 distanceVec = curLPos - transformedCenter; float colDistance = m->m_BoundingBox.m_HalfSize.Length() + light->GetAttenuationDistance(); float curDist = distanceVec.Length(); if( colDistance > curDist ) { AffectingLights.push_back( light ); } } } for( int j = 0; j < (int)m->m_Faces->size(); j++ ) { if( j%100 == 0 ) { sprintf( buf, "Gathering data for mesh#%d triangles %d-%d\n", i, j/100, j/100+100 ); OutputDebugString( buf ); } triMapping = &((*m->m_Faces)[ j ].m_Pixels); floatColor * buffer = m->GetTextureBuffer(); floatColor * indirectLightBuffer = m->GetIndirectLightBuffer(); for( int k = 0; k < (int)triMapping->size(); k++ ) { TriangleTextureMapping &triMap = (*triMapping)[ k ]; int index = triMap.v*m->GetTextureSize() + triMap.u; if( index >= 0 && index < sizeTexture ) { int indexOut = -1; float usedRange = PHOTON_WEIGHT_RANGE; //check if a closest point is within range, if not, we have to extend range Vec3 transformed = (*m->m_Transform)*triMap.localSpaceCoord; //Vec3 transformed = triMap.localSpaceCoord; num++; Vec3 transformedNormal = matRot*triMap.localNormal; transformedNormal.Normalize(); float accumMaxLightIntensity = 0; static int skiptest = 0; skiptest++; //Direct pass if( buffer[ index ].a < 0 // && skiptest%100==0 ) { for( int a = 0; a< (int)AffectingLights.size(); a++ ) { static floatColor lightColor; static float fcolor[4]; ILightObject * light = AffectingLights[ a ]; if( light ) { light->GetColorIntensity(fcolor); lightColor.a = fcolor[3]; lightColor.r = 1.f;//fcolor[0]; lightColor.g = 1.f;//fcolor[1]; lightColor.b = 1.f;//fcolor[2]; if( ComputeDirectLightAtPoint( transformed, transformedNormal, buffer[ index ], light , lightColor ) ) { accumMaxLightIntensity += lightColor.a; } } } } if( accumMaxLightIntensity <= 0 ) { accumMaxLightIntensity = 1; } //Irradiance pass if( indexOut >= 0 && DIRECT_LIGHT_ONLY == false //&& indirectLightBuffer[ index ].a < 0 ) { m_KDTree->GetClosestPoint( (float*)&transformed.x, indexOut, true ); //Get from photon map Vec3 &refVec = m_KDBuffer[ indexOut ]; usedRange = max( PHOTON_WEIGHT_RANGE, ( refVec - transformed ).Length() + PHOTON_RANGE_EXTENSION ); usedRange = min( usedRange, PHOTON_WEIGHT_RANGE_MAX ); //Create range x range[0][0] = transformed.x - usedRange; range[0][1] = transformed.x + usedRange; range[1][0] = transformed.y - usedRange; range[1][1] = transformed.y + usedRange; range[2][0] = transformed.z - usedRange; range[2][1] = transformed.z + usedRange; m_KDTree->maxPoints = PHOTON_SAMPLES; m_KDTree->GetPointsInRange( (Range*)range ); int numpoints = PHOTON_SAMPLES; //m_KDTree->GetNumClosestPoints( (float*)&transformed.x, numpoints ); ComputeIrradianceAtPoint( transformed, transformedNormal, accumMaxLightIntensity, buffer[ index ], indirectLightBuffer[ index ], m_KDTree->pntsInRange, m_KDTree->nPntsInRange ); //ComputeIrradianceAtPoint2( transformed, transformedNormal, accumMaxLightIntensity, // indirectLightBuffer[ index ] ); #if 0 //if( m_KDTree->nPntsInRange> 0 && // m_KDTree->pntsInRange && if( (num % 40) == 0 ) { ADDLINEPARAMS LineParam; LineParam.name = &h; //LineParam.start = last; //LineParam.end = transformed; LineParam.start = transformed + transformedNormal*40; LineParam.end = transformed; LineParam.blue = 0; LineParam.green = 0; last = transformed; static DWORD msgHash_AddLine = CHashString(_T("AddLine")).GetUniqueID(); EngineGetToolBox()->SendMessage(msgHash_AddLine,sizeof(LineParam), &LineParam ); } #endif } } } } } } }