I have traced the problem with photon mapping part to be in shadowPhoton() function. I also had to change sqRadius global variable from 0.7 to 0.3, to get it look about right in most cases. I don't know if it got something to do with the way Hollywood does it's math stuff or is there still some kind of an error hidden somewhere?
Tell me, if you can figure it out. shadowPhoton() function call is currently commented out in emitPhotons() function.
Code: Select all
@DISPLAY {Height = 512, Width = 512}
Global szImg = 512
Global nrTypes = 2t
Global nrObjects = { 2, 5 }
Global gAmbient = 0.1
Global gOrigin = { 0.0, 0.0, 0.0 }
Global Light = { 0.0, 1.2, 3.75 }
Global spheres = { { 1.0, 0.0, 4.0, 0.5 }, { -0.6, -1.0, 4.5, 0.5 } }
Global planes = { { 0.0, 1.5 }, { 1.0, -1.5 }, { 0.0, -1.5 }, { 1.0, 1.5 }, { 2.0, 5.0 } }
Global nrPhotons = 1000
Global nrBounces = 3
Global lightPhotons = True
Global sqRadius = 0.3 ;0.7
Global exposure = 50.0
Global numPhotons = { {0, 0}, {0,0,0,0,0} }
Dim photons[2][5][5000][3][3]
Global gIntersect = False
Global gType
Global gIndex
Global gSqDist
Global gDist = -1.0
Global gPoint = { 0.0, 0.0, 0.0 }
Function raySphere(idx, r, o)
Local s = sub3(spheres[idx], o)
Local radius = spheres[idx][3]
Local A = dot3(r, r)
Local B = -2.0 * dot3(s, r)
Local C = dot3(s, s) - (radius * radius)
Local D = B * B - 4.0 * A * C
If D > 0.0
Local sign
If C < -0.00001 Then sign = 1.0 Else sign = -1.0
Local lDist = (-B + sign * Sqrt(D)) / (2.0 * A)
checkDistance(lDist, 0, idx)
EndIf
EndFunction
Function rayPlane(idx, r, o)
Local axis = planes[idx][0]
If r[axis] <> 0.0
Local lDist = (planes[idx][1] - o[axis]) / r[axis]
CheckDistance(lDist, 1, idx)
EndIf
EndFunction
Function rayObject(typ, idx, r, o)
If typ = 0
raySphere(idx, r, o)
Else
rayPlane(idx, r, o)
EndIf
EndFunction
Function checkDistance(lDist, p, i)
If lDist < gDist And lDist > 0.0
gType = p
gIndex = i
gDist = lDist
gIntersect = True
EndIf
EndFunction
Function lightDiffuse(N, P)
Local L = normalize3(sub3(Light, P))
Return(dot3(N, L))
EndFunction
Function sphereNormal(idx, P)
Return(normalize3(sub3(P, spheres[idx])))
EndFunction
Function planeNormal(idx, P, O)
Local axis = Int(planes[idx][0])
Local N = { 0.0, 0.0, 0.0 }
N[axis] = O[axis] - planes[idx][1]
Return(normalize3(N))
EndFunction
Function surfaceNormal(Typ, index, P, Inside)
If Typ = 0
Return(sphereNormal(index, P))
Else
Return(planeNormal(index, P, Inside))
EndIf
EndFunction
Function lightObject(Typ, idx, P, lightAmbient)
Local i = lightDiffuse(surfaceNormal(Typ, idx, P, Light), P)
Return(Min(1.0, Max(i, lightAmbient)))
EndFunction
Function raytrace(ray, origin)
gIntersect = False
gDist = 999999.9
For Local t = 0 To nrTypes - 1 Step 1
For Local i = 0 To nrObjects[t] - 1 Step 1
rayObject(t, i, ray, origin)
Next
Next
EndFunction
Function computePixelColor(x, y)
Local rgbc = { 0.0, 0.0, 0.0 }
Local ray = { x/szImg - 0.5, - (y/szImg - 0.5), 1.0 }
raytrace(ray, gOrigin)
If gIntersect
gPoint = mul3c(ray, gDist)
If gType = 0 And gIndex = 1
ray = reflect(ray, gOrigin)
raytrace(ray, gPoint)
If gIntersect Then gPoint = add3(mul3c(ray, gDist), gPoint)
EndIf
If lightPhotons
rgbc = gatherPhotons(gPoint, gType, gIndex)
Else
Local tType = gType
Local tIndex = gIndex
Local i = gAmbient
raytrace(sub3(gPoint, Light), Light)
If tType = gType And tIndex = gIndex Then i = lightObject(gType, gIndex, gPoint, gAmbient)
rgbc[0] = i
rgbc[1] = i
rgbc[2] = i
rgbc = GetColorRGB(rgbc, tType, tIndex)
EndIf
EndIf
Return(rgbc)
EndFunction
Function reflect(ray, fromPoint)
Local N = surfaceNormal(gType, gIndex, gPoint, fromPoint)
Return(normalize3(Sub3(ray, mul3c(N, (2.0 * dot3(ray, N))))))
EndFunction
Function gatherPhotons(p, Typ, id)
Local energy = { 0.0, 0.0, 0.0 }
Local N = surfaceNormal(Typ, id, p, gOrigin)
For Local i = 0 To numPhotons[Typ][id] - 1 Step 1
If gatedSqDist3(p, photons[Typ][id][i][0], sqRadius)
Local weight = Max(0.0, -dot3(N, photons[Typ][id][i][1]))
weight = weight * (1.0 - Sqrt(gSqDist)) / exposure
energy = add3(energy, mul3c(photons[Typ][id][i][2], weight))
EndIf
Next
Return(energy)
EndFunction
Function emitPhotons()
;SeedRnd(0) ; Sorry, no equilevant in Hollywood you get different photons on every run
For Local t = 0 To nrTypes - 1 Step 1
For Local i = 0 To nrObjects[t] - 1 Step 1
numPhotons[t][i] = 0
Next
Next
Local test = nrPhotons
If view3D Then test = nrPhotons * 3.0
For Local i = 0 To test - 1 Step 1
Local bounces = 1
Local rgbc = { 1.0, 1.0, 1.0 }
Local ray = normalize3(rand3(1.0))
Local prevPoint = CopyTable(Light)
While prevPoint[1] >= Light[1]
prevPoint = add3(Light, mul3c(normalize3(rand3(1.0)), 0.75))
Wend
If Abs(prevPoint[0]) > 1.5 Or Abs(prevPoint[1]) > 1.2 Or gatedSqDist3(prevPoint, spheres[0], spheres[0][3]* spheres[0][3]) Then bounces = nrBounces + 1
raytrace(ray, prevPoint)
While gIntersect And bounces <= nrBounces
gPoint = add3(mul3c(ray, gDist), prevPoint)
rgbc = mul3c(GetColorRGB(rgbc, gType, gIndex), 1.0 / Sqrt(bounces))
storePhoton(gType, gIndex, gPoint, ray, rgbc)
drawPhoton(rgbc, gPoint)
;shadowPhoton(ray)
ray = reflect(ray, prevPoint)
raytrace(ray, gPoint)
prevPoint = CopyTable(gPoint)
bounces = bounces + 1
Wend
Next
EndFunction
Function storePhoton(Typ, id, location, direction, energy)
photons[Typ][id][numPhotons[Typ][id]][0] = CopyTable(location)
photons[Typ][id][numPhotons[Typ][id]][1] = CopyTable(direction)
photons[Typ][id][numPhotons[Typ][id]][2] = CopyTable(energy)
numPhotons[Typ][id] = numPhotons[Typ][id] + 1
EndFunction
Function shadowPhoton(ray)
Local shadow = { -0.25, -0.25, -0.25 }
Local bumpedPoint = add3(gPoint, mul3c(ray, 0.00001))
raytrace(ray, bumpedPoint)
Local shadowPoint = add3(mul3c(ray, gDist), bumpedPoint)
storePhoton(gType, gIndex, shadowPoint, ray, shadow)
EndFunction
Function filterColor(rgbIn, r, g, b)
Local rgbOut = { r, g, b }
For Local c = 0 To 2
rgbOut[c] = Min(rgbOut[c], rgbIn[c])
Next
Return(rgbOut)
EndFunction
Function GetColorRGB(rgbIn, Typ, index)
If Typ = 1 And index = 0
Return(filterColor(rgbIn, 0.0, 1.0, 0.0))
ElseIf Typ = 1 And index = 2
Return(filterColor(rgbIn, 1.0, 0.0, 0.0))
Else
Return(filterColor(rgbIn, 1.0, 1.0, 1.0))
EndIf
EndFunction
Function normalize3(v)
Local L = Sqrt(dot3(v, v))
Return(mul3c(v, 1.0 / L))
EndFunction
Function sub3(a, b)
Local result = { a[0] - b[0], a[1] - b[1], a[2] - b[2] }
Return(result)
EndFunction
Function add3(a, b)
Local result = { a[0] + b[0], a[1] + b[1], a[2] + b[2] }
Return(result)
EndFunction
Function mul3c(a, c)
Local result = { c * a[0], c * a[1], c * a[2] }
Return(result)
EndFunction
Function dot3(a, b)
Local result = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
Return(result)
EndFunction
Function rand3(s)
Local s2 = s * 2
Local r = { RndF() * s2 - s, RndF() * s2 - s, RndF() * s2 - s }
Return(r)
EndFunction
Function gatedSqDist3(a, b, sqradius)
Local c = a[0] - b[0]
Local d = c * c
If d > sqradius Then Return(False)
c = a[1] - b[1]
d = d + c * c
If d > sqradius Then Return(False)
c = a[2] - b[2]
d = d + c * c
If d > sqradius Then Return(False)
gSqDist = d
Return(True)
EndFunction
Function odd(x)
Return(x & 1)
EndFunction
Global empty = True
Global view3D = False
Global pRow, pCol, pIteration, pMax
Function draw()
If view3D
If empty
Cls
;drawInterface()
emitPhotons()
empty = False
EndIf
Else
If empty
render()
xx = xx + 1
If xx > 10
xx = 0
yy = yy + 1
;DebugPrint(pMax, pRow)
EndIf
EndIf
EndIf
EndFunction
Function render()
Local x, y
Local iterations = 0
Local rgbc = { 0.0, 0.0, 0.0 }
Local imax = Max(pMax, 256)
If mouseDragging Then imax = 1024
While iterations < imax
If pCol >= pMax
pRow = pRow + 1
pCol = 0
If pRow >= pMax
pIteration = pIteration + 1
pRow = 0
pMax = Int(2^pIteration)
EndIf
EndIf
Local pNeedDrawing = 0
If pIteration = 1 Or odd(pRow) Or ((Not odd(pRow)) And odd(pCol)) Then pNeedDrawing = 1
x = pCol * (szImg/pMax)
y = pRow * (szImg/pMax)
pCol = pCol + 1
If pNeedDrawing
iterations = iterations + 1
rgbc = mul3c(computePixelColor(x, y), 255.0)
Local col = RGB(rgbc[0],rgbc[1], rgbc[2])
SetFillStyle(#FILLCOLOR)
Box(x, y, (szImg/pMax), (szImg/pMax), col)
EndIf
Wend
If pRow = szImg - 1 Then empty = False
EndFunction
Function resetRender()
pRow = 0
pCol = 0
pIteration = 1
pMax = 2
empty = True
If lightPhotons And Not view3D Then emitPhotons()
EndFunction
Function drawPhoton(rgbc, p)
If view3D And p[2] > 0.0
Local x = (szImg/2) + Int(szImg * p[0] / p[2])
Local y = (szImg/2) + Int(szImg * -p[1] / p[2])
If y <= szImg
Local col = RGB(255.0 * rgbc[0], 255.0 * rgbc[1], 255.0 * rgbc[2])
Plot(x, y, col)
EndIf
EndIf
EndFunction
Global MouseDragging = False
Function GrabObject()
SphereIndex = 2 ; Default to lightsource
; Try to project screen coords to world space
Local mx = (MouseX() - (szImg/2))/(szImg/2)
Local my = -(MouseY() - (szImg/2))/(szImg/2)
Local mouse3 = { mx, my, (0.5 * (spheres[0][2] + spheres[1][2])) }
If (gatedSqDist3(mouse3,spheres[0],spheres[0][3]))
sphereIndex = 0
ElseIf gatedSqDist3(mouse3,spheres[1],spheres[1][3])
sphereIndex = 1
EndIf
mouseDragging = True
EndFunction
; Simple hack for dragging, try to project screen coords to world space
Function DragObject()
If sphereIndex < nrObjects[0] ; Drag Sphere
spheres[sphereIndex][0] = ((MouseX() - (szImg/2)) /(szImg/2))/0.5
spheres[sphereIndex][1] = -((MouseY() - (szImg/2))/(szImg/2))/0.5
Else ;Drag Light
Light[0] = ((MouseX() - (szImg/2))/(szImg/2))/0.5
Light[1] = -((MouseY() - (szImg/2))/(szImg/2))/0.5
EndIf
resetRender()
EndFunction
EscapeQuit(True)
emitPhotons()
resetRender()
BeginDoubleBuffer()
Repeat
If IsLeftMouse()
If Not MouseDragging
GrabObject()
Else
DragObject()
EndIf
Else
MouseDragging = False
EndIf
draw()
Flip()
Forever