/// <summary> /// 绘制三角形 /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="p3"></param> /// <param name="mvp"></param> private void DrawTriangle(CVertex p1, CVertex p2, CVertex p3, CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p) { //--------------------几何阶段--------------------------- //变换到齐次裁剪空 SetMVPTransform(m, v, p, p1); SetMVPTransform(m, v, p, p2); SetMVPTransform(m, v, p, p3); ////裁剪 if (Clip(p1) == false || Clip(p2) == false || Clip(p3) == false) { return; } //背面消隐 //if (BackFaceCulling(p1, p2, p3) == false) //{ // return; //} //变换到屏幕坐标 TransformToScreen(p1); VectorMatrixTestCase.showVector3(p1.point); TransformToScreen(p2); VectorMatrixTestCase.showVector3(p2.point); TransformToScreen(p3); VectorMatrixTestCase.showVector3(p3.point); //--------------------光栅化阶段--------------------------- //todo test //_frameBuff.SetPixel((int)p1.point.x, (int)p1.point.y, System.Drawing.Color.White); //_frameBuff.SetPixel((int)p2.point.x, (int)p2.point.y, System.Drawing.Color.White); //_frameBuff.SetPixel((int)p3.point.x, (int)p3.point.y, System.Drawing.Color.White); TriangleRasterization(p1, p2, p3); }
private void Draw(CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p) { DrawPanel(0, 1, 2, 3, m, v, p); DrawPanel(4, 5, 6, 7, m, v, p); DrawPanel(0, 4, 5, 1, m, v, p); DrawPanel(1, 5, 6, 2, m, v, p); DrawPanel(2, 6, 7, 3, m, v, p); DrawPanel(3, 7, 4, 0, m, v, p); }
public static void showMat(CMatrix4x4 mat) { if (isEnable) { for (int i = 0; i < 4; i++) { Console.WriteLine("[{0},{1},{2},{3}]", mat[i, 0], mat[i, 1], mat[i, 2], mat[i, 3]); } } }
/// <summary> /// 绘制平面 /// </summary> /// <param name="vIndex1">顶点索引</param> /// <param name="vIndex2">顶点索引</param> /// <param name="vIndex3">顶点索引</param> /// <param name="vIndex4">顶点索引</param> /// <param name="mvp">mvp矩阵</param> private void DrawPanel(int vIndex1, int vIndex2, int vIndex3, int vIndex4, CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p) { CVertex p1 = new CVertex(mesh[vIndex1]); CVertex p2 = new CVertex(mesh[vIndex2]); CVertex p3 = new CVertex(mesh[vIndex3]); // DrawTriangle(p1, p2, p3, m, v, p); p1 = new CVertex(mesh[vIndex1]); p3 = new CVertex(mesh[vIndex3]); CVertex p4 = new CVertex(mesh[vIndex4]); DrawTriangle(p3, p4, p1, m, v, p); }
public static void Test() { CVector3D a = new CVector3D(1, 2, 1, 1); CVector3D b = new CVector3D(5, 6, 0, 1); CVector3D c = new CVector3D(1, 2, 3, 1); float r1 = CVector3D.Dot(a, b); CVector3D r2 = a - b; CVector3D r3 = CVector3D.Cross(a, b); Console.WriteLine("a dot b:{0}", r1); Console.WriteLine("a - b:({0},{1},{2},{3})", r2.x, r2.y, r2.z, r2.w); Console.WriteLine("a X b:({0},{1},{2},{3})", r3.x, r3.y, r3.z, r3.w); // CMatrix4x4 mat1 = new CMatrix4x4(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 0, 0, 0, 1); CMatrix4x4 mat2 = new CMatrix4x4(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4); CMatrix4x4 mat3 = new CMatrix4x4(); mat3.Identity(); CMatrix4x4 mat4 = new CMatrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1); CMatrix4x4 matr1 = mat1 * mat3; Console.WriteLine("mat1 * mat3:"); showMat(matr1); CMatrix4x4 matr2 = mat1 * mat2; Console.WriteLine("mat1 * mat2:"); showMat(matr2); CVector3D r4 = a * mat1; Console.WriteLine("a * mat1:({0},{1},{2},{3})", r4.x, r4.y, r4.z, r4.w); CVector3D r5 = a * mat4; Console.WriteLine("a * mat4:({0},{1},{2},{3})", r5.x, r5.y, r5.z, r5.w); }
/// <summary> /// 进行mvp矩阵变换,将顶点变换到齐次裁剪空间 /// </summary> private void SetMVPTransform(CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p, CVertex vertex) { vertex.point = vertex.point * m; VectorMatrixTestCase.showVector3(vertex.point); vertex.point = vertex.point * v; VectorMatrixTestCase.showVector3(vertex.point); vertex.point = vertex.point * p; VectorMatrixTestCase.showVector3(vertex.point); //得到齐次裁剪空间的点 v.point.w 中保存着原来的z(具体是z还是-z要看使用的投影矩阵,我们使用投影矩阵是让w中保存着z) //onePerZ 保存1/z,方便之后对1/z关于x’、y’插值得到1/z’ vertex.onePerZ = 1 / vertex.point.w; //校正的推论: s/z、t/z和x’、y’也是线性关系。而我们之前知道1/z和x’、y’是线性关系。则我们得出新的思路:对1/z关于x’、y’插值得到1/z’,然后对s/z、t/z关于x’、y’进行插值得到s’/z’、t’/z’,然后用s’/z’和t’/z’分别除以1/z’,就得到了插值s’和t’ //这里将需要插值的信息都乘以1/z 得到 s/z和t/z等,方便光栅化阶段进行插值 vertex.u *= vertex.onePerZ; vertex.v *= vertex.onePerZ; // vertex.color.r *= vertex.onePerZ; vertex.color.g *= vertex.onePerZ; vertex.color.b *= vertex.onePerZ; }
private void timer1_Tick(object sender, EventArgs e) { lock (_frameBuff) { ClearBuff(); CMatrix4x4 m = new CMatrix4x4(); m.Identity(); m[3, 2] = 5; rot += 0.1f; m = MathUntil.GetRotateY(rot) * m; CMatrix4x4 v = MathUntil.GetView(new CVector3D(0, 0, 0, 1), new CVector3D(0, 0, 1, 1), new CVector3D(0, 1, 0, 1)); CMatrix4x4 p = MathUntil.GetProjection((float)System.Math.PI / 4, this.MaximumSize.Width / (float)this.MaximumSize.Height, 1f, 500f); // Draw(m, v, p); // if (g1 == null) { g1 = this.CreateGraphics(); } g1.Clear(System.Drawing.Color.Black); g1.DrawImage(_frameBuff, 0, 0); } this.Invalidate(); }
/// <summary> /// Read mesh chunk and buffer infos. /// </summary> public void LoadData(CR2WFile meshFile) { // IMPLEMENTED FROM jlouis' witcherconverter // http://jlouisb.users.sourceforge.net/ // https://bitbucket.org/jlouis/witcherconverter SBufferInfos bufferInfos = new SBufferInfos(); // *************** READ CHUNK INFOS *************** foreach (var chunk in meshFile.Chunks) { if (chunk.REDType == "CMesh" && chunk.data is CMesh cmesh) { List <SVertexBufferInfos> vertexBufferInfos = new List <SVertexBufferInfos>(); SMeshCookedData meshCookedData = cmesh.CookedData; var bytes = meshCookedData.RenderChunks.Bytes; using (MemoryStream ms = new MemoryStream(bytes)) using (BinaryReader br = new BinaryReader(ms)) { var nbBuffers = br.ReadByte(); for (uint i = 0; i < nbBuffers; i++) { SVertexBufferInfos buffInfo = new SVertexBufferInfos(); br.BaseStream.Position += 1; // Unknown buffInfo.verticesCoordsOffset = br.ReadUInt32(); buffInfo.uvOffset = br.ReadUInt32(); buffInfo.normalsOffset = br.ReadUInt32(); br.BaseStream.Position += 9; // Unknown buffInfo.indicesOffset = br.ReadUInt32(); br.BaseStream.Position += 1; // 0x1D buffInfo.nbVertices = br.ReadUInt16(); buffInfo.nbIndices = br.ReadUInt32(); buffInfo.materialID = br.ReadByte(); br.BaseStream.Position += 2; // Unknown buffInfo.lod = br.ReadByte(); // lod ? vertexBufferInfos.Add(buffInfo); } } bufferInfos.indexBufferOffset = meshCookedData.IndexBufferOffset.val; bufferInfos.indexBufferSize = meshCookedData.IndexBufferSize.val; //bufferInfos.vertexBufferOffset = meshCookedData.vertexBufferOffset.val; //FIXME bufferInfos.vertexBufferSize = meshCookedData.VertexBufferSize.val; bufferInfos.quantizationOffset.X = meshCookedData.QuantizationOffset.X.val; bufferInfos.quantizationOffset.Y = meshCookedData.QuantizationOffset.Y.val; bufferInfos.quantizationOffset.Z = meshCookedData.QuantizationOffset.Z.val; bufferInfos.quantizationScale.X = meshCookedData.QuantizationScale.X.val; bufferInfos.quantizationScale.Y = meshCookedData.QuantizationScale.Y.val; bufferInfos.quantizationScale.Z = meshCookedData.QuantizationScale.Z.val; if (meshCookedData.BonePositions != null) { foreach (var item in meshCookedData.BonePositions) { Vector3Df pos = new Vector3Df(); pos.X = item.X.val; pos.Y = item.Y.val; pos.Z = item.Z.val; bonePositions.Add(pos); } } bufferInfos.verticesBuffer = vertexBufferInfos; CArray <SMeshChunkPacked> meshChunks = cmesh.Chunks; foreach (SMeshChunkPacked meshChunk in meshChunks.Elements) { SMeshInfos meshInfo = new SMeshInfos(); meshInfo.numVertices = meshChunk.NumVertices == null ? 0 : meshChunk.NumVertices.val; meshInfo.numIndices = meshChunk.NumIndices == null ? 0 : meshChunk.NumIndices.val; meshInfo.numBonesPerVertex = meshChunk.NumBonesPerVertex == null ? (uint)0 : meshChunk.NumBonesPerVertex.val; meshInfo.firstVertex = meshChunk.FirstVertex == null ? 0 : meshChunk.FirstVertex.val; meshInfo.firstIndex = meshChunk.FirstIndex == null ? 0 : meshChunk.FirstIndex.val; meshInfo.materialID = meshChunk.MaterialID == null ? 0 : meshChunk.MaterialID.val; if (meshChunk.VertexType != null) { if (meshChunk.VertexType.WrappedEnum == Enums.EMeshVertexType.MVT_StaticMesh) { meshInfo.vertexType = SMeshInfos.EMeshVertexType.EMVT_STATIC; } else if (meshChunk.VertexType.WrappedEnum == Enums.EMeshVertexType.MVT_SkinnedMesh) { meshInfo.vertexType = SMeshInfos.EMeshVertexType.EMVT_SKINNED; } } CData.meshInfos.Add(meshInfo); } // bone names and matrices CBufferVLQInt32 <CName> boneNames = cmesh.BoneNames; CBufferVLQInt32 <CMatrix4x4> bonematrices = cmesh.Bonematrices; CData.boneData.nbBones = (uint)boneNames.elements.Count; for (int i = 0; i < CData.boneData.nbBones; i++) { CName name = boneNames.elements[i]; CData.boneData.jointNames.Add(name.Value); CMatrix4x4 cmatrix = bonematrices.elements[i]; Matrix matrix = new Matrix(); for (int j = 0; j < 16; j++) { float value = (cmatrix.fields[j] as CFloat).val; matrix.SetElement(j, value); } CData.boneData.boneMatrices.Add(matrix); } } else if (chunk.REDType == "CMaterialInstance") { CData.materialInstances.Add(chunk.data as CMaterialInstance); } } // *************** READ MESH BUFFER INFOS *************** foreach (var meshInfo in CData.meshInfos) { SVertexBufferInfos vBufferInf = new SVertexBufferInfos(); uint nbVertices = 0; uint firstVertexOffset = 0; uint nbIndices = 0; uint firstIndiceOffset = 0; for (int i = 0; i < bufferInfos.verticesBuffer.Count; i++) { nbVertices += bufferInfos.verticesBuffer[i].nbVertices; if (nbVertices > meshInfo.firstVertex) { vBufferInf = bufferInfos.verticesBuffer[i]; // the index of the first vertex in the buffer firstVertexOffset = meshInfo.firstVertex - (nbVertices - vBufferInf.nbVertices); break; } } for (int i = 0; i < bufferInfos.verticesBuffer.Count; i++) { nbIndices += bufferInfos.verticesBuffer[i].nbIndices; if (nbIndices > meshInfo.firstIndex) { vBufferInf = bufferInfos.verticesBuffer[i]; firstIndiceOffset = meshInfo.firstIndex - (nbIndices - vBufferInf.nbIndices); break; } } // Load only best LOD if (vBufferInf.lod == 1) { using (BinaryReader br = new BinaryReader(File.Open(meshFile.FileName + ".1.buffer", FileMode.Open))) { uint vertexSize = 8; if (meshInfo.vertexType == SMeshInfos.EMeshVertexType.EMVT_SKINNED) { vertexSize += meshInfo.numBonesPerVertex * 2; } br.BaseStream.Seek(vBufferInf.verticesCoordsOffset + firstVertexOffset * vertexSize, SeekOrigin.Begin); List <Vertex3D> vertex3DCoords = new List <Vertex3D>(); Color defaultColor = new Color(255, 255, 255, 255); for (uint i = 0; i < meshInfo.numVertices; i++) { ushort x = br.ReadUInt16(); ushort y = br.ReadUInt16(); ushort z = br.ReadUInt16(); ushort w = br.ReadUInt16(); if (meshInfo.vertexType == SMeshInfos.EMeshVertexType.EMVT_SKINNED) { //sr.BaseStream.Seek(meshInfo.numBonesPerVertex * 2, SeekOrigin.Current); byte[] skinningData = new byte[meshInfo.numBonesPerVertex * 2]; br.BaseStream.Read(skinningData, 0, (int)meshInfo.numBonesPerVertex * 2); for (uint j = 0; j < meshInfo.numBonesPerVertex; ++j) { uint boneId = skinningData[j]; uint weight = skinningData[j + meshInfo.numBonesPerVertex]; float fweight = weight / 255.0f; if (weight != 0) { var vertexSkinningEntry = new W3_DataCache.VertexSkinningEntry(); vertexSkinningEntry.boneId = boneId; vertexSkinningEntry.meshBufferId = 0; vertexSkinningEntry.vertexId = i; vertexSkinningEntry.strength = fweight; CData.w3_DataCache.vertices.Add(vertexSkinningEntry); } } } Vertex3D vertex3DCoord = new Vertex3D(); vertex3DCoord.Position = new Vector3Df(x, y, z) / 65535f * bufferInfos.quantizationScale + bufferInfos.quantizationOffset; vertex3DCoord.Color = defaultColor; vertex3DCoords.Add(vertex3DCoord); } br.BaseStream.Seek(vBufferInf.uvOffset + firstVertexOffset * 4, SeekOrigin.Begin); for (int i = 0; i < meshInfo.numVertices; i++) { float uf = br.ReadHalfFloat(); float vf = br.ReadHalfFloat(); Vertex3D vertex3DCoord = vertex3DCoords[i]; vertex3DCoord.TCoords = new Vector2Df(uf, vf); vertex3DCoords[i] = vertex3DCoord; } // Indices ------------------------------------------------------------------- br.BaseStream.Seek(bufferInfos.indexBufferOffset + vBufferInf.indicesOffset + firstIndiceOffset * 2, SeekOrigin.Begin); List <ushort> indices = new List <ushort>(); for (int i = 0; i < meshInfo.numIndices; i++) { indices.Add(0); } for (int i = 0; i < meshInfo.numIndices; i++) { ushort index = br.ReadUInt16(); // Indice need to be inversed for the normals if (i % 3 == 0) { indices[i] = index; } else if (i % 3 == 1) { indices[i + 1] = index; } else if (i % 3 == 2) { indices[i - 1] = index; } } MeshBuffer meshBuff = MeshBuffer.Create(VertexType.Standard, IndexType._16Bit); meshBuff.Append(vertex3DCoords.ToArray(), indices.ToArray()); meshBuff.RecalculateBoundingBox(); CData.staticMesh.AddMeshBuffer(meshBuff); meshBuff.Drop(); } } } }
static void Main(string[] args) { CMatrix4x4 temp = new CMatrix4x4( new CVector4(10, 5, 3, 7), new CVector4(-2, 7, -10, 1), new CVector4(0, 3, 1, 6), new CVector4(2, -3, 0, -1)); CMatrix4x4 inv = temp.inverse(); CMatrix buff = new CMatrix(3, false); buff[0][0] = 8.0 / 9; buff[0][1] = 1.0 / 2; buff[0][2] = 1.0 / 3; buff[1][0] = 1.0 / 2; buff[1][1] = 1.0 / 3; buff[1][2] = 1.0 / 4; buff[2][0] = 1.0 / 3; buff[2][1] = 1.0 / 4; buff[2][2] = 1.0 / 5; CEigen res = CEigen.calculate(buff); System.Console.WriteLine("T"); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { System.Console.Write(res.vectors[i, j] + " "); } System.Console.WriteLine(); } System.Console.WriteLine("d"); for (int i = 0; i < 3; i++) { System.Console.WriteLine(res.values[i]); } CVector dx = new CVector(10); dx[0] = 3.369; dx[1] = 9.999; dx[2] = 12; dx[3] = 0.00458; dx[4] = 398; dx[5] = 0.0782; dx[6] = 1.596; dx[7] = 4.2118; dx[8] = 6.2258; dx[9] = 0.0795; CMatrix ret = dx.multiplyMatrix(dx); System.Console.WriteLine("dxdxT"); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { System.Console.Write(ret[i, j] + " "); } System.Console.WriteLine(); } System.Console.In.ReadToEnd(); }