RGBA Plate::EvalColor(ShadeContext& sc) { BMM_Color_64 c; IPoint2 s; int id = sc.NodeID(); PlateMap *pmap = FindMap(id); if (gbufID) sc.SetGBufferID(gbufID); if (pmap) { s = sc.ScreenCoord(); int w = pmap->bm->Width(); int h = pmap->bm->Height(); Point3 view = sc.OrigView(); Point3 v2 = sc.V(); Point3 p = sc.P(); Point3 dV,dvf; Point3 N0 = sc.OrigNormal(); Point3 vf = RefractVector(sc, N0, view, sc.GetIOR()); RenderGlobalContext *gc = sc.globContext; if (gc==NULL) return blackrgba; // total deflection due to refraction dV = view-v2; // deflection due to flat refracton (no bumps) dvf = view-vf; dV = refrAmt*(dV-dvf) + thick*dvf; // compute screen deflection: This is really a cheat, and the // scale factor is arbitrary. Infact it depends on the distance // between to the point on the glass plate and to the point being // seen behind it, which we don't know. // these should be multiplied by the factor (Zbehind-Zcur)/Zcur // This assumes that the factor is .1 float dsx,dsy; if (gc->projType==0) { // perspective dsx = dV.x*0.1f*gc->xscale; dsy = dV.y*0.1f*gc->yscale; } else { // parallel projection dsx = -dV.x*gc->xscale*10.0f; dsy = -dV.y*gc->yscale*10.0f; } if (gc->fieldRender) dsy *= 2.0f; int x = s.x - (pmap->org.x+gc->devWidth/2); int y = s.y - (pmap->org.y+gc->devHeight/2); if (applyBlur) { float du = 1.0f/float(w); float dv = 1.0f/float(h); float u = (float(x)+dsx)*du; float v = (float(y)+dsy)*dv; if (u<0.0f||u>1.0f||v<0.0f||v>1.0f) { if (useEnvMap) { return sc.EvalGlobalEnvironMap(view-dvf); } else return blackrgba; } else pmap->bm->GetFiltered(u,v, du*blur, dv*blur,&c); } else { int ix = x + int(dsx); int iy = y + int(dsy); if (ix<0||ix>=w||iy<0||iy>=h) { if (useEnvMap) return sc.EvalGlobalEnvironMap(view-dvf); else return blackrgba; } else pmap->bm->GetLinearPixels(ix,iy,1,&c); } return c; } else return blackrgba; }
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; }