/// <summary> /// Function to build the plane vertices. /// </summary> /// <param name="buffer">Buffer to populate.</param> /// <param name="size">The width and height of the plane.</param> /// <param name="textureCoordinates">The texture coordinates to apply to the plane.</param> /// <param name="columns">The number of columns to subdivide by.</param> /// <param name="rows">The number of rows to subdivide by.</param> private unsafe void GetVertices(Vertex3D *buffer, Vector2 size, RectangleF textureCoordinates, int columns, int rows) { float columnWidth = 1.0f / columns; float columnHeight = 1.0f / rows; var vertexNormal = -Vector3.UnitZ; Vector3.TransformNormal(ref vertexNormal, ref _orientation, out vertexNormal); for (int y = 0; y <= rows; ++y) { for (int x = 0; x <= columns; ++x) { var vertexPos = new Vector3(((x * columnWidth) - 0.5f) * size.X, ((y * columnHeight) - 0.5f) * size.Y, 0); Vector3.TransformCoordinate(ref vertexPos, ref _orientation, out vertexPos); *(buffer++) = new Vertex3D { Position = new Vector4(vertexPos, 1.0f), Normal = vertexNormal, UV = new Vector2((x * (textureCoordinates.Width / columns)) + textureCoordinates.X, (1.0f - (y * (textureCoordinates.Height / rows))) + textureCoordinates.Y) }; } } }
/// <summary> /// Function to build the plane vertices. /// </summary> /// <param name="buffer">Buffer to populate.</param> /// <param name="up">Up vector for orientation.</param> /// <param name="normal">The face normal.</param> /// <param name="size">The width and height of the plane.</param> /// <param name="textureCoordinates">The texture coordinates to apply to the plane.</param> /// <param name="columns">The number of columns to subdivide by.</param> /// <param name="rows">The number of rows to subdivide by.</param> private unsafe void GetVertices(Vertex3D *buffer, Vector3 up, Vector3 normal, Vector3 size, RectangleF textureCoordinates, int columns, int rows) { float columnWidth = 1.0f / columns; float columnHeight = 1.0f / rows; Matrix rotation = Matrix.Identity; Vector3 translate; Vector3 transformNormal; Vector3 orientVector; Vector3.Cross(ref normal, ref up, out orientVector); Vector3.Multiply(ref normal, 0.5f, out translate); rotation.Row1 = orientVector; rotation.Row2 = up; rotation.Row3 = normal; rotation.Row4 = new Vector4(translate, 1); Vector3.TransformCoordinate(ref normal, ref _orientation, out transformNormal); Vector3.Normalize(ref transformNormal, out transformNormal); for (int y = 0; y <= rows; ++y) { for (int x = 0; x <= columns; ++x) { var vertexPos = new Vector3(((x * columnWidth) - 0.5f) * size.X, ((y * columnHeight) - 0.5f) * size.Y, 0); Vector3.TransformCoordinate(ref vertexPos, ref rotation, out vertexPos); Vector3.TransformCoordinate(ref vertexPos, ref _orientation, out vertexPos); *(buffer++) = new Vertex3D { Position = new Vector4(vertexPos, 1.0f), Normal = transformNormal, UV = new Vector2((x * (textureCoordinates.Width / columns)) + textureCoordinates.X, (1.0f - (y * (textureCoordinates.Height / rows))) + textureCoordinates.Y) }; } } }
/// <summary> /// Function to create the vertex data for the sphere. /// </summary> /// <param name="vertexData">Pointer to the buffer that will hold the vertex data.</param> /// <param name="indexData">Pointer to the buffer that will hold the index data.</param> /// <param name="radius">Radius of the sphere.</param> /// <param name="textureCoordinates">Texture coordinates for the sphere.</param> /// <param name="ringCount">Number of rings in the sphere.</param> /// <param name="segmentCount">Number of segments in the sphere.</param> private unsafe void GetVertices(Vertex3D *vertexData, int *indexData, void *normalData, float radius, RectangleF textureCoordinates, int ringCount, int segmentCount) { int index = 0; // Current index. float deltaRingAngle = ((float)System.Math.PI) / ringCount; float deltaSegAngle = (((float)System.Math.PI) * 2.0f) / segmentCount; var linePtStart = (Vector4 *)normalData; Radius = radius; // Build our sphere. for (int ring = 0; ring <= ringCount; ring++) { float ringAngle = ring * deltaRingAngle; radius = ringAngle.Sin() * 0.5f * Radius; float radiusY = ringAngle.Cos() * Radius * 0.5f; for (int segment = 0; segment <= segmentCount; segment++) { var textureDelta = new Vector2(1.0f - segment / (float)segmentCount, ring / (float)ringCount); float segmentAngle = deltaSegAngle * segment; var position = new Vector3(radius * segmentAngle.Sin(), radiusY, radius * segmentAngle.Cos()); Vector3 normal; Vector3.Multiply(ref position, 2.0f, out normal); Vector3.TransformCoordinate(ref position, ref _orientation, out position); Vector3.TransformCoordinate(ref normal, ref _orientation, out normal); normal.Normalize(); *(linePtStart++) = new Vector4(position, 1.0f); *(linePtStart++) = new Vector4(position + (normal * 0.05f), 1.0f); // Create the vertex. textureDelta.X *= textureCoordinates.Width; textureDelta.Y *= textureCoordinates.Height; textureDelta.X += textureCoordinates.X; textureDelta.Y += textureCoordinates.Y; *(vertexData++) = new Vertex3D { Position = new Vector4(position, 1.0f), UV = textureDelta, Normal = normal }; // Add the indices and skip the last ring. if (ring == ringCount) { continue; } *(indexData++) = (index + segmentCount + 1); *(indexData++) = index; *(indexData++) = (index + segmentCount); *(indexData++) = (index + segmentCount + 1); *(indexData++) = (index + 1); *(indexData++) = index; index++; } } }
/// <summary> /// Function to calculate tangent information for bump mapping. /// </summary> /// <param name="vertexData">Buffer holding the vertices.</param> /// <param name="indexData">Buffer holding the indices.</param> protected unsafe void CalculateTangents(Vertex3D *vertexData, int *indexData) { var biTanData = new Vector3[VertexCount]; var tanData = new Vector3[VertexCount]; for (int i = 0; i < TriangleCount; ++i) { int index1 = *(indexData++); // If we hit a strip-restart index, then skip to the next index. if ((PrimitiveType == PrimitiveType.TriangleStrip) && (index1 < 0)) { index1 = *(indexData++); } int index2 = *(indexData++); int index3 = *(indexData++); Vertex3D vertex1 = vertexData[index1]; Vertex3D vertex2 = vertexData[index2]; Vertex3D vertex3 = vertexData[index3]; Vector4 deltaPos1; Vector4.Subtract(ref vertex2.Position, ref vertex1.Position, out deltaPos1); Vector4 deltaPos2; Vector4.Subtract(ref vertex3.Position, ref vertex1.Position, out deltaPos2); Vector2 deltaUV1; Vector2.Subtract(ref vertex2.UV, ref vertex1.UV, out deltaUV1); Vector2 deltaUV2; Vector2.Subtract(ref vertex3.UV, ref vertex1.UV, out deltaUV2); float denom = (deltaUV1.X * deltaUV2.Y - deltaUV1.Y * deltaUV2.X); float r = 0.0f; if (!denom.EqualsEpsilon(0)) { r = 1.0f / denom; } var tangent = new Vector3((deltaUV2.Y * deltaPos1.X - deltaUV1.Y * deltaPos2.X) * r, (deltaUV2.Y * deltaPos1.Y - deltaUV1.Y * deltaPos2.Y) * r, (deltaUV2.Y * deltaPos1.Z - deltaUV1.Y * deltaPos2.Z) * r); var biTangent = new Vector3((deltaUV1.X * deltaPos2.X - deltaUV2.X * deltaPos1.X) * r, (deltaUV1.X * deltaPos2.Y - deltaUV2.X * deltaPos1.Y) * r, (deltaUV1.X * deltaPos2.Z - deltaUV2.X * deltaPos1.Z) * r); Vector3.Add(ref tanData[index1], ref tangent, out tanData[index1]); Vector3.Add(ref tanData[index2], ref tangent, out tanData[index2]); Vector3.Add(ref tanData[index3], ref tangent, out tanData[index3]); Vector3.Add(ref biTanData[index1], ref biTangent, out biTanData[index1]); Vector3.Add(ref biTanData[index2], ref biTangent, out biTanData[index2]); Vector3.Add(ref biTanData[index3], ref biTangent, out biTanData[index3]); } for (int i = 0; i < VertexCount; ++i) { Vertex3D vertex = vertexData[i]; Vector3 tangent; Vector3 cross; float dot; Vector3.Dot(ref vertex.Normal, ref tanData[i], out dot); Vector3.Multiply(ref vertex.Normal, dot, out tangent); Vector3.Subtract(ref tanData[i], ref tangent, out tangent); Vector3.Normalize(ref tangent, out tangent); Vector3.Cross(ref vertex.Normal, ref tanData[i], out cross); Vector3.Dot(ref cross, ref biTanData[i], out dot); vertexData[i] = new Vertex3D { Position = vertex.Position, Normal = vertex.Normal, UV = vertex.UV, Tangent = new Vector4(tangent, dot < 0.0f ? -1.0f : 1.0f) }; } }