void CMaterialViewer::Draw2D() { guard(CMaterialViewer::Draw2D); CObjectViewer::Draw2D(); if (IsTexture && ShowChannels) { UUnrealMaterial *Mat = static_cast<UUnrealMaterial*>(Object); Mat->SetMaterial(); int width, height; Window->GetWindowSize(width, height); int w = min(width, height) / 2; for (int i = 0; i < 4; i++) { int x0 = (i & 1) * w; int y0 = ((i >> 1) & 1) * w; static const CVec3 colors[4] = { { 1, 1, 1 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } // normal, red, green, blue }; glColor3fv(colors[i].v); glBegin(GL_QUADS); glTexCoord2f(1, 0); glVertex2f(x0+w, y0); glTexCoord2f(0, 0); glVertex2f(x0, y0); glTexCoord2f(0, 1); glVertex2f(x0, y0+w); glTexCoord2f(1, 1); glVertex2f(x0+w, y0+w); glEnd(); } }
void CStatMeshInstance::Draw(unsigned flags) { guard(CStatMeshInstance::Draw); int i; if (!pMesh->Lods.Num()) return; /*const*/ CStaticMeshLod& Mesh = pMesh->Lods[LodNum]; //?? not 'const' because of BuildTangents(); change this? int NumSections = Mesh.Sections.Num(); if (!NumSections || !Mesh.NumVerts) return; // if (!Mesh.HasNormals) Mesh.BuildNormals(); if (!Mesh.HasTangents) Mesh.BuildTangents(); // copy of CSkelMeshInstance::Draw sorting code #if SORT_BY_OPACITY // sort sections by material opacity int SectionMap[MAX_MESHMATERIALS]; int secPlace = 0; for (int opacity = 0; opacity < 2; opacity++) { for (i = 0; i < NumSections; i++) { UUnrealMaterial *Mat = Mesh.Sections[i].Material; int op = 0; // sort value if (Mat && Mat->IsTranslucent()) op = 1; if (op == opacity) SectionMap[secPlace++] = i; } } assert(secPlace == NumSections); #endif // SORT_BY_OPACITY // draw mesh glEnable(GL_LIGHTING); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Position); glNormalPointer(GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal); glTexCoordPointer(2, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].UV[UVIndex].U); /*?? Can move tangent/binormal setup here too, but this will require to force shader to use fixed attribute locations (use glBindAttribLocation before glLinkProgram instead of querying atttribute via glGetAtribLocation). In this case: - can remove GCurrentShader - can eliminate hasTangent checks below and always bind attributes (when supports GL2.0) - can share code between SkeletalMesh and StaticMesh: - sort sections - setup arrays; differences: - position and normals are taken from different arrays in static and skeletal meshes - ShowInfluences in SkeletalMeshInstance should disable material binding - draw sections using glDrawElements() - un-setup arrays - use VAO+VBO for rendering */ for (i = 0; i < NumSections; i++) { #if SORT_BY_OPACITY int MaterialIndex = SectionMap[i]; #else int MaterialIndex = i; #endif const CMeshSection &Sec = Mesh.Sections[MaterialIndex]; if (!Sec.NumFaces) continue; SetMaterial(Sec.Material, MaterialIndex); // check tangent space GLint aTangent = -1, aBinormal = -1; bool hasTangent = false; const CShader *Sh = GCurrentShader; if (Sh) { aTangent = Sh->GetAttrib("tangent"); aBinormal = Sh->GetAttrib("binormal"); hasTangent = (aTangent >= 0 && aBinormal >= 0); } if (hasTangent) { glEnableVertexAttribArray(aTangent); glEnableVertexAttribArray(aBinormal); glVertexAttribPointer(aTangent, 3, GL_FLOAT, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Tangent); glVertexAttribPointer(aBinormal, 3, GL_FLOAT, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Binormal); } // draw //?? place this code into CIndexBuffer? if (Mesh.Indices.Is32Bit()) glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_INT, &Mesh.Indices.Indices32[Sec.FirstIndex]); else glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_SHORT, &Mesh.Indices.Indices16[Sec.FirstIndex]); // disable tangents if (hasTangent) { glDisableVertexAttribArray(aTangent); glDisableVertexAttribArray(aBinormal); } } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_LIGHTING); BindDefaultMaterial(true); // draw mesh normals if (flags & DF_SHOW_NORMALS) { int NumVerts = Mesh.NumVerts; glBegin(GL_LINES); glColor3f(0.5, 1, 0); for (i = 0; i < NumVerts; i++) { glVertex3fv(Mesh.Verts[i].Position.v); CVec3 tmp; VectorMA(Mesh.Verts[i].Position, 2, Mesh.Verts[i].Normal, tmp); glVertex3fv(tmp.v); } #if SHOW_TANGENTS glColor3f(0, 0.5f, 1); for (i = 0; i < NumVerts; i++) { const CVec3 &v = Mesh.Verts[i].Position; glVertex3fv(v.v); CVec3 tmp; VectorMA(v, 2, Mesh.Verts[i].Tangent, tmp); glVertex3fv(tmp.v); } glColor3f(1, 0, 0.5f); for (i = 0; i < NumVerts; i++) { const CVec3 &v = Mesh.Verts[i].Position; glVertex3fv(v.v); CVec3 tmp; VectorMA(v, 2, Mesh.Verts[i].Binormal, tmp); glVertex3fv(tmp.v); } #endif // SHOW_TANGENTS glEnd(); } unguard; }
void CMaterialViewer::Draw3D(float TimeDelta) { if (IsTexture && ShowChannels) return; static const CVec3 origin = { -150, 100, 100 }; // static const CVec3 origin = { -150, 50, 50 }; CVec3 lightPosV; viewAxis.UnTransformVector(origin, lightPosV); #if 0 // show light source glDisable(GL_LIGHTING); BindDefaultMaterial(true); glBegin(GL_LINES); glColor3f(1, 0, 0); CVec3 tmp; tmp = lightPosV; tmp[0] -= 20; glVertex3fv(tmp.v); tmp[0] += 40; glVertex3fv(tmp.v); tmp = lightPosV; tmp[1] -= 20; glVertex3fv(tmp.v); tmp[1] += 40; glVertex3fv(tmp.v); tmp = lightPosV; tmp[2] -= 20; glVertex3fv(tmp.v); tmp[2] += 40; glVertex3fv(tmp.v); glEnd(); #endif glColor3f(1, 1, 1); if (!IsTexture) { glEnable(GL_LIGHTING); // no lighting for textures float lightPos[4]; lightPos[0] = lightPosV[0]; lightPos[1] = lightPosV[1]; lightPos[2] = lightPosV[2]; lightPos[3] = 0; glLightfv(GL_LIGHT0, GL_POSITION, lightPos); // glMaterialf(GL_FRONT, GL_SHININESS, 20); } // bind material UUnrealMaterial *Mat = static_cast<UUnrealMaterial*>(Object); Mat->SetMaterial(); // check tangent space GLint aNormal = -1; GLint aTangent = -1; // GLint aBinormal = -1; const CShader *Sh = GCurrentShader; if (Sh) { aNormal = Sh->GetAttrib("normal"); aTangent = Sh->GetAttrib("tangent"); // aBinormal = Sh->GetAttrib("binormal"); } // and draw box ... #define A 100 // vertex #define V000 {-A, -A, -A} #define V001 {-A, -A, A} #define V010 {-A, A, -A} #define V011 {-A, A, A} #define V100 { A, -A, -A} #define V101 { A, -A, A} #define V110 { A, A, -A} #define V111 { A, A, A} static const CVec3 box[] = { V001, V000, V010, V011, // near (x=-A) V111, V110, V100, V101, // far (x=+A) V101, V100, V000, V001, // left (y=-A) V011, V010, V110, V111, // right (y=+A) V010, V000, V100, V110, // bottom (z=-A) V001, V011, V111, V101, // top (z=+A) #undef A }; #define REP4(...) {__VA_ARGS__},{__VA_ARGS__},{__VA_ARGS__},{__VA_ARGS__} static const CVec4 normal[] = { REP4(-1, 0, 0, 1 ), REP4( 1, 0, 0, 1 ), REP4( 0,-1, 0, 1 ), REP4( 0, 1, 0, 1 ), REP4( 0, 0,-1, 1 ), REP4( 0, 0, 1, 1 ) }; static const CVec3 tangent[] = { REP4( 0,-1, 0 ), REP4( 0, 1, 0 ), REP4( 1, 0, 0 ), REP4(-1, 0, 0 ), REP4( 1, 0, 0 ), REP4(-1, 0, 0 ) }; // static const CVec3 binormal[] = // { // REP4( 0, 0, 1 ), // REP4( 0, 0, 1 ), // REP4( 0, 0, 1 ), // REP4( 0, 0, 1 ), // REP4( 0,-1, 0 ), // REP4( 0,-1, 0 ) // }; #undef REP4 static const float tex[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}, {0, 1}, {1, 1}, {1, 0} }; static const int inds[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23 }; #if 0 // verify tangents, should be suitable for binormal computation in shaders // (note: we're not verifying correspondence with UV coordinates) for (int i = 0; i < 24; i++) { CVec4 n4 = normal[i]; CVec3 n = n4.ToVec3(); CVec3 t = tangent[i]; CVec3 b = binormal[i]; CVec3 b2; cross(n, t, b2); VectorScale(b2, n4[3], b2); float dd = VectorDistance(b2, b); if (dd > 0.001f) appPrintf("dist[%d] = %g\n", i, dd); } #endif glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(CVec3), box); glNormalPointer(GL_FLOAT, sizeof(CVec4), normal); glTexCoordPointer(2, GL_FLOAT, 0, tex); if (aNormal >= 0) { glEnableVertexAttribArray(aNormal); // send 4 components to decode binormal in shader glVertexAttribPointer(aNormal, 4, GL_FLOAT, GL_FALSE, sizeof(CVec4), normal); } if (aTangent >= 0) { glEnableVertexAttribArray(aTangent); glVertexAttribPointer(aTangent, 3, GL_FLOAT, GL_FALSE, sizeof(CVec3), tangent); } // if (aBinormal >= 0) // { // glEnableVertexAttribArray(aBinormal); // glVertexAttribPointer(aBinormal, 3, GL_FLOAT, GL_FALSE, sizeof(CVec3), binormal); // } glDrawElements(GL_QUADS, ARRAY_COUNT(inds), GL_UNSIGNED_INT, inds); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); // disable tangents if (aNormal >= 0) glDisableVertexAttribArray(aNormal); if (aTangent >= 0) glDisableVertexAttribArray(aTangent); // if (aBinormal >= 0) // glDisableVertexAttribArray(aBinormal); BindDefaultMaterial(true); #if 0 glBegin(GL_LINES); glColor3f(0.2, 0.2, 1); for (int i = 0; i < ARRAY_COUNT(box); i++) { glVertex3fv(box[i].v); CVec3 tmp; VectorMA(box[i], 20, normal[i], tmp); glVertex3fv(tmp.v); } glEnd(); glColor3f(1, 1, 1); #endif }
void CStatMeshInstance::Draw(unsigned flags) { guard(CStatMeshInstance::Draw); int i; if (!pMesh->Lods.Num()) return; /*const*/ CStaticMeshLod& Mesh = pMesh->Lods[LodNum]; //?? not 'const' because of BuildTangents(); change this? int NumSections = Mesh.Sections.Num(); if (!NumSections || !Mesh.NumVerts) return; // if (!Mesh.HasNormals) Mesh.BuildNormals(); if (!Mesh.HasTangents) Mesh.BuildTangents(); // copy of CSkelMeshInstance::Draw sorting code #if SORT_BY_OPACITY // sort sections by material opacity int SectionMap[MAX_MESHMATERIALS]; int secPlace = 0; for (int opacity = 0; opacity < 2; opacity++) { for (i = 0; i < NumSections; i++) { UUnrealMaterial *Mat = Mesh.Sections[i].Material; int op = 0; // sort value if (Mat && Mat->IsTranslucent()) op = 1; if (op == opacity) SectionMap[secPlace++] = i; } } assert(secPlace == NumSections); #endif // SORT_BY_OPACITY // draw mesh glEnable(GL_LIGHTING); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Position); glNormalPointer(GL_BYTE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal); if (UVIndex == 0) { glTexCoordPointer(2, GL_FLOAT, sizeof(CStaticMeshVertex), &Mesh.Verts[0].UV.U); } else { glTexCoordPointer(2, GL_FLOAT, sizeof(CMeshUVFloat), &Mesh.ExtraUV[UVIndex-1][0].U); } /*?? Can move tangent/binormal setup here too, but this will require to force shader to use fixed attribute locations (use glBindAttribLocation before glLinkProgram instead of querying atttribute via glGetAtribLocation). In this case: - can remove GCurrentShader - can eliminate hasTangent checks below and always bind attributes (when supports GL2.0) - can share code between SkeletalMesh and StaticMesh: - sort sections - setup arrays; differences: - position and normals are taken from different arrays in static and skeletal meshes - ShowInfluences in SkeletalMeshInstance should disable material binding - draw sections using glDrawElements() - un-setup arrays - use VAO+VBO for rendering */ for (i = 0; i < NumSections; i++) { #if SORT_BY_OPACITY int MaterialIndex = SectionMap[i]; #else int MaterialIndex = i; #endif const CMeshSection &Sec = Mesh.Sections[MaterialIndex]; if (!Sec.NumFaces) continue; SetMaterial(Sec.Material, MaterialIndex); // check tangent space GLint aNormal = -1; GLint aTangent = -1; // GLint aBinormal = -1; const CShader *Sh = GCurrentShader; if (Sh) { aNormal = Sh->GetAttrib("normal"); aTangent = Sh->GetAttrib("tangent"); // aBinormal = Sh->GetAttrib("binormal"); } if (aNormal >= 0) { glEnableVertexAttribArray(aNormal); // send 4 components to decode binormal in shader glVertexAttribPointer(aNormal, 4, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Normal); } if (aTangent >= 0) { glEnableVertexAttribArray(aTangent); glVertexAttribPointer(aTangent, 3, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Tangent); } /* if (aBinormal >= 0) { glEnableVertexAttribArray(aBinormal); glVertexAttribPointer(aBinormal, 3, GL_BYTE, GL_FALSE, sizeof(CStaticMeshVertex), &Mesh.Verts[0].Binormal); } */ // draw //?? place this code into CIndexBuffer? if (Mesh.Indices.Is32Bit()) glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_INT, &Mesh.Indices.Indices32[Sec.FirstIndex]); else glDrawElements(GL_TRIANGLES, Sec.NumFaces * 3, GL_UNSIGNED_SHORT, &Mesh.Indices.Indices16[Sec.FirstIndex]); // disable tangents if (aNormal >= 0) glDisableVertexAttribArray(aNormal); if (aTangent >= 0) glDisableVertexAttribArray(aTangent); // if (aBinormal >= 0) // glDisableVertexAttribArray(aBinormal); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_LIGHTING); BindDefaultMaterial(true); // draw mesh normals if (flags & DF_SHOW_NORMALS) { //!! TODO: performance issues when displaying a large mesh (1M+ triangles) with normals/tangents. //!! Possible solution: //!! 1. use vertex buffer for normals, use single draw call //!! 2. cache normal data between render frames //!! 3. DecodeTangents() will do Unpack() for normal and tangent too, so this work is duplicated here int NumVerts = Mesh.NumVerts; glBegin(GL_LINES); glColor3f(0.5, 1, 0); CVecT tmp, unpacked; const float VisualLength = 2.0f; for (i = 0; i < NumVerts; i++) { glVertex3fv(Mesh.Verts[i].Position.v); Unpack(unpacked, Mesh.Verts[i].Normal); VectorMA(Mesh.Verts[i].Position, VisualLength, unpacked, tmp); glVertex3fv(tmp.v); } #if SHOW_TANGENTS glColor3f(0, 0.5f, 1); for (i = 0; i < NumVerts; i++) { const CVec3 &v = Mesh.Verts[i].Position; glVertex3fv(v.v); Unpack(unpacked, Mesh.Verts[i].Tangent); VectorMA(v, VisualLength, unpacked, tmp); glVertex3fv(tmp.v); } glColor3f(1, 0, 0.5f); for (i = 0; i < NumVerts; i++) { const CMeshVertex& vert = Mesh.Verts[i]; // decode binormal CVecT normal, tangent, binormal; vert.DecodeTangents(normal, tangent, binormal); // render const CVecT &v = vert.Position; glVertex3fv(v.v); VectorMA(v, VisualLength, binormal, tmp); glVertex3fv(tmp.v); } #endif // SHOW_TANGENTS glEnd(); } unguard; }