void Model::loadObj(QFile &file) { // 1e9 = 1*10^9 = 1,000,000,000 QVector3D boundsMin( 1e9, 1e9, 1e9); QVector3D boundsMax(-1e9,-1e9,-1e9); QTextStream in(&file); while (!in.atEnd()) { QString input = in.readLine(); // # means comment if (input.isEmpty() || input[0] == '#') continue; QTextStream ts(&input); QString id; ts >> id; //--------------- v = List of vertices with (x,y,z[,w]) corrdinates. ----------------- if (id == "v") { QVector3D p; for (int i = 0; i < 3; ++i) { ts >> p[i]; boundsMin[i] = qMin(boundsMin[i], p[i]); boundsMax[i] = qMax(boundsMax[i], p[i]); } m_vertices << p; //--------------- f = Face definitions ----------------- } else if (id == "f" || id == "fo") {
Model::Model(const QString &filePath) : m_fileName(QFileInfo(filePath).fileName()) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return; QVector3D boundsMin( 1e9, 1e9, 1e9); QVector3D boundsMax(-1e9,-1e9,-1e9); QTextStream in(&file); while (!in.atEnd()) { QString input = in.readLine(); if (input.isEmpty() || input[0] == '#') continue; QTextStream ts(&input); QString id; ts >> id; if (id == "v") { QVector3D p; for (int i = 0; i < 3; ++i) { ts >> ((float *)&p)[i]; ((float *)&boundsMin)[i] = qMin(((float *)&boundsMin)[i], ((float *)&p)[i]); ((float *)&boundsMax)[i] = qMax(((float *)&boundsMax)[i], ((float *)&p)[i]); } m_points << p; } else if (id == "f" || id == "fo") {
/* ================ R_SurfaceToTextureAxis Calculates two axis for the surface such that a point dotted against the axis will give a 0.0 to 1.0 range in S and T when inside the gui surface ================ */ void R_SurfaceToTextureAxis( const srfTriangles_t* tri, idVec3& origin, idVec3 axis[3] ) { // find the bounds of the texture idVec2 boundsMin( 999999.0f, 999999.0f ); idVec2 boundsMax( -999999.0f, -999999.0f ); for( int i = 0 ; i < tri->numVerts ; i++ ) { const idVec2 uv = tri->verts[i].GetTexCoord(); boundsMin.x = Min( uv.x, boundsMin.x ); boundsMax.x = Max( uv.x, boundsMax.x ); boundsMin.y = Min( uv.y, boundsMin.y ); boundsMax.y = Max( uv.y, boundsMax.y ); } // use the floor of the midpoint as the origin of the // surface, which will prevent a slight misalignment // from throwing it an entire cycle off const idVec2 boundsOrg( floor( ( boundsMin.x + boundsMax.x ) * 0.5f ), floor( ( boundsMin.y + boundsMax.y ) * 0.5f ) ); // determine the world S and T vectors from the first drawSurf triangle // RB: added check wether GPU skinning is available at all const idJointMat* joints = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() && glConfig.gpuSkinningAvailable ) ? tri->staticModelWithJoints->jointsInverted : NULL; // RB end const idVec3 aXYZ = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[0] ], joints ); const idVec3 bXYZ = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[1] ], joints ); const idVec3 cXYZ = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[ tri->indexes[2] ], joints ); const idVec2 aST = tri->verts[ tri->indexes[0] ].GetTexCoord(); const idVec2 bST = tri->verts[ tri->indexes[1] ].GetTexCoord(); const idVec2 cST = tri->verts[ tri->indexes[2] ].GetTexCoord(); float d0[5]; d0[0] = bXYZ[0] - aXYZ[0]; d0[1] = bXYZ[1] - aXYZ[1]; d0[2] = bXYZ[2] - aXYZ[2]; d0[3] = bST.x - aST.x; d0[4] = bST.y - aST.y; float d1[5]; d1[0] = cXYZ[0] - aXYZ[0]; d1[1] = cXYZ[1] - aXYZ[1]; d1[2] = cXYZ[2] - aXYZ[2]; d1[3] = cST.x - aST.x; d1[4] = cST.y - aST.y; const float area = d0[3] * d1[4] - d0[4] * d1[3]; if( area == 0.0f ) { axis[0].Zero(); axis[1].Zero(); axis[2].Zero(); return; // degenerate } const float inva = 1.0f / area; axis[0][0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva; axis[0][1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva; axis[0][2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva; axis[1][0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva; axis[1][1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva; axis[1][2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva; idPlane plane; plane.FromPoints( aXYZ, bXYZ, cXYZ ); axis[2][0] = plane[0]; axis[2][1] = plane[1]; axis[2][2] = plane[2]; // take point 0 and project the vectors to the texture origin VectorMA( aXYZ, boundsOrg.x - aST.x, axis[0], origin ); VectorMA( origin, boundsOrg.y - aST.y, axis[1], origin ); }
void LightList::QueueDraw(Renderer& rRenderer, const Sky& rSky, const Camera& rCamera, const float sceneDepthMin, const float sceneDepthMax, RdrLightingMethod lightingMethod, RdrLightResources* pOutResources) { Camera lightCamera; int curShadowMapIndex = 0; int curShadowCubeMapIndex = 0; int shadowMapsThisFrame = 0; // Update shadow casting lights and the global light constants // todo: Choose shadow lights based on location and dynamic object movement GlobalLightData* pGlobalLights = (GlobalLightData*)RdrFrameMem::AllocAligned(sizeof(GlobalLightData), 16); // Temporarily add sky light to the light list. m_directionalLights.push(rSky.GetSunLight()); for (uint i = 0, count = m_directionalLights.size(); i < count; ++i) { DirectionalLight& rDirLight = m_directionalLights[i]; int remainingShadowMaps = MAX_SHADOW_MAPS - curShadowMapIndex - 1; const int kNumCascades = 4; if (remainingShadowMaps >= kNumCascades) { // Directional lights always change because they're based on camera position/rotation rDirLight.shadowMapIndex = curShadowMapIndex; Rect viewport(0.f, 0.f, (float)s_shadowMapSize, (float)s_shadowMapSize); float zMin = sceneDepthMin; float zMax = sceneDepthMax; float zDiff = (zMax - zMin); float nearDepth = zMin; float lamda = rSky.GetPssmLambda(); for (int iPartition = 0; iPartition < kNumCascades; ++iPartition) { float zUni = zMin + (zDiff / kNumCascades) * (iPartition + 1); float zLog = zMin * powf(zMax / zMin, (iPartition + 1) / (float)kNumCascades); float farDepth = lamda * zLog + (1.f - lamda) * zUni; Vec3 center = rCamera.GetPosition() + rCamera.GetDirection() * ((farDepth + nearDepth) * 0.5f); Matrix44 lightViewMtx = getLightViewMatrix(center, rDirLight.direction); Quad nearQuad = rCamera.GetFrustumQuad(nearDepth); QuadTransform(nearQuad, lightViewMtx); Quad farQuad = rCamera.GetFrustumQuad(farDepth); QuadTransform(farQuad, lightViewMtx); Vec3 boundsMin(FLT_MAX, FLT_MAX, FLT_MAX); Vec3 boundsMax(-FLT_MAX, -FLT_MAX, -FLT_MAX); accumQuadMinMax(nearQuad, boundsMin, boundsMax); accumQuadMinMax(farQuad, boundsMin, boundsMax); float height = (boundsMax.y - boundsMin.y); float width = (boundsMax.x - boundsMin.x); lightCamera.SetAsOrtho(center, rDirLight.direction, std::max(width, height), -500.f, 500.f); rRenderer.QueueShadowMapPass(lightCamera, m_shadowMapDepthViews[curShadowMapIndex], viewport); Matrix44 mtxView; Matrix44 mtxProj; lightCamera.GetMatrices(mtxView, mtxProj); pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Multiply(mtxView, mtxProj); pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Transpose(pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj); pGlobalLights->shadowData[curShadowMapIndex].partitionEndZ = (iPartition == kNumCascades - 1) ? FLT_MAX : farDepth; ++shadowMapsThisFrame; ++curShadowMapIndex; nearDepth = farDepth; } } else { rDirLight.shadowMapIndex = -1; } } for (uint i = 0, count = m_spotLights.size(); i < count; ++i) { SpotLight& rSpotLight = m_spotLights[i]; int remainingShadowMaps = MAX_SHADOW_MAPS - curShadowMapIndex - 1; if (remainingShadowMaps) { Matrix44 mtxView; Matrix44 mtxProj; float angle = rSpotLight.outerConeAngle + Maths::DegToRad(5.f); lightCamera.SetAsPerspective(rSpotLight.position, rSpotLight.direction, angle * 2.f, 1.f, 0.1f, 1000.f); lightCamera.GetMatrices(mtxView, mtxProj); pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Multiply(mtxView, mtxProj); pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj = Matrix44Transpose(pGlobalLights->shadowData[curShadowMapIndex].mtxViewProj); Rect viewport(0.f, 0.f, (float)s_shadowMapSize, (float)s_shadowMapSize); rRenderer.QueueShadowMapPass(lightCamera, m_shadowMapDepthViews[curShadowMapIndex], viewport); rSpotLight.shadowMapIndex = curShadowMapIndex; ++shadowMapsThisFrame; ++curShadowMapIndex; } else { rSpotLight.shadowMapIndex = -1; } } for (uint i = 0, count = m_pointLights.size(); i < count; ++i) { PointLight& rPointLight = m_pointLights[i]; int remainingShadowCubeMaps = MAX_SHADOW_CUBEMAPS - curShadowCubeMapIndex - 1; if (remainingShadowCubeMaps) { rPointLight.shadowMapIndex = curShadowCubeMapIndex + MAX_SHADOW_MAPS; Rect viewport(0.f, 0.f, (float)s_shadowCubeMapSize, (float)s_shadowCubeMapSize); #if USE_SINGLEPASS_SHADOW_CUBEMAP rRenderer.QueueShadowCubeMapPass(rPointLight, m_shadowCubeMapDepthViews[curShadowCubeMapIndex], viewport); #else for (uint face = 0; face < 6; ++face) { lightCamera.SetAsCubemapFace(light.position, (CubemapFace)face, 0.1f, light.radius * 2.f); rRenderer.QueueShadowMapPass(lightCamera, m_shadowCubeMapDepthViews[curShadowCubeMapIndex * 6 + face], viewport); } #endif ++shadowMapsThisFrame; ++curShadowCubeMapIndex; } else { rPointLight.shadowMapIndex = -1; } } ////////////////////////////////////////////////////////////////////////// // Apply resource updates RdrResourceCommandList* pResCommandList = rRenderer.GetActionCommandList(); // Update spot lights SpotLight* pSpotLights = (SpotLight*)RdrFrameMem::Alloc(sizeof(SpotLight) * m_spotLights.size()); memcpy(pSpotLights, m_spotLights.getData(), sizeof(SpotLight) * m_spotLights.size()); if (!m_hSpotLightListRes) m_hSpotLightListRes = pResCommandList->CreateStructuredBuffer(pSpotLights, m_spotLights.capacity(), sizeof(SpotLight), RdrResourceUsage::Dynamic); else pResCommandList->UpdateBuffer(m_hSpotLightListRes, pSpotLights, sizeof(SpotLight) * m_spotLights.size()); // Update point lights PointLight* pPointLights = (PointLight*)RdrFrameMem::Alloc(sizeof(PointLight) * m_pointLights.size()); memcpy(pPointLights, m_pointLights.getData(), sizeof(PointLight) * m_pointLights.size()); if (!m_hPointLightListRes) m_hPointLightListRes = pResCommandList->CreateStructuredBuffer(pPointLights, m_pointLights.capacity(), sizeof(PointLight), RdrResourceUsage::Dynamic); else pResCommandList->UpdateBuffer(m_hPointLightListRes, pPointLights, sizeof(PointLight) * m_pointLights.size()); // Update environment lights EnvironmentLight* pEnvironmentLights = (EnvironmentLight*)RdrFrameMem::Alloc(sizeof(EnvironmentLight) * m_environmentLights.size()); memcpy(pEnvironmentLights, m_environmentLights.getData(), sizeof(EnvironmentLight) * m_environmentLights.size()); if (!m_hEnvironmentLightListRes) m_hEnvironmentLightListRes = pResCommandList->CreateStructuredBuffer(pEnvironmentLights, m_environmentLights.capacity(), sizeof(EnvironmentLight), RdrResourceUsage::Dynamic); else pResCommandList->UpdateBuffer(m_hEnvironmentLightListRes, pEnvironmentLights, sizeof(EnvironmentLight) * m_environmentLights.size()); // Light culling if (lightingMethod == RdrLightingMethod::Clustered) { QueueClusteredLightCulling(rRenderer, rCamera); } else { QueueTiledLightCulling(rRenderer, rCamera); } // Update global lights constant buffer last so the light culling data is up to date. pGlobalLights->numDirectionalLights = m_directionalLights.size(); pGlobalLights->globalEnvironmentLight = m_globalEnvironmentLight; pGlobalLights->clusterTileSize = m_clusteredLightData.clusterTileSize; memcpy(pGlobalLights->directionalLights, m_directionalLights.getData(), sizeof(DirectionalLight) * pGlobalLights->numDirectionalLights); m_hGlobalLightsCb = pResCommandList->CreateUpdateConstantBuffer(m_hGlobalLightsCb, pGlobalLights, sizeof(GlobalLightData), RdrCpuAccessFlags::Write, RdrResourceUsage::Dynamic); // Remove sky light. m_directionalLights.pop(); // Fill out resource params pOutResources->hGlobalLightsCb = m_hGlobalLightsCb; pOutResources->hSpotLightListRes = m_hSpotLightListRes; pOutResources->hPointLightListRes = m_hPointLightListRes; pOutResources->hEnvironmentLightListRes = m_hEnvironmentLightListRes; pOutResources->hShadowCubeMapTexArray = m_hShadowCubeMapTexArray; pOutResources->hShadowMapTexArray = m_hShadowMapTexArray; pOutResources->hEnvironmentMapTexArray = m_hEnvironmentMapTexArray; pOutResources->hLightIndicesRes = (lightingMethod == RdrLightingMethod::Clustered) ? m_clusteredLightData.hLightIndices : m_tiledLightData.hLightIndices; }
void Model::loadFile(QString filePath) { QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return; //如下两个变量存放模型的边界 Point3d boundsMin( 1e9, 1e9, 1e9); Point3d boundsMax(-1e9,-1e9,-1e9); //读取obj格式的文件 QTextStream in(&file); //now begin to read the verters Point3d pi; float currentZ = 0.0; float currentX = 0.0; float currentY = 0.0; QRegExp regZ("[\w\d\s]*Z([0-9\.]*[0-9]*)"); QRegExp regL(";LAYER: *([0-9]*)"); QRegExp regXY("G1 [\w\d\s]* *X([0-9\.]*[0-9]*) *Y([0-9\.]*[0-9]*)"); bool isZ = false; bool isIn = false; while(!in.atEnd()) { QString current_str = in.readLine(); if(current_str.contains(regXY)) { currentX = regXY.cap(1).toFloat(); currentY = regXY.cap(2).toFloat(); boundsMin.x = qMin(boundsMin.x,currentX); boundsMax.x = qMax(boundsMax.x, currentX); boundsMin.y = qMin(boundsMin.y,currentY); boundsMax.y = qMax(boundsMax.y, currentY); boundsMin.z = qMin(boundsMin.z,currentZ); boundsMax.z = qMax(boundsMax.z, currentZ); qDebug()<< QObject::tr("Xs=%1").arg(currentX); pi = Point3d(currentX,currentY,currentZ); m_points.push_back(pi); } if(current_str.contains(regL)) { if((regL.cap(1))=="0") isIn = false; else isIn = true; isZ = true; } if(current_str.contains(regZ)&&(isZ)) { isZ = false; QString str_Z = regZ.cap(1); currentZ = str_Z.toFloat(); } } const Point3d bounds = boundsMax - boundsMin; const qreal scale = 100 / qMax(bounds.x, qMax(bounds.y, bounds.z)); for(int j=0;j<m_points.size();j++) { m_points[j] = (m_points[j] - (boundsMin + bounds * 0.5)) * scale; qDebug()<< QObject::tr("X=%1").arg(m_points[j].x); } }