sRGBAfloat cRenderWorker::EnvMapping(const sShaderInputData &input) { sRGBAfloat envReflect; CVector3 reflect; double dot = -input.viewVector.Dot(input.normal); reflect = input.normal * 2.0 * dot + input.viewVector; double alphaTexture = -reflect.GetAlpha() + M_PI; double betaTexture = -reflect.GetBeta(); double texWidth = data->textures.envmapTexture.Width(); double texHeight = data->textures.envmapTexture.Height(); if (betaTexture > 0.5 * M_PI) betaTexture = 0.5 * M_PI - betaTexture; if (betaTexture < -0.5 * M_PI) betaTexture = -0.5 * M_PI + betaTexture; double dtx = (alphaTexture / (2.0 * M_PI)) * texWidth + texWidth * 8.25; double dty = (betaTexture / (M_PI) + 0.5) * texHeight + texHeight * 8.0; dtx = fmod(dtx, texWidth); dty = fmod(dty, texHeight); if (dtx < 0) dtx = 0; if (dty < 0) dty = 0; double reflectance = 1.0; if (input.material->fresnelReflectance) { double n1 = 1.0; double n2 = input.material->transparencyIndexOfRefraction; reflectance = Reflectance(input.normal, input.viewVector, n1, n2); if (reflectance < 0.0) reflectance = 0.0; if (reflectance > 1.0) reflectance = 1.0; } envReflect.R = data->textures.envmapTexture.Pixel(dtx, dty).R * reflectance; envReflect.G = data->textures.envmapTexture.Pixel(dtx, dty).G * reflectance; envReflect.B = data->textures.envmapTexture.Pixel(dtx, dty).B * reflectance; return envReflect; }
cRenderWorker::sRayRecursionOut cRenderWorker::RayRecursion(sRayRecursionIn in, sRayRecursionInOut &inOut) { sRayMarchingOut rayMarchingOut; *inOut.rayMarchingInOut.buffCount = 0; //trace the light in given direction CVector3 point = RayMarching(in.rayMarchingIn, &inOut.rayMarchingInOut, &rayMarchingOut); sRGBAfloat resultShader = in.resultShader; sRGBAfloat objectColour = in.objectColour; //here will be called branch for RayRecursion(); sRGBAfloat objectShader; objectShader.A = 0.0; sRGBAfloat backgroundShader; sRGBAfloat volumetricShader; sRGBAfloat specular; //prepare data for shaders CVector3 lightVector = shadowVector; sShaderInputData shaderInputData; shaderInputData.distThresh = rayMarchingOut.distThresh; shaderInputData.delta = CalcDelta(point); shaderInputData.lightVect = lightVector; shaderInputData.point = point; shaderInputData.viewVector = in.rayMarchingIn.direction; shaderInputData.lastDist = rayMarchingOut.lastDist; shaderInputData.depth = rayMarchingOut.depth; shaderInputData.stepCount = *inOut.rayMarchingInOut.buffCount; shaderInputData.stepBuff = inOut.rayMarchingInOut.stepBuff; shaderInputData.invertMode = in.calcInside; shaderInputData.objectId = rayMarchingOut.objectId; cObjectData objectData = data->objectData[shaderInputData.objectId]; shaderInputData.material = &data->materials[objectData.materialId]; sRGBAfloat reflectShader = in.resultShader; double reflect = shaderInputData.material->reflectance; sRGBAfloat transparentShader = in.resultShader; double transparent = shaderInputData.material->transparencyOfSurface; sRGBfloat transparentColor = sRGBfloat(shaderInputData.material->transparencyInteriorColor.R / 65536.0, shaderInputData.material->transparencyInteriorColor.G / 65536.0, shaderInputData.material->transparencyInteriorColor.B / 65536.0); resultShader.R = transparentColor.R; resultShader.G = transparentColor.G; resultShader.B = transparentColor.B; CVector3 vn; //if found any object if (rayMarchingOut.found) { //calculate normal vector vn = CalculateNormals(shaderInputData); shaderInputData.normal = vn; if(shaderInputData.material->diffusionTexture.IsLoaded()) shaderInputData.texDiffuse = TextureShader(shaderInputData, cMaterial::texDiffuse, shaderInputData.material); else shaderInputData.texDiffuse = sRGBfloat(1.0, 1.0, 1.0); if(shaderInputData.material->normalMapTexture.IsLoaded()) { vn = NormalMapShader(shaderInputData); } //prepare refraction values double n1, n2; if (in.calcInside) //if trance is inside the object { n1 = shaderInputData.material ->transparencyIndexOfRefraction; //reverse refractive indices n2 = 1.0; } else { n1 = 1.0; n2 = shaderInputData.material ->transparencyIndexOfRefraction; ; } if (inOut.rayIndex < reflectionsMax) { //calculate refraction (transparency) if (transparent > 0.0) { sRayRecursionIn recursionIn; sRayMarchingIn rayMarchingIn; sRayMarchingInOut rayMarchingInOut; //calculate direction of refracted light CVector3 newDirection = RefractVector(vn, in.rayMarchingIn.direction, n1, n2); //move starting point a little CVector3 newPoint = point + in.rayMarchingIn.direction * shaderInputData.distThresh * 1.0; //if is total internal reflection the use reflection instead of refraction bool internalReflection = false; if (newDirection.Length() == 0.0) { newDirection = ReflectionVector(vn, in.rayMarchingIn.direction); newPoint = point + in.rayMarchingIn.direction * shaderInputData.distThresh * 1.0; internalReflection = true; } //preparation for new recursion rayMarchingIn.binaryEnable = true; rayMarchingIn.direction = newDirection; rayMarchingIn.maxScan = params->viewDistanceMax; rayMarchingIn.minScan = 0.0; rayMarchingIn.start = newPoint; rayMarchingIn.invertMode = !in.calcInside || internalReflection; recursionIn.rayMarchingIn = rayMarchingIn; recursionIn.calcInside = !in.calcInside || internalReflection; recursionIn.resultShader = resultShader; recursionIn.objectColour = objectColour; //setup buffers for ray data inOut.rayIndex++; //increase recursion index rayMarchingInOut.buffCount = &rayBuffer[inOut.rayIndex].buffCount; rayMarchingInOut.stepBuff = rayBuffer[inOut.rayIndex].stepBuff; inOut.rayMarchingInOut = rayMarchingInOut; //recursion for refraction sRayRecursionOut recursionOutTransparent = RayRecursion(recursionIn, inOut); transparentShader = recursionOutTransparent.resultShader; } //calculate reflection if (reflect > 0.0) { sRayRecursionIn recursionIn; sRayMarchingIn rayMarchingIn; sRayMarchingInOut rayMarchingInOut; //calculate new direction of reflection CVector3 newDirection = ReflectionVector(vn, in.rayMarchingIn.direction); CVector3 newPoint = point + newDirection * shaderInputData.distThresh; //prepare for new recursion rayMarchingIn.binaryEnable = true; rayMarchingIn.direction = newDirection; rayMarchingIn.maxScan = params->viewDistanceMax; rayMarchingIn.minScan = 0.0; rayMarchingIn.start = newPoint; rayMarchingIn.invertMode = false; recursionIn.rayMarchingIn = rayMarchingIn; recursionIn.calcInside = false; recursionIn.resultShader = resultShader; recursionIn.objectColour = objectColour; //setup buffers for ray data inOut.rayIndex++; //increase recursion index rayMarchingInOut.buffCount = &rayBuffer[inOut.rayIndex].buffCount; rayMarchingInOut.stepBuff = rayBuffer[inOut.rayIndex].stepBuff; inOut.rayMarchingInOut = rayMarchingInOut; //recursion for reflection sRayRecursionOut recursionOutReflect = RayRecursion(recursionIn, inOut); reflectShader = recursionOutReflect.resultShader; } if (transparent > 0.0) inOut.rayIndex--; //decrease recursion index if (reflect > 0.0) inOut.rayIndex--; //decrease recursion index } shaderInputData.normal = vn; //calculate effects for object surface objectShader = ObjectShader(shaderInputData, &objectColour, &specular); //calculate reflectance according to Fresnel equations double reflectance = 1.0; double reflectanceN = 1.0; if (shaderInputData.material->fresnelReflectance) { reflectance = Reflectance(vn, in.rayMarchingIn.direction, n1, n2); if (reflectance < 0.0) reflectance = 0.0; if (reflectance > 1.0) reflectance = 1.0; reflectanceN = 1.0 - reflectance; } //combine all results resultShader.R = (objectShader.R + specular.R); resultShader.G = (objectShader.G + specular.G); resultShader.B = (objectShader.B + specular.B); if (reflectionsMax > 0) { sRGBfloat reflectDiffused; double diffIntes = shaderInputData.material->diffussionTextureIntensity; double diffIntesN = 1.0 - diffIntes; reflectDiffused.R = reflect * shaderInputData.texDiffuse.R * diffIntes + reflect * diffIntesN; reflectDiffused.G = reflect * shaderInputData.texDiffuse.G * diffIntes + reflect * diffIntesN; reflectDiffused.B = reflect * shaderInputData.texDiffuse.B * diffIntes + reflect * diffIntesN; resultShader.R = transparentShader.R * transparent * reflectanceN + (1.0 - transparent * reflectanceN) * resultShader.R; resultShader.G = transparentShader.G * transparent * reflectanceN + (1.0 - transparent * reflectanceN) * resultShader.G; resultShader.B = transparentShader.B * transparent * reflectanceN + (1.0 - transparent * reflectanceN) * resultShader.B; resultShader.R = reflectShader.R * reflectDiffused.R * reflectance + (1.0 - reflectDiffused.R * reflectance) * resultShader.R; resultShader.G = reflectShader.G * reflectDiffused.G * reflectance + (1.0 - reflectDiffused.G * reflectance) * resultShader.G; resultShader.B = reflectShader.B * reflectDiffused.B * reflectance + (1.0 - reflectDiffused.B * reflectance) * resultShader.B; } if(resultShader.R < 0.0) resultShader.R = 0.0; if(resultShader.G < 0.0) resultShader.G = 0.0; if(resultShader.B < 0.0) resultShader.B = 0.0; } else //if object not found then calculate background { backgroundShader = BackgroundShader(shaderInputData); resultShader = backgroundShader; shaderInputData.depth = 1e20; vn = mRot.RotateVector(CVector3(0.0, -1.0, 0.0)); } sRGBAfloat opacityOut; if (in.calcInside) //if the object interior is traced, then the absorption of light has to be calculated { for (int index = shaderInputData.stepCount - 1; index > 0; index--) { double step = shaderInputData.stepBuff[index].step; //CVector3 point = shaderInputData.stepBuff[index].point; //shaderInputData.point = point; //sRGBAfloat color = SurfaceColour(shaderInputData); //transparentColor.R = color.R; //transparentColor.G = color.G; //transparentColor.B = color.B; double opacity = -log(shaderInputData.material ->transparencyOfInterior) * step; if (opacity > 1.0) opacity = 1.0; resultShader.R = opacity * transparentColor.R + (1.0 - opacity) * resultShader.R; resultShader.G = opacity * transparentColor.G + (1.0 - opacity) * resultShader.G; resultShader.B = opacity * transparentColor.B + (1.0 - opacity) * resultShader.B; } } else //if now is outside the object, then calculate all volumetric effects like fog, glow... { volumetricShader = VolumetricShader(shaderInputData, resultShader, &opacityOut); resultShader = volumetricShader; } //prepare final result sRayRecursionOut out; out.point = point; out.rayMarchingOut = rayMarchingOut; out.objectColour = objectColour; out.resultShader = resultShader; out.found = (shaderInputData.depth == 1e20) ? false : true; out.fogOpacity = opacityOut.R; out.normal = vn; return out; }