public override bool getSample(RayContext rayContext, double ru, double rv, out Vector3 wi, out double invPdf) { Vector3 viewDir = rayContext.ray.dir; Vector3 normal = rayContext.hitData.hitNormal; Vector3 reflectDir = viewDir - (normal * (normal * viewDir) * 2.0); reflectDir.normalize(); Matrix3 shadingMatrix = new Matrix3(); shadingMatrix.computeTangentBasis(reflectDir); double pdf = 1; invPdf = 1; wi = MathUtils.getSpecularDir(ru, rv, glossy, out pdf); wi = shadingMatrix.transformVector(wi); wi.normalize(); if (pdf < 0.0001) return false; invPdf = 1.0 / pdf; double cosT = rayContext.hitData.hitNormal * wi; if (cosT < 0.0) return false; return true; }
public bool trace(RayContext rayContext) { double maxt = rayContext.ray.maxt; bool haveIntersection = false; foreach (GeomPrimitive primitive in m_primitives) { if (rayContext.ignorePrimitive == primitive) continue; //skip this primitive IntersectionData hitData = new IntersectionData(); if (primitive.intersect(rayContext.ray, hitData)) { if (maxt > hitData.hitT && hitData.hitT > rayContext.ray.mint) { maxt = hitData.hitT; rayContext.hitData = hitData; rayContext.hitData.hitPrimitive = primitive; haveIntersection = true; } if (haveIntersection) { rayContext.hitData.hitPos = rayContext.ray.p + rayContext.ray.dir * rayContext.hitData.hitT; } } }//foreach return haveIntersection; }
public Color3 getFilterColor(RayContext rayContext) { if (null != filterTexture) return filterTexture.evalColor(rayContext); return filterColor; }
public virtual Color3 eval(RayContext rayContext, Vector3 wi, out double pdf) { pdf = 1.0; if (null != filterTexture) return filterTexture.evalColor(rayContext); return filterColor; }
public Color3 getTransparency(RayContext rayContext) { Color3 transparency = filterColor.getWhiteComplement(); if (null != filterTexture) transparency = filterTexture.evalColor(rayContext).getWhiteComplement(); return transparency; }
public override Color3 eval(RayContext rayContext, Vector3 wi, out double pdf) { pdf = System.Math.Max( rayContext.hitData.hitNormal * wi, 0.0) * (1.0 / System.Math.PI); if (null != filterTexture) return filterTexture.evalColor(rayContext); return filterColor; }
public static RayContext createNewContext(RayContext previousContext, Ray newRay) { RayContext newContext = new RayContext(newRay); newContext.traceLevel += previousContext.traceLevel + 1; newContext.scene = previousContext.scene; newContext.ignorePrimitive = previousContext.hitData.hitPrimitive; newContext.m_renderer = previousContext.m_renderer; newContext.ignoreID = previousContext.ignoreID; newContext.m_rndContext = previousContext.m_rndContext.createNew(previousContext.randomIndex, 2); return newContext; }
public override bool getSample(RayContext rayContext, double ru, double rv, out Vector3 wi, out double invPdf) { //в каква посока гледа наблюдателят (входящ лъч) Vector3 viewDir = rayContext.ray.dir; //faceforward се грижи нормалата винаги да е от страната на входящия лъч Vector3 normal = MathUtils.faceforward(rayContext.hitData.hitNormal, viewDir); //намираме посоката на отразения лъч (изходящ лъч) wi = viewDir - (normal * (normal * viewDir) * 2.0); wi.normalize(); invPdf = 0; return true; }
public override Color3 eval(RayContext rayContext, Vector3 wi, out double pdf) { Vector3 viewDir = rayContext.ray.dir; Vector3 normal = rayContext.hitData.hitNormal; Vector3 reflectDir = viewDir - (normal * (normal * viewDir) * 2.0); reflectDir.normalize(); double cosA = wi * reflectDir; double k = 0.0f; if (cosA > 0.0f) k = System.Math.Pow(cosA, glossy) * (glossy + 1.0f) * (2.0 / System.Math.PI); pdf = k; return filterColor *k; }
public override bool getSample(RayContext rayContext, double ru, double rv, out Vector3 wi, out double invPdf) { Vector3 viewDir = rayContext.ray.dir; Vector3 normal = rayContext.hitData.hitNormal; double ior = 1.0 / m_ior; double thetaView = viewDir * normal; double thetaT = 1.0 - (ior * ior) * (1.0 - thetaView * thetaView); wi = new Vector3(0, 0, 0); invPdf = 0; if (thetaT < 0.0f) // проверка за пълно вътрешно отражение return false; wi = ior * viewDir - (ior * thetaView + System.Math.Sqrt(thetaT)) * normal; invPdf = 0; return true; }
public Color3 getRadiance(RayContext rayContext) { Vector3 d = new Vector3(); d.set( rayContext.ray.dir ); double len = System.Math.Sqrt(d.x*d.x + d.y*d.y); double r = (len<0.0001) ? 0.0f : System.Math.Acos(-d.z)/(2.0f*System.Math.PI*len); double u = r*d.x + 0.5f; double v = 0.5f - r*d.y; int w = m_skyTexture.getWidth(), h = m_skyTexture.getHeight(); double x = System.Math.Min(System.Math.Max(u, 0), 1); double y = System.Math.Min(System.Math.Max(v, 0), 1); Color3 c = new Color3();//m_skyTexture.evalColor(x, y); //System.Diagnostics.Debug.WriteLine(x.ToString()+" "+y.ToString()); return c; }
public override LightSample getSample(RayContext rayContext, double ru, double rv) { //намираме векрор между двете точки Vector3 dir = pos - rayContext.hitData.hitPos; //определяме каква част от сферата (пространствен ъгъл) покрива точката double solidAngle = (1.0 / (4.0 * System.Math.PI * dir.getLenghtSqr())); //максимална дистанция за търсене на пресичания double maxt = dir.getLenght(); dir.normalize(); //ако светлината се намира под повърхността от която е точката, //няма смисъл да пресмятаме нищо if (dir * (rayContext.hitData.hitNormal) <= 0) return null; //създаваме "сонда за сянка" и попълваме LightSample sample = new LightSample(); sample.shadowRay = new Ray(); sample.shadowRay.p.set(rayContext.hitData.hitPos); sample.shadowRay.dir.set(dir); sample.shadowRay.maxt = maxt; //задаваме енергията (изпратена през пространствения ъгъл) sample.color = color * (power * solidAngle); return sample; }
public Color3 illuminate(RayContext rayContext, BRDF brdf) { Color3 finalColor = new Color3(); BRDFTypes brdfType = brdf.getType(); if (brdf.matchTypes(BRDFTypes.Diffuse) || brdf.matchTypes(BRDFTypes.Glossy)) { if (null != m_directLightIntegrator) finalColor += m_directLightIntegrator.illuminate(rayContext, brdf); if (brdf.matchTypes(BRDFTypes.Diffuse) && null != m_diffuseIntegrator) finalColor += m_diffuseIntegrator.illuminate(rayContext, brdf); } if (brdf.matchTypes(BRDFTypes.Specular)) { if (rayContext.traceLevel < m_maxTraceLevel) if (null != m_specularIntegrator) finalColor += m_specularIntegrator.illuminate(rayContext, brdf); } return finalColor; }
public Color3 evalColor(RayContext rayContext) { return evalColorBilinear(rayContext.hitData.textureUVW.x, rayContext.hitData.textureUVW.y); }
public override void shade(RayContext rayContext) { rayContext.resultColor = texture.evalColor(rayContext); }
public abstract void shade(RayContext rayContext);
//return True if the sample ray is valid and False otherwise public abstract bool getSample(RayContext rayContext, double ru, double rv, out Vector3 wi, out double invPdf);
public static RayContext startFromPixel(Ray startRay, int pixX, int pixY, Scene _scene, IIntegrator integrator) { RayContext newContext = new RayContext(startRay); newContext.scene = _scene; newContext.m_renderer = integrator; newContext.m_rndContext = new RandomContext(2, 17 * pixX + 73 * pixY); return newContext; }
public Color3 shadeBackground(RayContext rayContext) { if (null != m_skyDome) return m_skyDome.getRadiance(rayContext); return backgroundColor; }
public bool trace(RayContext rayContext) { return m_bruteforceTracer.trace( rayContext ); }
public static RayContext createNewContextGI(RayContext previousContext, Ray newRay) { RayContext newContext = createNewContext(previousContext, newRay); newContext.traceLevelGI += previousContext.traceLevelGI + 1; return newContext; }
public void shade(RayContext rayContext) { if( trace(rayContext) ) { if( null != rayContext.hitData.hitPrimitive ) { rayContext.hitData.hitPrimitive.shader.shade(rayContext); return; } } rayContext.resultColor.set( shadeBackground(rayContext) ); }
public bool traceShadowRay(Ray shadowRay, RayContext origContext) { RayContext rayContext = RayContext.createNewContext(origContext, shadowRay); rayContext.ignorePrimitive = origContext.hitData.hitPrimitive; rayContext.isShadowRay = true; return trace(rayContext); }
public bool trace(RayContext rayContext) { GeomPrimitive hitObject; rayContext.hitData = null; GetIntersection(rayContext.ray.p, rayContext.ray.dir, rayContext.ignorePrimitive, out hitObject, rayContext.ray.p, rayContext); if (rayContext.hitData == null) return false; return rayContext.hitData.hasIntersection ; }
public void GetIntersection( Vector3 rayOrigin, Vector3 rayDirection, GeomPrimitive lastHit, out GeomPrimitive pHitObject, Vector3 pStart, RayContext rayContext) { //hitPosition = null; pHitObject = null; // is branch: step through subcells and recurse if (isBranch) { //if (pStart == null) // pStart = rayOrigin; // find which subcell holds ray origin (ray origin is inside cell) int subCell = 0; for (int i = 3; i-- > 0; ) { // compare dimension with center if (pStart[i] >= ((bound[i] + bound[i + 3]) * 0.5f)) subCell |= 1 << i; } // step through intersected subcells Vector3 cellPosition = new Vector3(pStart); for (; ; ) { if (null != spatial[subCell]) { // intersect subcell spatial[subCell].GetIntersection(rayOrigin, rayDirection, lastHit, out pHitObject, cellPosition, rayContext); // exit if item hit if (null != pHitObject) break; } // find next subcell ray moves to // (by finding which face of the corner ahead is crossed first) int axis = 2; float[] step = new float[3]; // todo - move this allocation? for (int i = 3; i-- > 0; axis = step[i] < step[axis] ? i : axis) { bool high = ((subCell >> i) & 1) != 0; float face = (rayDirection[i] < 0.0f) ^ high ? bound[i + ((high ? 1 : 0) * 3)] : (bound[i] + bound[i + 3]) * 0.5f; // distance to face // (div by zero produces infinity, which is later discarded) step[i] = (float)(face - rayOrigin[i]) / (float)rayDirection[i]; } // leaving branch if: subcell is low and direction is negative, // or subcell is high and direction is positive if ((((subCell >> axis) & 1) != 0) ^ (rayDirection[axis] < 0.0f)) break; // move to (outer face of) next subcell cellPosition = rayOrigin + (rayDirection * step[axis]); subCell = subCell ^ (1 << axis); } } else { // is leaf: exhaustively intersect contained items //float nearestDistance = float.MaxValue; // step through items foreach (GeomPrimitive item in triangles) { if (rayContext.ignorePrimitive == item) continue; //skip this primitive if (item == lastHit) continue; //skip this primitive IntersectionData hitData = new IntersectionData(); if (item.intersect(rayContext.ray, hitData)) { // check intersection is inside cell bound (with tolerance) Vector3 hit = rayOrigin + (rayDirection * hitData.hitT); float t = TOLERANCE; if ((bound[0] - hit[0] <= t) && (hit[0] - bound[3] <= t) && (bound[1] - hit[1] <= t) && (hit[1] - bound[4] <= t) && (bound[2] - hit[2] <= t) && (hit[2] - bound[5] <= t)) { pHitObject = item; //nearestDistance = distance; //hitPosition = hit; rayContext.hitData = hitData; rayContext.hitData.hitPrimitive = item; rayContext.hitData.hitPos = rayContext.ray.p + rayContext.ray.dir * rayContext.hitData.hitT; rayContext.hitData.hasIntersection = true; } } } } }
public Color3 illuminate(RayContext rayContext, BRDF brdf) { return new Color3(); }
public Color3 illuminate(RayContext rayContext, BRDF brdf) { //вземаме списък с всички светлини в сцената List<Light> lights = rayContext.scene.getLights(); //в sumColor ще сумираме тяхната енергия Color3 sumColor = new Color3(); foreach (Light light in lights) { Color3 color = new Color3(); //задаваме максималната бройка лъчи //с които ще проследяваме към всяка светлина int numSamples = 25; int curSample = 0; //номер на текущ лъч LightSample lightSample; rayContext.randomIndex = 0; do { curSample++; //генерирме двойка случайни числа (ru, rv) double ru = rayContext.getRandom(0, curSample); double rv = rayContext.getRandom(1, curSample); //искаме от светлината да върне сонда за сянка lightSample = light.getSample(rayContext, ru, rv); rayContext.randomIndex++; if (null == lightSample) continue; //пресмятаме косинуса между нормалата на повърхността и лъча към лампата double cosT = rayContext.hitData.hitNormal * (lightSample.shadowRay.dir); if (cosT < 0.00001) cosT = 0.0; //проверяваме за засенчване if (rayContext.scene.traceShadowRay(lightSample.shadowRay, rayContext)) continue; double pdf = 1.0; //пресмятаме, каква част от светлината ще отрази BRFD-a Color3 brdfCol = brdf.eval(rayContext, lightSample.shadowRay.dir, out pdf); color += brdfCol * pdf * lightSample.color * cosT; //ако светлината е точкова ни е нужен само един лъч if (light.isSingular()) break; } while (curSample < numSamples); if (curSample < 1) curSample = 1; //сумираме резултата от всички сампъли color *= 1.0 / (double)curSample; sumColor += color; } int lightsCount = lights.Count; if (lightsCount < 1) lightsCount = 1; //сумираме енергията от всички светлини sumColor *= 1.0 / (double)lightsCount; return sumColor; }
public abstract LightSample getSample(RayContext rayContext, double ru, double rv);
public override void shade(RayContext rayContext) { rayContext.resultColor = color; }
public Color3 illuminate(RayContext rayContext, BRDF brdf) { Ray newRay = new Ray(); double invPdf = 0; //във finalColor ще сумираме резултатния цвят Color3 finalColor = new Color3(); //задаваме максималната бройка лъчи //с които ще проследяваме грапави отражения int numSamples = 10; int curSample = 0; //номер на текущ лъч for (curSample = 0; curSample < numSamples; curSample++) { //генерирме двойка случайни числа (ru, rv) double ru = rayContext.getRandom(0, curSample); double rv = rayContext.getRandom(1, curSample); //искаме brdf да конструира лъч използвайки (ru, rv) bool isValidSample = brdf.getSample(rayContext, ru, rv, out newRay.dir, out invPdf); if (!isValidSample) continue; //конструираме нов лъч от текущата точка //и го обвиваме във собствен контекст newRay.p = rayContext.hitData.hitPos; RayContext newContext = RayContext.createNewContext(rayContext, newRay); //извикваме функцията shade, която проследява //лъча в сцената и го осветява rayContext.scene.shade(newContext); double cosT = rayContext.hitData.hitNormal * (newRay.dir); if (cosT < 0.0) cosT *= -1.0; double pdf; Color3 w = new Color3(1, 1, 1); //пресмятаме, каква част от светлината ще отрази BRFD-a w = brdf.eval(rayContext, newRay.dir, out pdf); if (!brdf.isSingular()) { w *= cosT * invPdf; } //добавяме енергията на новия лъч finalColor += newContext.resultColor * w; //if (Double.IsNaN(finalColor.getIntensity())) // break; if (brdf.isSingular()) break; } //сумираме енергията от всички лъчи if (curSample > 0) finalColor *= 1.0 / (double)curSample; return finalColor; }