public KdTree(int maxDepth, int maxLeavePrimitives, SceneDatabase sceneDatabase) { mMaxNumOfPrimitives = maxLeavePrimitives; mMaxDepth = maxDepth; // List <RTGeometry> allGeom = new List <RTGeometry>(); Vector3 worldMin = new Vector3(float.MaxValue); Vector3 worldMax = new Vector3(float.MinValue); // we need to compute the compute the world min/max for (int i = 0; i < sceneDatabase.GetNumGeom(); i++) { RTGeometry g = sceneDatabase.GetGeom(i); allGeom.Add(g); worldMin = Vector3.Min(worldMin, g.Min); worldMax = Vector3.Max(worldMax, g.Max); } int rootDepth = 0; mRoot = new KdTreeNode(worldMin, worldMax, new KdTreeAxis(rootDepth), allGeom); BuildKDTree(mRoot, rootDepth, allGeom); }
/// <summary> /// Diffuse color lookup: if texture mapped, scale the texture value by mKd /// </summary> /// <param name="database"></param> /// <param name="rec"></param> /// <returns></returns> public Vector3 GetDiffuse(SceneDatabase database, IntersectionRecord rec) { Vector3 result = mKd.AttributeValue(); if (mKd.IsTextureMapped()) { result *= mKd.AttributeLookup(database, rec); } return(result); }
public RTCore(RTWindow w, String cmdFile, ContentManager meshLoader) { mRTWindows = w; mSceneDatabase = new SceneDatabase(); mParser = new CommandFileParser(cmdFile, meshLoader, w.StatusArea(), this, mSceneDatabase); mCurrentX = mCurrentY = 0; // FirstTimeInit(); }
/// <summary> /// Transparency look up: if mapped, scales Avg(RBG) by transparency /// </summary> /// <param name="database"></param> /// <param name="rec"></param> /// <returns></returns> public float GetTransparency(SceneDatabase database, IntersectionRecord rec) { float result = mTransparency.AttributeValue(); if (mTransparency.IsTextureMapped()) { Vector3 v = mTransparency.AttributeLookup(database, rec); result *= ((v.X + v.Y + v.Z) / 3f); } return(result); }
/// <summary> /// Percentage of the light that is visible from the visiblePt /// </summary> /// <param name="visiblePt"></param> /// <param name="exceptGeomIndex">this geometry can never block the light (geomIndex of the visiblePt)</param> /// <param name="database"></param> /// <returns></returns> public virtual float PercentVisible(Vector3 visiblePt, int exceptGeomIndex, SceneDatabase sceneDatabase) { IntersectionRecord rec = new IntersectionRecord(DistanceToLight(visiblePt)); Ray r = Ray.CrateRayFromPtDir(visiblePt, GetNormalizedDirection(visiblePt)); bool blocked = false; int count = 0; while ((!blocked) && (count < sceneDatabase.GetNumGeom())) { if (count != exceptGeomIndex) { blocked = sceneDatabase.GetGeom(count).Intersect(r, rec); } count++; } return(blocked ? 0f : 1f); }
/// <summary> /// How much of the spot light is visible from the visiblePt /// </summary> /// <param name="visiblePt"></param> /// <param name="exceptGeomIndex">this geometry can never block the light (geomIndex of the visiblePt)</param> /// <param name="database"></param> /// <returns></returns> public override float PercentVisible(Vector3 visiblePt, int exceptGeomIndex, SceneDatabase sceneDatabase) { float cosAlpha = 0f; bool canIllum = InLightCone(visiblePt, ref cosAlpha); float percent = 0f; if (canIllum) { if (mUseDepthMap) { percent = SampleDepthMap(visiblePt, exceptGeomIndex); } else { percent = base.PercentVisible(visiblePt, exceptGeomIndex, sceneDatabase); } } return(percent); }
/// <summary> /// Normal vector lookup, if texture mapped, replaces the intersection record's normal vector! /// </summary> /// <param name="database"></param> /// <param name="rec"></param> /// <returns></returns> public Vector3 GetNormal(SceneDatabase database, IntersectionRecord rec) { Vector3 result; if (mNormal.IsTextureMapped()) { result = mNormal.AttributeLookup(database, rec); if (Vector3.Dot(result, rec.NormalAtIntersect) < 0) { result = -result; } rec.SetNormalAtIntersection(result); } else { result = rec.NormalAtIntersect; } return(result); }
private void AddLights(RayTracer_552.SceneDatabase rtScene) { UWB_XNAGraphicsDevice.m_TheAPI.LightManager.ResetAllLights(); for (int l = 0; l < rtScene.GetNumLights(); l++) { RTLight lgt = rtScene.GetLight(l); Vector4 useColor = new Vector4(lgt.GetColor(new Vector3(0, 0, 0)), 1f); UWB_XNALight theLight = null; if (lgt.GetLightSourceType() == RTLightType.RTLightSourceType.RTLightSourceTypeDirection) { theLight = UWB_XNAGraphicsDevice.m_TheAPI.LightManager.CreateDirectionalLight(); } else if (lgt.GetLightSourceType() == RTLightType.RTLightSourceType.RTLightSourceTypeSpot) { theLight = UWB_XNAGraphicsDevice.m_TheAPI.LightManager.CreateSpotLight(); } else { theLight = UWB_XNAGraphicsDevice.m_TheAPI.LightManager.CreatePointLight(); } theLight.Ambient = Vector4.Zero; theLight.Diffuse = useColor; theLight.Specular = useColor; theLight.Position = lgt.GetLightPosition(); theLight.Direction = -lgt.GetNormalizedDirection(Vector3.Zero); theLight.Color = useColor; theLight.Attenuation = new Vector3(1f, 0.0f, 0.0f); theLight.Range = 10000f; theLight.SwitchOnLight(); UWB_Primitive prim = CreateSphereMesh(); SetMeshMaterial(prim, rtScene.GetMaterial(0)); float scale = 0.25f; CreateNode(lgt.GetLightPosition(), scale, scale, scale, prim); } }
public KdTree(int maxDepth, int maxLeavePrimitives, SceneDatabase sceneDatabase) { mMaxNumOfPrimitives = maxLeavePrimitives; mMaxDepth = maxDepth; // List<RTGeometry> allGeom = new List<RTGeometry>(); Vector3 worldMin = new Vector3(float.MaxValue); Vector3 worldMax = new Vector3(float.MinValue); // we need to compute the compute the world min/max for (int i = 0; i < sceneDatabase.GetNumGeom(); i++) { RTGeometry g = sceneDatabase.GetGeom(i); allGeom.Add(g); worldMin = Vector3.Min(worldMin, g.Min); worldMax = Vector3.Max(worldMax, g.Max); } int rootDepth = 0; mRoot = new KdTreeNode(worldMin, worldMax, new KdTreeAxis(rootDepth), allGeom); BuildKDTree(mRoot, rootDepth, allGeom); }
public CommandFileParser(String cmdFile, ContentManager meshLoader, System.Windows.Forms.TextBox statusArea, RTCore rt, SceneDatabase scene) { mStatusArea = statusArea; mFullPath = System.IO.Path.GetFullPath(System.IO.Path.GetDirectoryName(cmdFile)); mParser = new XmlTextReader(cmdFile); mParser.WhitespaceHandling = WhitespaceHandling.None; ParserRead(); while (!IsEndElement("RayTracer_552")) { if (IsElement() && (!IsElement("RayTracer_552")) ) { if (IsElement("camera")) { RTCamera c = new RTCamera(this); rt.SetCamera(c); ParserRead(); } else if (IsElement("sphere")) { RTSphere s = new RTSphere(this); scene.AddGeom(s); ParserRead(); } else if (IsElement("rectangle")) { RTRectangle r = new RTRectangle(this); scene.AddGeom(r); ParserRead(); } else if (IsElement("triangle")) { RTTriangle t = new RTTriangle(this); scene.AddGeom(t); ParserRead(); } else if (IsElement("mesh")) { RTTriangle.ParseMeshForTriangles(this, meshLoader, scene); ParserRead(); } else if (IsElement("imagespec")) { ImageSpec s = new ImageSpec(this); rt.SetImageSpec(s); ParserRead(); } else if (IsElement("rtspec")) { rt.Parse(this); ParserRead(); } else if (IsElement("material")) { RTMaterial m = new RTMaterial(this); scene.AddMaterial(m); ParserRead(); } else if (IsElement("light")) { RTLight l = new RTLight(this); scene.AddLight(l); ParserRead(); } else if (IsElement("texture")) { RTTexture t = new RTTexture(this); scene.AddTexture(t); ParserRead(); } else ParserError("Main Parser:"); } else ParserRead(); } mParser.Close(); if (!mHasError) mStatusArea.Text = "Parsing Completed!"; }
public override void InitializeLight(SceneDatabase sceneDatabase) { InitDepthMap(sceneDatabase); }
internal void AddRTScene(RayTracer_552.RTCamera c, RayTracer_552.SceneDatabase rtScene) { UWB_Primitive prim; NewSceneDatabase(); SceneResource <RTGeometry> allGeom = rtScene.GetAllGeom(); for (int i = 0; i < allGeom.Count; i++) { RTGeometry g = (RTGeometry)allGeom.ResourceLookup(i); switch (g.GeomType()) { case RTGeometry.RTGeometryType.Sphere: RTSphere s = (RTSphere)g; prim = CreateSphereMesh(); SetMeshMaterial(prim, rtScene.GetMaterial(s.GetMaterialIndex())); float scale = s.Radius / 2f; CreateNode(s.Center, scale, scale, scale, prim); break; case RTGeometry.RTGeometryType.Rectangle: RTRectangle r = (RTRectangle)g; prim = CreateRectangle(r); SetMeshMaterial(prim, rtScene.GetMaterial(r.GetMaterialIndex())); UWB_SceneNode node = CreateNode(r.GetCenter(), r.GetUSize() / 2f, 1f, r.GetVSize() / 2f, prim); // now rotate the y-vector of node to point towards r.Normal; float dot = (float)Math.Abs(Vector3.Dot(Vector3.UnitY, r.GetNormal())); if (dot < 0.9999f) { float angle = (float)Math.Acos(dot); Vector3 axis = Vector3.Cross(Vector3.UnitY, r.GetNormal()); axis.Normalize(); Quaternion q = Quaternion.CreateFromAxisAngle(axis, angle); UWB_XFormInfo xf = node.getXFormInfo(); xf.SetRotationQuat(q); node.setXFormInfo(xf); } break; case RTGeometry.RTGeometryType.Triangle: RTTriangle t = (RTTriangle)g; Vector3[] v = t.GetVertices(); prim = new UWB_PrimitiveTriangle(v[0], v[1], v[2]); prim.EnableLighting(true); prim.EnableTexturing(false); SetMeshMaterial(prim, rtScene.GetMaterial(t.GetMaterialIndex())); CreateNode(Vector3.Zero, 1f, 1f, 1f, prim); break; } } AddCamera(c); AddLights(rtScene); // to show ray list mShownRayX = mShownRayY = 0; mRaysToShow = new UWB_PrimitiveList(); mDebugInfo = new UWB_SceneNode(); mDebugInfo.setPrimitive(mRaysToShow); mDebugInfo.insertChildNode(mPixelsToShow.GetAllPixels()); mDebugInfo.insertChildNode(mPixelInWorld.GetAllPixels()); }
public float PercentVisible(Vector3 visiblePt, int exceptGeomIndex, SceneDatabase sceneDatabase) { return(mLight.PercentVisible(visiblePt, exceptGeomIndex, sceneDatabase)); }
public CommandFileParser(String cmdFile, ContentManager meshLoader, System.Windows.Forms.TextBox statusArea, RTCore rt, SceneDatabase scene) { mStatusArea = statusArea; mFullPath = System.IO.Path.GetFullPath(System.IO.Path.GetDirectoryName(cmdFile)); mParser = new XmlTextReader(cmdFile); mParser.WhitespaceHandling = WhitespaceHandling.None; ParserRead(); while (!IsEndElement("RayTracer_552")) { if (IsElement() && (!IsElement("RayTracer_552"))) { if (IsElement("camera")) { RTCamera c = new RTCamera(this); rt.SetCamera(c); ParserRead(); } else if (IsElement("sphere")) { RTSphere s = new RTSphere(this); scene.AddGeom(s); ParserRead(); } else if (IsElement("rectangle")) { RTRectangle r = new RTRectangle(this); scene.AddGeom(r); ParserRead(); } else if (IsElement("triangle")) { RTTriangle t = new RTTriangle(this); scene.AddGeom(t); ParserRead(); } else if (IsElement("mesh")) { RTTriangle.ParseMeshForTriangles(this, meshLoader, scene); ParserRead(); } else if (IsElement("imagespec")) { ImageSpec s = new ImageSpec(this); rt.SetImageSpec(s); ParserRead(); } else if (IsElement("rtspec")) { rt.Parse(this); ParserRead(); } else if (IsElement("material")) { RTMaterial m = new RTMaterial(this); scene.AddMaterial(m); ParserRead(); } else if (IsElement("light")) { RTLight l = new RTLight(this); scene.AddLight(l); ParserRead(); } else if (IsElement("texture")) { RTTexture t = new RTTexture(this); scene.AddTexture(t); ParserRead(); } else { ParserError("Main Parser:"); } } else { ParserRead(); } } mParser.Close(); if (!mHasError) { mStatusArea.Text = "Parsing Completed!"; } }
private int mRes = 128; // depth map resolution is Res x Res #endregion Fields #region Methods private void InitDepthMap(SceneDatabase sceneDatabase) { if (null != mDepthMap) return; // done // remember!! mDireciton is L, or a vector from Visible point to the light. // Here we want direction from light source towards the scene Vector3 useDir = -mDirection; // 1. Find a Up direction // guess up direction to be (0, 1, 0), if view direction is also this, // use (1, 0, 0) as view direction Vector3 up = Vector3.UnitY; if (Math.Abs(Vector3.Dot(up, useDir)) > 0.99999) up = Vector3.UnitX; // 2. define Orthonormal base Vector3 sideV = Vector3.Cross(up, useDir); up = Vector3.Cross(useDir, sideV); sideV.Normalize(); up.Normalize(); // 3. compute the depth map image plane, // define the image plane to be located at ... a distance of kDepthImageDist away Vector3 ptOnImage = mPosition + kDepthImageDist * useDir; // 4. compute depth map image size float halfImageSize = kDepthImageDist * (float)Math.Tan(mOuterAngle/2f); // 5. Compute the 4 vertices the defines the depth map Vector3[] v = new Vector3[4]; v[0] = ptOnImage - halfImageSize * up - halfImageSize * sideV; v[1] = ptOnImage - halfImageSize * up + halfImageSize * sideV; v[2] = ptOnImage + halfImageSize * up + halfImageSize * sideV; v[3] = ptOnImage + halfImageSize * up - halfImageSize * sideV; // 6. create a Geometry that represents the map // ** Be caureful **!! // RTRectangle uses v[0] as the origin for texture lookup // we _MUST_ follow the same in order to take advante of GetUV() function! mDepthMapGeom = new RTRectangle(v); // 7. Now allocate memory for the actual map mDepthMap = new float[mRes][]; mGeomID = new int[mRes][]; for (int i = 0; i<mRes; i++) { mDepthMap[i] = new float[mRes]; mGeomID[i] = new int[mRes]; } // now, trace rays through each of the pixels in the depth map and record the depth and geomID float pixelSize = halfImageSize / (0.5f * mRes); Vector3 upPixelVector = pixelSize * up; Vector3 sidePixelVector = pixelSize * sideV; for (int y = 0; y < mRes; y++) { Vector3 yDisp = v[0] + (y+0.5f) * upPixelVector; for (int x = 0; x < mRes; x++) { Vector3 pixelPos = ((x+0.5f) * sidePixelVector) + yDisp; Ray r = new Ray(mPosition, pixelPos); IntersectionRecord rec = new IntersectionRecord(); for (int i = 0; i < sceneDatabase.GetNumGeom(); i++) { RTGeometry g = sceneDatabase.GetGeom(i); g.Intersect(r, rec); } mDepthMap[x][y] = rec.HitDistance; // closes intersection distance, any object that is // further away from the light than this distance is in the shadow of this light mGeomID[x][y] = rec.GeomIndex; // this object can never be in shadow, becuase it is the closest to the light! } } }
/// <summary> /// Looks up attribute from the texture table! NO ERROR CHECKINGG! If mTextureIndex is invalid, this function will crash!! /// </summary> /// <param name="database"></param> /// <param name="rec"></param> /// <returns></returns> public Vector3 AttributeLookup(SceneDatabase database, IntersectionRecord rec) { return(database.GetTexture(mTextureIndex).TextureLookup(rec, database.GetGeom(rec.GeomIndex))); }
public float PercentVisible(Vector3 visiblePt, int exceptGeomIndex, SceneDatabase sceneDatabase) { return mLight.PercentVisible(visiblePt, exceptGeomIndex, sceneDatabase); }
static public void ParseMeshForTriangles(CommandFileParser parser, ContentManager meshLoader, SceneDatabase sceneDatabase) { String meshFileName = null; int material = 0; // has xform? bool hasTransform = false; Matrix xform = Matrix.Identity; Matrix invT = Matrix.Identity; #region Parse the command file parser.ParserRead(); while (!parser.IsEndElement("mesh")) { if (parser.IsElement() && (!parser.IsElement("mesh"))) { if (parser.IsElement("filename")) { meshFileName = parser.ReadString(); } else if (parser.IsElement("xform")) { hasTransform = true; xform = ParseTransform(parser); } else if (parser.IsElement("material")) { material = parser.ReadInt(); } else { parser.ParserError("mesh"); } } else { parser.ParserRead(); } } #endregion if (null == meshFileName) { parser.ParserError("No Mesh filename!"); return; } if (hasTransform) { invT = Matrix.Transpose(Matrix.Invert(xform)); } Model model = meshLoader.Load <Model>(meshFileName); Byte[] localVertexBuffer = null; Int32[] localIndexBuffer = null; Vector3[] vertexPosition = null; Vector3[] normalAtVertex = null; Vector2[] uvAtVertex = null; bool hasPosition = false; bool hasNormal = false; bool hasUV = false; foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { int numIndices = part.IndexBuffer.IndexCount; // total number of localIndexBuffer in the buffer int numVertices = part.VertexBuffer.VertexCount; // total number of vertices in the buffer #region Only need to load/translate these buffers once! // *** REALLY? *** if (null == localIndexBuffer) { vertexPosition = new Vector3[numVertices]; normalAtVertex = new Vector3[numVertices]; uvAtVertex = new Vector2[numVertices]; localIndexBuffer = LoadIndexBuffer(part); int numBytes = numVertices * part.VertexBuffer.VertexDeclaration.VertexStride; localVertexBuffer = new Byte[numBytes]; part.VertexBuffer.GetData <Byte>(localVertexBuffer); VertexElement[] vertexElements = part.VertexBuffer.VertexDeclaration.GetVertexElements(); int bufferOffset = 0; #region parse each vertex // now get all the vertices for (int vertCount = 0; vertCount < numVertices; vertCount++) { // parse through the elements bufferOffset = vertCount * part.VertexBuffer.VertexDeclaration.VertexStride; hasUV = false; // do this for each vertex for (int e = 0; e < vertexElements.Length; e++) { switch (vertexElements[e].VertexElementUsage) { case VertexElementUsage.Position: hasPosition = true; // Vertex position int vertexByteOffset = bufferOffset + vertexElements[e].Offset; vertexPosition[vertCount].X = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); vertexByteOffset += 4; vertexPosition[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); vertexByteOffset += 4; vertexPosition[vertCount].Z = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); break; case VertexElementUsage.Normal: hasNormal = true; int normalByteOffset = bufferOffset + vertexElements[e].Offset; normalAtVertex[vertCount].X = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); normalByteOffset += 4; normalAtVertex[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); normalByteOffset += 4; normalAtVertex[vertCount].Z = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); break; case VertexElementUsage.TextureCoordinate: if (!hasUV) { // if more than one defined, will only use the first one hasUV = true; int uvByteOffset = bufferOffset + vertexElements[e].Offset; uvAtVertex[vertCount].X = BitConverter.ToSingle(localVertexBuffer, uvByteOffset); uvByteOffset += 4; uvAtVertex[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, uvByteOffset); } break; // ignore all other cases } // the switch on usage for parsing } // for of vertexElements } // for each vertex #endregion #region compute the transform for each vertex // now do the transform if (hasTransform) { for (int v = 0; v < numVertices; v++) { vertexPosition[v] = Vector3.Transform(vertexPosition[v], xform); } if (hasNormal) { for (int v = 0; v < numVertices; v++) { normalAtVertex[v] = Vector3.Transform(normalAtVertex[v], invT); normalAtVertex[v] = Vector3.Normalize(normalAtVertex[v]); } } } #endregion } #endregion // now start working on this particular part ... int startIndex = part.StartIndex; int vertexOffset = part.VertexOffset; // start from part.StartIndex int numTriangles = part.PrimitiveCount; #region create the triangles // now all vertice are stored. // let's create the Triangles for (int nthT = 0; nthT < numTriangles; nthT++) { Vector3[] vertices = new Vector3[3]; Vector2[] uv = new Vector2[3]; Vector3[] normals = null; if (hasNormal) { normals = new Vector3[3]; } #region copy vertex info int indexOffset = startIndex + (nthT * 3); for (int i = 0; i < 3; i++) { int index = vertexOffset + localIndexBuffer[indexOffset + i]; vertices[i] = vertexPosition[index]; uv[i] = uvAtVertex[index]; if (hasNormal) { normals[i] = normalAtVertex[index]; } } #endregion // now create the new triangle // watch out for bad triangles!! if (hasPosition) { if (!hasNormal) { normalAtVertex = null; } Vector3 aVec = vertices[1] - vertices[0]; if (aVec.LengthSquared() > float.Epsilon) { Vector3 bVec = vertices[2] - vertices[0]; if (bVec.LengthSquared() > float.Epsilon) { RTTriangle t = new RTTriangle(vertices, normals, uv, material); sceneDatabase.AddGeom(t); } } } } #endregion } } }
public void InitializeLight(SceneDatabase sceneDataBase) { mLight.InitializeLight(sceneDataBase); }
public static void ParseMeshForTriangles(CommandFileParser parser, ContentManager meshLoader, SceneDatabase sceneDatabase) { String meshFileName = null; int material = 0; // has xform? bool hasTransform = false; Matrix xform = Matrix.Identity; Matrix invT = Matrix.Identity; #region Parse the command file parser.ParserRead(); while (!parser.IsEndElement("mesh")) { if (parser.IsElement() && (!parser.IsElement("mesh"))) { if (parser.IsElement("filename")) { meshFileName = parser.ReadString(); } else if (parser.IsElement("xform")) { hasTransform = true; xform = ParseTransform(parser); } else if (parser.IsElement("material")) material = parser.ReadInt(); else parser.ParserError("mesh"); } else parser.ParserRead(); } #endregion if (null == meshFileName) { parser.ParserError("No Mesh filename!"); return; } if (hasTransform) invT = Matrix.Transpose(Matrix.Invert(xform)); Model model = meshLoader.Load<Model>(meshFileName); Byte[] localVertexBuffer = null; Int32[] localIndexBuffer = null; Vector3[] vertexPosition = null; Vector3[] normalAtVertex = null; Vector2[] uvAtVertex = null; bool hasPosition = false; bool hasNormal = false; bool hasUV = false; foreach (ModelMesh mesh in model.Meshes) { foreach (ModelMeshPart part in mesh.MeshParts) { int numIndices = part.IndexBuffer.IndexCount; // total number of localIndexBuffer in the buffer int numVertices = part.VertexBuffer.VertexCount; // total number of vertices in the buffer #region Only need to load/translate these buffers once! // *** REALLY? *** if (null == localIndexBuffer) { vertexPosition = new Vector3[numVertices]; normalAtVertex = new Vector3[numVertices]; uvAtVertex = new Vector2[numVertices]; localIndexBuffer = LoadIndexBuffer(part); int numBytes = numVertices * part.VertexBuffer.VertexDeclaration.VertexStride; localVertexBuffer = new Byte[numBytes]; part.VertexBuffer.GetData<Byte>(localVertexBuffer); VertexElement[] vertexElements = part.VertexBuffer.VertexDeclaration.GetVertexElements(); int bufferOffset = 0; #region parse each vertex // now get all the vertices for (int vertCount = 0; vertCount < numVertices; vertCount++) { // parse through the elements bufferOffset = vertCount * part.VertexBuffer.VertexDeclaration.VertexStride; hasUV = false; // do this for each vertex for (int e = 0; e < vertexElements.Length; e++) { switch (vertexElements[e].VertexElementUsage) { case VertexElementUsage.Position: hasPosition = true; // Vertex position int vertexByteOffset = bufferOffset + vertexElements[e].Offset; vertexPosition[vertCount].X = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); vertexByteOffset += 4; vertexPosition[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); vertexByteOffset += 4; vertexPosition[vertCount].Z = BitConverter.ToSingle(localVertexBuffer, vertexByteOffset); break; case VertexElementUsage.Normal: hasNormal = true; int normalByteOffset = bufferOffset + vertexElements[e].Offset; normalAtVertex[vertCount].X = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); normalByteOffset += 4; normalAtVertex[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); normalByteOffset += 4; normalAtVertex[vertCount].Z = BitConverter.ToSingle(localVertexBuffer, normalByteOffset); break; case VertexElementUsage.TextureCoordinate: if (!hasUV) { // if more than one defined, will only use the first one hasUV = true; int uvByteOffset = bufferOffset + vertexElements[e].Offset; uvAtVertex[vertCount].X = BitConverter.ToSingle(localVertexBuffer, uvByteOffset); uvByteOffset += 4; uvAtVertex[vertCount].Y = BitConverter.ToSingle(localVertexBuffer, uvByteOffset); } break; // ignore all other cases } // the switch on usage for parsing } // for of vertexElements } // for each vertex #endregion #region compute the transform for each vertex // now do the transform if (hasTransform) { for (int v = 0; v < numVertices; v++) vertexPosition[v] = Vector3.Transform(vertexPosition[v], xform); if (hasNormal) for (int v = 0; v < numVertices; v++) { normalAtVertex[v] = Vector3.Transform(normalAtVertex[v], invT); normalAtVertex[v] = Vector3.Normalize(normalAtVertex[v]); } } #endregion } #endregion // now start working on this particular part ... int startIndex = part.StartIndex; int vertexOffset = part.VertexOffset; // start from part.StartIndex int numTriangles = part.PrimitiveCount; #region create the triangles // now all vertice are stored. // let's create the Triangles for (int nthT = 0; nthT < numTriangles; nthT++) { Vector3[] vertices = new Vector3[3]; Vector2[] uv = new Vector2[3]; Vector3[] normals = null; if (hasNormal) normals = new Vector3[3]; #region copy vertex info int indexOffset = startIndex + (nthT * 3); for (int i = 0; i < 3; i++) { int index = vertexOffset + localIndexBuffer[indexOffset + i]; vertices[i] = vertexPosition[index]; uv[i] = uvAtVertex[index]; if (hasNormal) normals[i] = normalAtVertex[index]; } #endregion // now create the new triangle // watch out for bad triangles!! if (hasPosition) { if (!hasNormal) normalAtVertex = null; Vector3 aVec = vertices[1] - vertices[0]; if (aVec.LengthSquared() > float.Epsilon) { Vector3 bVec = vertices[2] - vertices[0]; if (bVec.LengthSquared() > float.Epsilon) { RTTriangle t = new RTTriangle(vertices, normals, uv, material); sceneDatabase.AddGeom(t); } } } } #endregion } } }
/// <summary> /// Initialization of light after the entire scene has been read in /// </summary> /// <param name="sceneDatabase"></param> public virtual void InitializeLight(SceneDatabase sceneDatabase) { }
/// <summary> /// How much of the spot light is visible from the visiblePt /// </summary> /// <param name="visiblePt"></param> /// <param name="exceptGeomIndex">this geometry can never block the light (geomIndex of the visiblePt)</param> /// <param name="database"></param> /// <returns></returns> public override float PercentVisible(Vector3 visiblePt, int exceptGeomIndex, SceneDatabase sceneDatabase) { float cosAlpha = 0f; bool canIllum = InLightCone(visiblePt, ref cosAlpha); float percent = 0f; if (canIllum) { if (mUseDepthMap) { percent = SampleDepthMap(visiblePt, exceptGeomIndex); } else percent = base.PercentVisible(visiblePt, exceptGeomIndex, sceneDatabase); } return percent; }
private const float kDepthImageDist = 1f; // depth map image plane distance from the light source private void InitDepthMap(SceneDatabase sceneDatabase) { if (null != mDepthMap) { return; // done } // remember!! mDireciton is L, or a vector from Visible point to the light. // Here we want direction from light source towards the scene Vector3 useDir = -mDirection; // 1. Find a Up direction // guess up direction to be (0, 1, 0), if view direction is also this, // use (1, 0, 0) as view direction Vector3 up = Vector3.UnitY; if (Math.Abs(Vector3.Dot(up, useDir)) > 0.99999) { up = Vector3.UnitX; } // 2. define Orthonormal base Vector3 sideV = Vector3.Cross(up, useDir); up = Vector3.Cross(useDir, sideV); sideV.Normalize(); up.Normalize(); // 3. compute the depth map image plane, // define the image plane to be located at ... a distance of kDepthImageDist away Vector3 ptOnImage = mPosition + kDepthImageDist * useDir; // 4. compute depth map image size float halfImageSize = kDepthImageDist * (float)Math.Tan(mOuterAngle / 2f); // 5. Compute the 4 vertices the defines the depth map Vector3[] v = new Vector3[4]; v[0] = ptOnImage - halfImageSize * up - halfImageSize * sideV; v[1] = ptOnImage - halfImageSize * up + halfImageSize * sideV; v[2] = ptOnImage + halfImageSize * up + halfImageSize * sideV; v[3] = ptOnImage + halfImageSize * up - halfImageSize * sideV; // 6. create a Geometry that represents the map // ** Be caureful **!! // RTRectangle uses v[0] as the origin for texture lookup // we _MUST_ follow the same in order to take advante of GetUV() function! mDepthMapGeom = new RTRectangle(v); // 7. Now allocate memory for the actual map mDepthMap = new float[mRes][]; mGeomID = new int[mRes][]; for (int i = 0; i < mRes; i++) { mDepthMap[i] = new float[mRes]; mGeomID[i] = new int[mRes]; } // now, trace rays through each of the pixels in the depth map and record the depth and geomID float pixelSize = halfImageSize / (0.5f * mRes); Vector3 upPixelVector = pixelSize * up; Vector3 sidePixelVector = pixelSize * sideV; for (int y = 0; y < mRes; y++) { Vector3 yDisp = v[0] + (y + 0.5f) * upPixelVector; for (int x = 0; x < mRes; x++) { Vector3 pixelPos = ((x + 0.5f) * sidePixelVector) + yDisp; Ray r = new Ray(mPosition, pixelPos); IntersectionRecord rec = new IntersectionRecord(); for (int i = 0; i < sceneDatabase.GetNumGeom(); i++) { RTGeometry g = sceneDatabase.GetGeom(i); g.Intersect(r, rec); } mDepthMap[x][y] = rec.HitDistance; // closes intersection distance, any object that is // further away from the light than this distance is in the shadow of this light mGeomID[x][y] = rec.GeomIndex; // this object can never be in shadow, becuase it is the closest to the light! } } }