📄 graytrace.cpp
字号:
/* Copyright (C) 2006, Mike Gashler This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. see http://www.gnu.org/copyleft/lesser.html*/#include "GRayTrace.h"#include "GMacros.h"#include "GPointerQueue.h"#include "GXML.h"#include "GBits.h"#include "GHashTable.h"void GRayTraceVector::ComputeReflectionVector(GRayTraceVector* pRay, GRayTraceVector* pNormal){ Copy(pNormal); Multiply(pNormal->DotProduct(pRay) * -2); Add(pRay);}// -----------------------------------------------------------------------------#define MIN_RAY_DISTANCE ((GRayTraceReal).001)GRayTraceRay::GRayTraceRay(){ m_indexOfRefraction = 1;}GRayTraceRay::GRayTraceRay(GRayTraceRay* pThat){ m_indexOfRefraction = pThat->m_indexOfRefraction;}GRayTraceRay::~GRayTraceRay(){}bool GRayTraceRay::ComputeTransmissionVector(GRayTraceVector* pDirectionVector, GRayTraceVector* pTransmissionVector, GRayTraceReal oldIndexOfRefraction, GRayTraceReal newIndexOfRefraction){ double ratio = (double)oldIndexOfRefraction / newIndexOfRefraction; double comp = (double)pDirectionVector->DotProduct(&m_normalVector); double tmp = (double)1 - (ratio * ratio * ((double)1 - (comp * comp))); if(tmp < 0) return false; pTransmissionVector->Copy(&m_normalVector); pTransmissionVector->Multiply((GRayTraceReal)(-ratio * comp - sqrt(tmp))); GRayTraceVector x(pDirectionVector); x.Multiply((GRayTraceReal)ratio); pTransmissionVector->Add(&x); pTransmissionVector->Normalize(); return true;}void GRayTraceRay::ComputeRandomDiffuseVector(GRayTraceVector* pOutVector){ GRayTraceVector u; GRayTraceVector v; if(ABS(m_normalVector.m_vals[0]) < .5) // if N is not co-linear with (1, 0, 0) { v.m_vals[0] = 1; u.CrossProduct(&m_normalVector, &v); } else { v.m_vals[1] = 1; u.CrossProduct(&m_normalVector, &v); } u.Normalize(); v.CrossProduct(&u, &m_normalVector); double a, b, c; while(true) { a = GBits::GetRandomDouble() * 2 - 1; b = GBits::GetRandomDouble() * 2 - 1; if(a * a + b * b < 1) break; } c = sqrt(1.0 - (a * a + b * b)); u.Multiply((GRayTraceReal)a); v.Multiply((GRayTraceReal)b); pOutVector->Copy(&m_normalVector); pOutVector->Multiply((GRayTraceReal)c); pOutVector->Add(&u); pOutVector->Add(&v);}void GRayTraceRay::JitterRay(GRayTraceVector* pVector, GRayTraceReal jitter){ pVector->m_vals[0] += (jitter * (GRayTraceReal)(GBits::GetRandomDouble() * 2 - 1)); pVector->m_vals[1] += (jitter * (GRayTraceReal)(GBits::GetRandomDouble() * 2 - 1)); pVector->m_vals[2] += (jitter * (GRayTraceReal)(GBits::GetRandomDouble() * 2 - 1)); pVector->Normalize();}void GRayTraceRay::Cast(GRayTraceScene* pScene, GRayTraceVector* pRayOrigin, GRayTraceVector* pDirectionVector, int nMaxDepth){ // Find the object GRayTraceReal distance; GAssert(pScene->GetBoundingBoxTree(), "You must to call RenderBegin first?"); GRayTraceObject* pClosestObject = pScene->GetBoundingBoxTree()->FindClosestIntersection(pRayOrigin, pDirectionVector, &distance); if(!pClosestObject) { m_color.Copy(pScene->GetBackgroundColor()); return; } // Compute the collision point m_collisionPoint.Copy(pDirectionVector); m_collisionPoint.Multiply(distance); m_collisionPoint.Add(pRayOrigin); // Compute the normal m_bHitTexture = false; pClosestObject->ComputeNormalVector(this); if(!pClosestObject->IsCulled()) { if(pDirectionVector->DotProduct(&m_normalVector) > 0) m_normalVector.Multiply(-1); } // Compute the reflection vector m_reflectionVector.ComputeReflectionVector(pDirectionVector, &m_normalVector); // Compute the color GRayTraceMaterial* pMaterial = pClosestObject->GetMaterial(); pMaterial->ComputeColor(pScene, this, true, true); // Cast child rays if(nMaxDepth > 0) { // Reflection GRayTraceColor* pReflectedColor = pMaterial->GetColor(GRayTraceMaterial::Reflective, this); if(!pReflectedColor->IsBlack()) { GRayTraceReal jitter = pMaterial->GetGlossiness(); if(jitter > 0) JitterRay(&m_reflectionVector, jitter); GRayTraceRay reflectionRay(this); reflectionRay.Cast(pScene, &m_collisionPoint, &m_reflectionVector, nMaxDepth - 1); reflectionRay.m_color.Multiply(pReflectedColor); m_color.Add(&reflectionRay.m_color); } // Transmission GRayTraceColor* pTransmissionColor = pMaterial->GetColor(GRayTraceMaterial::Transmissive, this); if(!pTransmissionColor->IsBlack()) { // Compute transmission ray GRayTraceReal newIndexOfRefraction; if(m_indexOfRefraction > .9999 && m_indexOfRefraction < 1.0001) newIndexOfRefraction = pMaterial->GetIndexOfRefraction(); else newIndexOfRefraction = 1; GRayTraceVector transmissionVector; if(!ComputeTransmissionVector(pDirectionVector, &transmissionVector, m_indexOfRefraction, newIndexOfRefraction)) { // total internal reflection occurs transmissionVector.Copy(&m_reflectionVector); newIndexOfRefraction = m_indexOfRefraction; } // Cast transmission ray GRayTraceReal jitter = pMaterial->GetCloudiness(); if(jitter > 0) JitterRay(&transmissionVector, jitter); GRayTraceRay transmissionRay(this); transmissionRay.m_indexOfRefraction = newIndexOfRefraction; transmissionRay.Cast(pScene, &m_collisionPoint, &transmissionVector, nMaxDepth - 1); transmissionRay.m_color.Multiply(pTransmissionColor); m_color.Add(&transmissionRay.m_color); } }}#define PATH_TRACER_PROB_REFLECTIVE 0.5#define PATH_TRACER_PROB_TRANSMISSIVE 0.3void GRayTraceRay::Trace(GRayTraceScene* pScene, GRayTraceVector* pRayOrigin, GRayTraceVector* pDirectionVector, int nMaxDepth, bool bEmissive){ // Find the object GRayTraceReal distance; GRayTraceObject* pClosestObject = pScene->GetBoundingBoxTree()->FindClosestIntersection(pRayOrigin, pDirectionVector, &distance); if(!pClosestObject) { m_color.Copy(pScene->GetBackgroundColor()); return; } // Compute the collision point m_collisionPoint.Copy(pDirectionVector); m_collisionPoint.Multiply(distance); m_collisionPoint.Add(pRayOrigin); // Compute the normal m_bHitTexture = false; pClosestObject->ComputeNormalVector(this); if(!pClosestObject->IsCulled()) { if(pDirectionVector->DotProduct(&m_normalVector) > 0) m_normalVector.Multiply(-1); } // Compute the reflection vector m_reflectionVector.ComputeReflectionVector(pDirectionVector, &m_normalVector); // Compute the color GRayTraceMaterial* pMaterial = pClosestObject->GetMaterial(); pMaterial->ComputeColor(pScene, this, false, false); if(bEmissive) m_color.Add(pMaterial->GetColor(GRayTraceMaterial::Emissive, this)); // Cast child rays if(nMaxDepth > 0) { GRayTraceColor* pReflectedColor = pMaterial->GetColor(GRayTraceMaterial::Reflective, this); GRayTraceColor* pTransmissionColor = pMaterial->GetColor(GRayTraceMaterial::Transmissive, this); GRayTraceColor* pDiffuseColor = pMaterial->GetColor(GRayTraceMaterial::Diffuse, this); GRayTraceReal lumReflective = pReflectedColor->r * (GRayTraceReal)0.299 + pReflectedColor->g * (GRayTraceReal)0.587 + pReflectedColor->b * (GRayTraceReal)0.114; GRayTraceReal lumTransmissive = pTransmissionColor->r * (GRayTraceReal)0.299 + pTransmissionColor->g * (GRayTraceReal)0.587 + pTransmissionColor->b * (GRayTraceReal)0.114; GRayTraceReal lumDiffuse = pDiffuseColor->r * (GRayTraceReal)0.299 + pDiffuseColor->g * (GRayTraceReal)0.587 + pDiffuseColor->b * (GRayTraceReal)0.114; GRayTraceReal lumSum = lumReflective + lumTransmissive + lumDiffuse; if(lumSum > .0001) { lumReflective /= lumSum; lumTransmissive /= lumSum; lumDiffuse /= lumSum; double d = GBits::GetRandomDouble(); if(d < lumReflective) { // Reflective path GRayTraceReal jitter = pMaterial->GetGlossiness(); if(jitter > 0) JitterRay(&m_reflectionVector, jitter); GRayTraceRay reflectionRay(this); reflectionRay.Trace(pScene, &m_collisionPoint, &m_reflectionVector, nMaxDepth - 1, true); reflectionRay.m_color.Multiply(pReflectedColor); reflectionRay.m_color.Multiply((GRayTraceReal)1.0 / lumReflective); // Compensate for less than one probability of selecting this path m_color.Add(&reflectionRay.m_color); } else if(d < lumReflective + lumTransmissive) { // Compute transmission ray GRayTraceReal newIndexOfRefraction; if(m_indexOfRefraction > .9999 && m_indexOfRefraction < 1.0001) newIndexOfRefraction = pMaterial->GetIndexOfRefraction(); else newIndexOfRefraction = 1; GRayTraceVector transmissionVector; if(!ComputeTransmissionVector(pDirectionVector, &transmissionVector, m_indexOfRefraction, newIndexOfRefraction)) { // total internal reflection occurs transmissionVector.Copy(&m_reflectionVector); newIndexOfRefraction = m_indexOfRefraction; } // Cast transmission ray GRayTraceReal jitter = pMaterial->GetCloudiness(); if(jitter > 0) JitterRay(&transmissionVector, jitter); GRayTraceRay transmissionRay(this); transmissionRay.m_indexOfRefraction = newIndexOfRefraction; transmissionRay.Trace(pScene, &m_collisionPoint, &transmissionVector, nMaxDepth - 1, true); transmissionRay.m_color.Multiply(pTransmissionColor); transmissionRay.m_color.Multiply((GRayTraceReal)1.0 / lumTransmissive); // Compensate for less than one probability of selecting this path m_color.Add(&transmissionRay.m_color); } else { // Diffuse path GRayTraceVector diffuseVector; ComputeRandomDiffuseVector(&diffuseVector); GRayTraceRay diffuseRay(this); diffuseRay.Trace(pScene, &m_collisionPoint, &diffuseVector, nMaxDepth - 1, false); diffuseRay.m_color.Multiply(pDiffuseColor); diffuseRay.m_color.Multiply((GRayTraceReal)1.0 / lumDiffuse); // Compensate for less than one probability of selecting this path m_color.Add(&diffuseRay.m_color); } } }}// I'm not sure it really makes sense to store the texture coordinates// in the ray, but somehow this data needs to be passed from the tri-mesh// to the material, and the ray is a convenient carriervoid GRayTraceRay::SetTextureCoords(GRayTraceReal x, GRayTraceReal y){ m_bHitTexture = true; m_textureX = x; m_textureY = y;}void GRayTraceRay::GetTextureCoords(GRayTraceReal* x, GRayTraceReal* y){ *x = m_textureX; *y = m_textureY;}// -----------------------------------------------------------------------------void GRayTraceCamera::ComputeSideVector(){ GRayTraceVector n(&m_lookAtPoint); n.Subtract(&m_lookFromPoint); m_viewSideVector.CrossProduct(&m_viewUpVector, &n); m_viewUpVector.Normalize(); m_viewSideVector.Normalize();}void GRayTraceCamera::SetRoll(GRayTraceReal angle){ GRayTraceVector z(&m_lookAtPoint); z.Subtract(&m_lookFromPoint); GRayTraceVector x; GRayTraceReal cosAngle = (GRayTraceReal)cos(angle); x.m_vals[0] = cosAngle * z.m_vals[2]; x.m_vals[1] = (GRayTraceReal)sin(angle); x.m_vals[2] = cosAngle * (-z.m_vals[0]); m_viewUpVector.CrossProduct(&z, &x); if(m_viewUpVector.GetMagnitudeSquared() == 0) m_viewUpVector.m_vals[0] = 1; ComputeSideVector();}// -----------------------------------------------------------------------------GRayTraceScene::GRayTraceScene(): m_backgroundColor(1, (GRayTraceReal).6, (GRayTraceReal).7, (GRayTraceReal).5), m_ambientLight(1, (GRayTraceReal).3, (GRayTraceReal).3, (GRayTraceReal).3){ m_pMaterials = new GPointerArray(256); m_pMeshes = new GPointerArray(64); m_pObjects = new GPointerArray(1024); m_pLights = new GPointerArray(32); m_pCamera = new GRayTraceCamera(); m_pBoundingBoxTree = NULL; m_pImage = NULL; m_pDistanceMap = NULL; m_nY = -1; m_toneMappingConstant = .5; m_eMode = FAST_RAY_TRACE;}GRayTraceScene::~GRayTraceScene(){ int n, nCount; // Materials nCount = m_pMaterials->GetSize(); for(n = 0; n < nCount; n++) delete((GRayTraceMaterial*)m_pMaterials->GetPointer(n)); delete(m_pMaterials); // Meshes nCount = m_pMeshes->GetSize(); for(n = 0; n < nCount; n++) delete((GRayTraceTriMesh*)m_pMeshes->GetPointer(n)); delete(m_pMeshes); // Objects nCount = m_pObjects->GetSize(); for(n = 0; n < nCount; n++) delete((GRayTraceObject*)m_pObjects->GetPointer(n)); delete(m_pObjects); // Lights nCount = m_pLights->GetSize(); for(n = 0; n < nCount; n++) delete((GRayTraceLight*)m_pLights->GetPointer(n)); delete(m_pBoundingBoxTree); delete(m_pCamera); delete(m_pImage); delete(m_pDistanceMap);}int GRayTraceScene::GetObjectCount(){ return m_pObjects->GetSize();}GRayTraceObject* GRayTraceScene::GetObject(int n){ return (GRayTraceObject*)m_pObjects->GetPointer(n);}int GRayTraceScene::GetLightCount(){ return m_pLights->GetSize();}GRayTraceLight* GRayTraceScene::GetLight(int n){ return (GRayTraceLight*)m_pLights->GetPointer(n);}void GRayTraceScene::AddMaterial(GRayTraceMaterial* pMaterial){ m_pMaterials->AddPointer(pMaterial);}void GRayTraceScene::AddMesh(GRayTraceTriMesh* pMesh){ m_pMeshes->AddPointer(pMesh); int nCount = pMesh->GetTriangleCount(); int i; for(i = 0; i < nCount; i++) AddObject(new GRayTraceTriangle(pMesh, i));}void GRayTraceScene::AddObject(GRayTraceObject* pObject){ m_pObjects->AddPointer(pObject);}void GRayTraceScene::AddLight(GRayTraceLight* pLight){ m_pLights->AddPointer(pLight);}void GRayTraceScene::ActivateDistanceMap(){ if(m_pDistanceMap) delete[] m_pDistanceMap; m_pDistanceMap = new GRayTraceReal[m_pCamera->GetImageWidth() * m_pCamera->GetImageHeight()];}void GRayTraceScene::RenderBegin(){ // Allocate an image if(!m_pImage) m_pImage = new GImage(); int nWidth = m_pCamera->GetImageWidth(); int nHeight = m_pCamera->GetImageHeight(); m_pImage->SetSize(nWidth, nHeight); m_pImage->Clear(0xff808080); // Rebuild the bounding box tree delete(m_pBoundingBoxTree); m_pBoundingBoxTree = GRayTraceBoundingBoxBase::MakeBoundingBoxTree(m_pObjects); // Precompute vectors m_pCamera->ComputeSideVector(); GRayTraceVector n(m_pCamera->GetLookAtPoint()); n.Subtract(m_pCamera->GetLookFromPoint()); GRayTraceVector v(m_pCamera->GetViewUpVector()); GRayTraceVector u(m_pCamera->GetViewSideVector()); GRayTraceReal halfViewHeight = (GRayTraceReal)(tan(m_pCamera->GetViewAngle() / 2) * sqrt(n.GetMagnitudeSquared())); GRayTraceReal halfViewWidth = halfViewHeight * nWidth / nHeight; u.Multiply(halfViewWidth); v.Multiply(halfViewHeight); m_pixSide.Copy(m_pCamera->GetLookAtPoint()); m_pixSide.Subtract(&u); m_pixSide.Subtract(&v); m_pixDX.Copy(&u); m_pixDX.Multiply((GRayTraceReal)2 / nWidth); m_pixDY.Copy(&v); m_pixDY.Multiply((GRayTraceReal)2 / nHeight); m_nY = nHeight - 1;}GColor GRayTraceScene::RenderPixel(GRayTraceRay* pRay, GRayTraceVector* pScreenPoint, GRayTraceReal* pDistance){ GRayTraceVector directionVector(pScreenPoint); directionVector.Subtract(m_pCamera->GetLookFromPoint()); directionVector.Normalize(); pRay->Cast(this, m_pCamera->GetLookFromPoint(), &directionVector, m_pCamera->GetMaxDepth());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -