8、基于osg引擎实现读取vtk数据通过着色器实现简单体渲染(2)


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

const std::string DATA_PATH = R"(..\data\)";//vtk数据存储路径
const std::string SHADER_PATH = R"(..\shaders\)";//着色器存储路径
int sizeX = 128, sizeY = 128, sizeZ = 128;

struct VTKData {
	std::vector<osg::Vec3> points;           // 节点坐标数组,每个元素包含(x,y,z)坐标
	std::vector<std::vector<unsigned int>> cells;  // 单元连接关系数组,每个子数组存储一个单元的节点索引
	std::vector<int> cell_types;             // 单元类型数组,存储每个单元的VTK类型编号
	std::vector<std::array<float, 6>> stresses;    // 应力张量数组,每个元素包含6个分量(σxx,σyy,σzz,τxy,τyz,τxz)
	std::vector<std::array<float, 6>> strains;     // 应变张量数组,每个元素包含6个分量(εxx,εyy,εzz,γxy,γyz,γxz)
	std::vector<osg::Vec3> displacements;    // 位移向量数组,每个元素包含(dx,dy,dz)分量
	std::vector<float> pore_pressures;       // 孔隙压力数组
	std::vector<float> PEEQs;                // 等效塑性应变数组
	std::vector<float> mises_stresses;       // Mises等效应力数组
	std::vector<osg::Vec3> fluid_velocities; // 流体速度向量数组,每个元素包含(vx,vy,vz)分量

	int type = 0;//8代表六面体 4代表四边形 0是无效值

	void computeMinMax()
	{
		// 计算应力最值
		for (const auto& stress : this->stresses) {
			this->minStressesXX = osg::minimum(this->minStressesXX, stress[0]);
			this->maxStressesXX = osg::maximum(this->maxStressesXX, stress[0]);
			this->minStressesYY = osg::minimum(this->minStressesYY, stress[1]);
			this->maxStressesYY = osg::maximum(this->maxStressesYY, stress[1]);
			this->minStressesZZ = osg::minimum(this->minStressesZZ, stress[2]);
			this->maxStressesZZ = osg::maximum(this->maxStressesZZ, stress[2]);
			this->minStressesXY = osg::minimum(this->minStressesXY, stress[3]);
			this->maxStressesXY = osg::maximum(this->maxStressesXY, stress[3]);
			this->minStressesYZ = osg::minimum(this->minStressesYZ, stress[4]);
			this->maxStressesYZ = osg::maximum(this->maxStressesYZ, stress[4]);
			this->minStressesXZ = osg::minimum(this->minStressesXZ, stress[5]);
			this->maxStressesXZ = osg::maximum(this->maxStressesXZ, stress[5]);
		}

		// 计算应变最值
		for (const auto& strain : this->strains) {
			this->minStrainsXX = osg::minimum(this->minStrainsXX, strain[0]);
			this->maxStrainsXX = osg::maximum(this->maxStrainsXX, strain[0]);
			this->minStrainsYY = osg::minimum(this->minStrainsYY, strain[1]);
			this->maxStrainsYY = osg::maximum(this->maxStrainsYY, strain[1]);
			this->minStrainsZZ = osg::minimum(this->minStrainsZZ, strain[2]);
			this->maxStrainsZZ = osg::maximum(this->maxStrainsZZ, strain[2]);
			this->minStrainsXY = osg::minimum(this->minStrainsXY, strain[3]);
			this->maxStrainsXY = osg::maximum(this->maxStrainsXY, strain[3]);
			this->minStrainsYZ = osg::minimum(this->minStrainsYZ, strain[4]);
			this->maxStrainsYZ = osg::maximum(this->maxStrainsYZ, strain[4]);
			this->minStrainsXZ = osg::minimum(this->minStrainsXZ, strain[5]);
			this->maxStrainsXZ = osg::maximum(this->maxStrainsXZ, strain[5]);
		}

		// 计算位移最值
		for (const auto& disp : this->displacements) {
			this->minDisplacementsDX = osg::minimum(this->minDisplacementsDX, disp.x());
			this->maxDisplacementsDX = osg::maximum(this->maxDisplacementsDX, disp.x());
			this->minDisplacementsDY = osg::minimum(this->minDisplacementsDY, disp.y());
			this->maxDisplacementsDY = osg::maximum(this->maxDisplacementsDY, disp.y());
			this->minDisplacementsDZ = osg::minimum(this->minDisplacementsDZ, disp.z());
			this->maxDisplacementsDZ = osg::maximum(this->maxDisplacementsDZ, disp.z());
		}

		// 计算孔隙压力、等效塑性应变、Mises等效应力最值
		for (float p : this->pore_pressures) {
			this->minPorePressures = osg::minimum(this->minPorePressures, p);
			this->maxPorePressures = osg::maximum(this->maxPorePressures, p);
		}
		for (float peeq : this->PEEQs) {
			this->minPEEQs = osg::minimum(this->minPEEQs, peeq);
			this->maxPEEQs = osg::maximum(this->maxPEEQs, peeq);
		}
		for (float mises : this->mises_stresses) {
			this->minMisesStresses = osg::minimum(this->minMisesStresses, mises);
			this->maxMisesStresses = osg::maximum(this->maxMisesStresses, mises);
		}

		// 计算流体速度最值
		for (const auto& vel : this->fluid_velocities) {
			this->minFluidVelocitiesVX = osg::minimum(this->minFluidVelocitiesVX, vel.x());
			this->maxFluidVelocitiesVX = osg::maximum(this->maxFluidVelocitiesVX, vel.x());
			this->minFluidVelocitiesVY = osg::minimum(this->minFluidVelocitiesVY, vel.y());
			this->maxFluidVelocitiesVY = osg::maximum(this->maxFluidVelocitiesVY, vel.y());
			this->minFluidVelocitiesVZ = osg::minimum(this->minFluidVelocitiesVZ, vel.z());
			this->maxFluidVelocitiesVZ = osg::maximum(this->maxFluidVelocitiesVZ, vel.z());
		}

		minVal = minStressesXY;
		maxVal = maxStressesXY;

	}
	float minVal, maxVal;
	float minStressesXX = FLT_MAX, maxStressesXX = -FLT_MAX;
	float minStressesYY = FLT_MAX, maxStressesYY = -FLT_MAX;
	float minStressesZZ = FLT_MAX, maxStressesZZ = -FLT_MAX;
	float minStressesXY = FLT_MAX, maxStressesXY = -FLT_MAX;
	float minStressesYZ = FLT_MAX, maxStressesYZ = -FLT_MAX;
	float minStressesXZ = FLT_MAX, maxStressesXZ = -FLT_MAX;

	float minStrainsXX = FLT_MAX, maxStrainsXX = -FLT_MAX;
	float minStrainsYY = FLT_MAX, maxStrainsYY = -FLT_MAX;
	float minStrainsZZ = FLT_MAX, maxStrainsZZ = -FLT_MAX;
	float minStrainsXY = FLT_MAX, maxStrainsXY = -FLT_MAX;
	float minStrainsYZ = FLT_MAX, maxStrainsYZ = -FLT_MAX;
	float minStrainsXZ = FLT_MAX, maxStrainsXZ = -FLT_MAX;

	float minDisplacementsDX = FLT_MAX, maxDisplacementsDX = -FLT_MAX;
	float minDisplacementsDY = FLT_MAX, maxDisplacementsDY = -FLT_MAX;
	float minDisplacementsDZ = FLT_MAX, maxDisplacementsDZ = -FLT_MAX;

	float minPorePressures = FLT_MAX, maxPorePressures = -FLT_MAX;
	float minPEEQs = FLT_MAX, maxPEEQs = -FLT_MAX;
	float minMisesStresses = FLT_MAX, maxMisesStresses = -FLT_MAX;

	float minFluidVelocitiesVX = FLT_MAX, maxFluidVelocitiesVX = -FLT_MAX;
	float minFluidVelocitiesVY = FLT_MAX, maxFluidVelocitiesVY = -FLT_MAX;
	float minFluidVelocitiesVZ = FLT_MAX, maxFluidVelocitiesVZ = -FLT_MAX;
};

VTKData ParseVtkFile(const std::string& filename)
{

	VTKData data;
	osgDB::ifstream fin((DATA_PATH + filename).c_str(), osgDB::ifstream::binary);
	if (!fin)
	{
		std::cout << "Failed to open VTK file." << std::endl;
		return data;
	}
	std::string line;
	bool readingPoints = false;
	bool readingCells = false;
	bool readingCellTypes = false;
	bool readingStresses = false;
	bool readingStrains = false;
	bool readingDisplacements = false;
	bool readingPorePressures = false;
	bool readingPEEQs = false;
	bool readingMisesStresses = false;
	bool readingFluidVelocities = false;

	while (std::getline(fin, line)) {
		// 跳过注释行
		if (line.empty() || line[0] == '#') continue;

		// 解析 POINTS
		if (line.find("POINTS") != std::string::npos) {
			readingPoints = true;
			continue;
		}

		if (readingPoints) {
			if (line.find("CELLS") != std::string::npos) {
				readingPoints = false;
				readingCells = true;
				continue;
			}
			std::stringstream ss(line);
			float x, y, z;
			while (ss >> x >> y >> z) {
				data.points.push_back(osg::Vec3(x, y, z));
			}
		}

		// 解析 CELLS
		if (readingCells) {
			if (line.find("CELL_TYPES") != std::string::npos) {
				readingCells = false;
				readingCellTypes = true;
				continue;
			}
			std::stringstream ss(line);
			int numIndices;
			ss >> numIndices; // 每行的第一个数是点的数量
			if (data.type == 0)
				data.type = numIndices;
			std::vector<unsigned int> cell;
			int index;
			for (int i = 0; i < numIndices; ++i) {
				ss >> index;
				cell.push_back(index);
			}
			data.cells.push_back(cell);
		}

		// 解析 CELL_TYPES
		if (readingCellTypes) {
			if (line.find("POINT_DATA") != std::string::npos) {
				readingCellTypes = false;
				continue;
			}
			std::stringstream ss(line);
			int cellType;
			while (ss >> cellType) {
				data.cell_types.push_back(cellType);
			}
		}

		// 解析 POINT_DATA
		if (line.find("POINT_DATA") != std::string::npos) {
			continue;
		}

		// 解析应力张量数组数据
		if (line.find("SCALARS stress float 6") != std::string::npos) {
			readingStresses = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}
		if(readingStresses)
		{
			std::stringstream ss(line);
			std::array<float, 6> stressArray;  // 临时数组存储6个应力分量
			bool validStress = true;
			
			// 读取一行中的6个应力分量
			for (int i = 0; i < 6; ++i) {
				if (!(ss >> stressArray[i])) {
					validStress = false;
					break;
				}
			}
			
			// 如果成功读取了6个分量,则添加到stresses向量中
			if (validStress) {
				data.stresses.push_back(stressArray);
			}
		}

		// 解析应力张量数组数据
		if (line.find("SCALARS strain float 6") != std::string::npos)
		{
			readingStrains = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}
		if(readingStrains)
		{
			std::stringstream ss(line);
			std::array<float, 6> strainArray;  // 临时数组存储6个应力分量
			bool validStrain = true;

			if (validStrain)
			{
				data.strains.push_back(strainArray);
			}
			
		}

		// 解析位移数据
		if (line.find("SCALARS displacement float 3") != std::string::npos) {
			readingDisplacements = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}

		if (readingDisplacements) {
			if (line.find("SCALARS") != std::string::npos) {
				readingDisplacements = false;
			}
			else
			{
				std::stringstream ss(line);
				float dx, dy, dz;
				while (ss >> dx >> dy >> dz) {
					data.displacements.push_back(osg::Vec3(dx, dy, dz));
				}
			}
		}

		// 解析孔隙压力数据
		if (line.find("SCALARS pore_pressure float 1") != std::string::npos) {
			readingPorePressures = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}

		if (readingPorePressures) {
			if (line.find("SCALARS") != std::string::npos) {
				readingPorePressures = false;
			}
			else
			{
				std::stringstream ss(line);
				float pressure;
				while (ss >> pressure) {
					data.pore_pressures.push_back(pressure);
				}
			}
		}

		// 解析等效塑性应变数据
		if (line.find("SCALARS PEEQ float 1") != std::string::npos) {
			readingPEEQs = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}
		if(readingPEEQs)
		{
			std::stringstream ss(line);
			float PEEQ;
			while (ss >> PEEQ) {
				data.PEEQs.push_back(PEEQ);
			}
		}


		// 解析 Mises 应力数据
		if (line.find("SCALARS Mises_stress float 1") != std::string::npos) {
			readingMisesStresses = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}

		if (readingMisesStresses) {
			if (line.find("SCALARS") != std::string::npos) {
				readingMisesStresses = false;
			}
			else
			{
				std::stringstream ss(line);
				float stress;
				while (ss >> stress) {
					data.mises_stresses.push_back(stress);
				}
			}
		}

		// 解析流体速度数据
		if (line.find("SCALARS fluid_velocity float 3") != std::string::npos) {
			readingFluidVelocities = true;
			std::getline(fin, line); // 跳过 LOOKUP_TABLE 行
			continue;
		}
		if(readingFluidVelocities)
		{
			std::stringstream ss(line);
			float vx, vy, vz;
			while (ss >> vx >> vy >> vz) {
				data.fluid_velocities.push_back(osg::Vec3(vx, vy, vz));
			}
		}
	}

	fin.close();

	data.computeMinMax();
	return data;
}

void CalculateTextureSize(const std::vector<osg::Vec3>& points, int& sizeX, int& sizeY, int& sizeZ) {
	float minX = std::numeric_limits<float>::max();
	float minY = std::numeric_limits<float>::max();
	float minZ = std::numeric_limits<float>::max();
	float maxX = std::numeric_limits<float>::lowest();
	float maxY = std::numeric_limits<float>::lowest();
	float maxZ = std::numeric_limits<float>::lowest();

	// 找到点的空间范围
	for (const auto& point : points) {
		if (point.x() < minX) minX = point.x();
		if (point.y() < minY) minY = point.y();
		if (point.z() < minZ) minZ = point.z();
		if (point.x() > maxX) maxX = point.x();
		if (point.y() > maxY) maxY = point.y();
		if (point.z() > maxZ) maxZ = point.z();
	}

	// 计算每个维度的范围
	float xRange = maxX - minX;
	float yRange = maxY - minY;
	float zRange = maxZ - minZ;

	// 确定纹理尺寸(假设每个维度的分辨率为 128)
	sizeX = static_cast<int>(xRange / 1.0f); // 根据实际需求调整分辨率
	sizeY = static_cast<int>(yRange / 1.0f);
	sizeZ = static_cast<int>(zRange / 1.0f);

	// 确保纹理尺寸不超过 GPU 限制
	sizeX = std::min(sizeX, 2048);
	sizeY = std::min(sizeY, 2048);
	sizeZ = std::min(sizeZ, 2048);
}

// 将 3D 纹理切片导出为 PNG 图片
void Export3DTextureSlices(osg::Image* image, int sizeX, int sizeY, int sizeZ, char direction, const std::string& outputDir) {
	if (!image) {
		throw std::invalid_argument("Invalid image pointer");
	}

	int primarySize, secondarySize1, secondarySize2;
	auto getIndices = [&](int p, int s1, int s2) -> const unsigned char* {
		switch (direction) {
		case 'x': return image->data(p, s1, s2);
		case 'y': return image->data(s1, p, s2);
		case 'z': return image->data(s1, s2, p);
		default: throw std::invalid_argument("Invalid direction for slicing");
		}
		};

	switch (direction) {
	case 'x':
		primarySize = sizeX;
		secondarySize1 = sizeY;
		secondarySize2 = sizeZ;
		break;
	case 'y':
		primarySize = sizeY;
		secondarySize1 = sizeX;
		secondarySize2 = sizeZ;
		break;
	case 'z':
		primarySize = sizeZ;
		secondarySize1 = sizeX;
		secondarySize2 = sizeY;
		break;
	default:
		throw std::invalid_argument("Invalid direction for slicing");
	}

	for (int p = 0; p < primarySize; ++p) {
		// 创建 2D 图像对象
		osg::ref_ptr<osg::Image> sliceImage = new osg::Image();
		sliceImage->allocateImage(secondarySize1, secondarySize2, 1, GL_RGBA, GL_UNSIGNED_BYTE);

		for (int s1 = 0; s1 < secondarySize1; ++s1) {
			for (int s2 = 0; s2 < secondarySize2; ++s2) {
				const unsigned char* src = getIndices(p, s1, s2);
				unsigned char* dest = sliceImage->data(s1, s2);
				for (int c = 0; c < 4; ++c) { // 复制 RGBA 数据
					dest[c] = src[c];
				}
			}
		}

		// 保存当前切片为 PNG
		std::ostringstream filename;
		filename << outputDir << "/slice_" << direction << "_"
			<< std::setfill('0') << std::setw(4) << p << ".png";
		osgDB::writeImageFile(*sliceImage, filename.str());
	}
}

void Interpolate3DTexture(osg::Image* image, int sizeX, int sizeY, int sizeZ, char direction) {
	int primarySize, secondarySize1, secondarySize2;
	auto getIndices = [&](int p, int s1, int s2) -> unsigned char* {
		switch (direction) {
		case 'x': return image->data(p, s1, s2);
		case 'y': return image->data(s1, p, s2);
		case 'z': return image->data(s1, s2, p);
		default: throw std::invalid_argument("Invalid direction for interpolation");
		}
		};

	switch (direction) {
	case 'x':
		primarySize = sizeX;
		secondarySize1 = sizeY;
		secondarySize2 = sizeZ;
		break;
	case 'y':
		primarySize = sizeY;
		secondarySize1 = sizeX;
		secondarySize2 = sizeZ;
		break;
	case 'z':
		primarySize = sizeZ;
		secondarySize1 = sizeX;
		secondarySize2 = sizeY;
		break;
	default:
		throw std::invalid_argument("Invalid direction for interpolation");
	}

	for (int s1 = 0; s1 < secondarySize1; ++s1) {
		for (int s2 = 0; s2 < secondarySize2; ++s2) {
			// 记录所有非透明点的索引
			std::vector<int> nonTransparentIndices;
			for (int p = 0; p < primarySize; ++p) {
				const unsigned char* dataPtr = getIndices(p, s1, s2);
				if (*dataPtr != 0.0) { // 值是否有效
					nonTransparentIndices.push_back(p);
				}
			}

			// 对相邻非透明点之间插值
			for (size_t i = 0; i + 1 < nonTransparentIndices.size(); ++i) {
				int p1 = nonTransparentIndices[i];
				int p2 = nonTransparentIndices[i + 1];

				const unsigned char* dataPtr1 = getIndices(p1, s1, s2);
				const unsigned char* dataPtr2 = getIndices(p2, s1, s2);

				for (int p = p1 + 1; p < p2; ++p) {
					unsigned char* dataPtr = getIndices(p, s1, s2);

					// 使用平滑的插值权重
					float t = float(p - p1) / (p2 - p1);
					t = t * t * (3.0f - 2.0f * t); // 立方插值,t在[0, 1]之间
					*dataPtr = static_cast<unsigned char>(
						*dataPtr1 * (1.0f - t) + *dataPtr2 * t);
				}
			}
		}
	}
}

osg::Texture3D* Create3DTextureFromVtk(const VTKData& data, osg::BoundingBox& bbox)
{
	CalculateTextureSize(data.points, sizeX, sizeY, sizeZ);
	sizeX = osg::Image::computeNearestPowerOfTwo(sizeX);
	sizeY = osg::Image::computeNearestPowerOfTwo(sizeY);
	sizeZ = osg::Image::computeNearestPowerOfTwo(sizeZ);

	osg::Texture3D* t3d = new osg::Texture3D;
	osg::Image* image = new osg::Image;
	image->allocateImage(sizeX, sizeY, sizeZ, GL_LUMINANCE, GL_UNSIGNED_BYTE);
	unsigned char* imageData = image->data();
	std::memset(imageData, 0.0, sizeX * sizeY * sizeZ * 1); // 所有体素初始化为0
	t3d->setImage(image);

	// 计算点的空间范围
	float minX = FLT_MAX;
	float minY = FLT_MAX;
	float minZ = FLT_MAX;
	float maxX = -FLT_MAX;
	float maxY = -FLT_MAX;
	float maxZ = -FLT_MAX;
	for (const auto& point : data.points) {
		if (point.x() < minX) minX = point.x();
		if (point.y() < minY) minY = point.y();
		if (point.z() < minZ) minZ = point.z();
		if (point.x() > maxX) maxX = point.x();
		if (point.y() > maxY) maxY = point.y();
		if (point.z() > maxZ) maxZ = point.z();
	}
	float xRange = maxX - minX;
	float yRange = maxY - minY;
	float zRange = maxZ - minZ;

	bbox.set(osg::Vec3(minX, minY, minZ), osg::Vec3(maxX, maxY, maxZ));

	// 将标量数据写入 3D 纹理
	const float range = data.maxVal - data.minVal;
	for(int i = 0; i < data.points.size(); ++i)
	{
		const osg::Vec3 point = data.points[i];
		osg::Vec3 texCoord((point.x() - minX) / xRange, (point.y() - minY) / yRange, (point.z() - minZ) / zRange);
		osg::Vec3ui xyz(texCoord.x() * (sizeX - 1), texCoord.y() * (sizeY - 1), texCoord.z() * (sizeZ - 1));
		const float stressNormalized = (data.stresses[i][3] - data.minVal) / range;

		// 将归一化值映射到 [1, 255]
		const float mappedValue = stressNormalized * 254.0f + 1.0f; // 映射范围为 [1, 255]
		// 将映射后的值存储到纹理数据中(注意:映射值在 [1, 255] 范围)
		unsigned char* dataPtr = image->data(xyz.x(), xyz.y(), xyz.z());
		*dataPtr = static_cast<unsigned char>(mappedValue); 
	}
	
	// 插值,可不启用
	Interpolate3DTexture(image, sizeX, sizeY, sizeZ, 'z');
	Interpolate3DTexture(image, sizeX, sizeY, sizeZ, 'x');
	Interpolate3DTexture(image, sizeX, sizeY, sizeZ, 'y');

	//测试用
	//Export3DTextureSlices(image, sizeX, sizeY, sizeZ, 'x', "./x/");
	//Export3DTextureSlices(image, sizeX, sizeY, sizeZ, 'y', "./y/");
	//Export3DTextureSlices(image, sizeX, sizeY, sizeZ, 'z', "./z/");


	t3d->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);//只能用LINEAR
	t3d->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);

	t3d->setWrap(osg::Texture::WRAP_R, osg::Texture3D::CLAMP_TO_BORDER);
	t3d->setWrap(osg::Texture::WRAP_T, osg::Texture3D::CLAMP_TO_BORDER);
	t3d->setWrap(osg::Texture::WRAP_S, osg::Texture3D::CLAMP_TO_BORDER);
	return t3d;
}

osg::Texture1D* Create1DTextureFromVtk(const VTKData& data)
{
	osg::Texture1D* t1d = new osg::Texture1D;
	osg::Image* image = new osg::Image;
	image->allocateImage(256, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
	t1d->setImage(image);

	unsigned char* imageData = image->data();
	// 创建 TransferFunction1D
	osg::ref_ptr<osg::TransferFunction1D> tf = new osg::TransferFunction1D;

	osg::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0);   // 蓝色
	osg::Vec4 green(0.0f, 1.0f, 0.0f, 1.0);  // 绿色
	osg::Vec4 yellow(1.0f, 1.0f, 0.0f, 1.0); // 黄色
	osg::Vec4 red(1.0f, 0.0f, 0.0f, 1.0);    // 红色
	// 定义颜色映射
	tf->setColor(0.f / 255.0f, blue); 
	tf->setColor(85.f / 255.0f, green);
	tf->setColor(170.f / 255.0f, yellow);
	tf->setColor(255.f / 255.0f, red);

	for (int i = 0; i < 256; ++i)
	{
		unsigned char* dataPtr = image->data(i, 0, 0);
		if (i != 0)
		{
			const osg::Vec4 color = tf->getColor(static_cast<float>(i) / 255.0f);
			dataPtr[0] = color.r() * 255.0;
			dataPtr[1] = color.g() * 255.0;
			dataPtr[2] = color.b() * 255.0;
			dataPtr[3] = color.a() * 255.0;
		}
		else
		{
			dataPtr[0] = 0.0;
			dataPtr[1] = 0.0;
			dataPtr[2] = 0.0;
			dataPtr[3] = 0.0;
		}

	}
	t1d->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	t1d->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	t1d->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
	return t1d;
}

osg::Node* CreateVtkMesh(const VTKData& vtkData) {
	osg::Geode* geode = new osg::Geode;
	osg::Geometry* geometry = new osg::Geometry;

	// 设置顶点数据
	osg::Vec3Array* vertices = new osg::Vec3Array;
	// 计算边界框
	osg::Vec3 minPoint(FLT_MAX, FLT_MAX, FLT_MAX);
	osg::Vec3 maxPoint(-FLT_MAX, -FLT_MAX, -FLT_MAX);
	for (const auto& point : vtkData.points) {
		vertices->push_back(point);
	}

	geometry->setVertexArray(vertices);

	const int size = vtkData.cells.size();
	// 设置单元数据(假设单元类型为三角形)
	osg::DrawElementsUInt* elements;
	if (vtkData.type == 8)
	{
		elements = new osg::DrawElementsUInt(GL_TRIANGLES);
		for (const auto& cell : vtkData.cells) {
			elements->push_back(cell[0]);
			elements->push_back(cell[1]);
			elements->push_back(cell[2]);
			elements->push_back(cell[0]);
			elements->push_back(cell[2]);
			elements->push_back(cell[3]);

			elements->push_back(cell[4]);
			elements->push_back(cell[5]);
			elements->push_back(cell[6]);
			elements->push_back(cell[4]);
			elements->push_back(cell[6]);
			elements->push_back(cell[7]);

			elements->push_back(cell[0]);
			elements->push_back(cell[1]);
			elements->push_back(cell[5]);
			elements->push_back(cell[0]);
			elements->push_back(cell[5]);
			elements->push_back(cell[4]);


			elements->push_back(cell[1]);
			elements->push_back(cell[2]);
			elements->push_back(cell[6]);
			elements->push_back(cell[1]);
			elements->push_back(cell[6]);
			elements->push_back(cell[5]);

			elements->push_back(cell[2]);
			elements->push_back(cell[3]);
			elements->push_back(cell[7]);
			elements->push_back(cell[2]);
			elements->push_back(cell[7]);
			elements->push_back(cell[6]);

			elements->push_back(cell[3]);
			elements->push_back(cell[0]);
			elements->push_back(cell[4]);
			elements->push_back(cell[3]);
			elements->push_back(cell[4]);
			elements->push_back(cell[7]);
		}
	}
	else if (vtkData.type == 4)
	{
		elements = new osg::DrawElementsUInt(GL_QUADS);
		for (const auto& cell : vtkData.cells) {
			elements->push_back(cell[0]);
			elements->push_back(cell[1]);
			elements->push_back(cell[2]);
			elements->push_back(cell[3]);
		}
	}

	geometry->addPrimitiveSet(elements);
	geode->addDrawable(geometry);

	osg::StateSet* ss = geode->getOrCreateStateSet();
	ss->setMode(GL_BLEND, osg::StateAttribute::ON);
	ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	
	return geode;
}

osg::Node* CreateVtkBox(const VTKData& vtkData)
{
	osg::Geode* gnode = new osg::Geode;
	osg::Geometry* geom = new osg::Geometry;
	gnode->addDrawable(geom);

	osg::BoundingBox bbox;
	osg::ref_ptr<osg::Texture3D> t3d = Create3DTextureFromVtk(vtkData, bbox);
	osg::ref_ptr<osg::Texture1D> t1d = Create1DTextureFromVtk(vtkData);

	// 根据 bbox 范围定义顶点
	const osg::Vec3 min = bbox._min;
	const osg::Vec3 max = bbox._max;

	// 定义立方体的 8 个顶点
	osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
	vertices->push_back(osg::Vec3(min.x(), min.y(), min.z())); // 0
	vertices->push_back(osg::Vec3(max.x(), min.y(), min.z())); // 1
	vertices->push_back(osg::Vec3(max.x(), max.y(), min.z())); // 2
	vertices->push_back(osg::Vec3(min.x(), max.y(), min.z())); // 3
	vertices->push_back(osg::Vec3(min.x(), min.y(), max.z())); // 4
	vertices->push_back(osg::Vec3(max.x(), min.y(), max.z())); // 5
	vertices->push_back(osg::Vec3(max.x(), max.y(), max.z())); // 6
	vertices->push_back(osg::Vec3(min.x(), max.y(), max.z())); // 7

	// 定义立方体的 6 个面(每个面由 4 个顶点组成)
	osg::ref_ptr<osg::DrawElementsUShort> indices = new osg::DrawElementsUShort(GL_QUADS);

	// 前面
	indices->push_back(0); indices->push_back(1); indices->push_back(2); indices->push_back(3);
	// 后面
	indices->push_back(4); indices->push_back(5); indices->push_back(6); indices->push_back(7);
	// 左面
	indices->push_back(0); indices->push_back(3); indices->push_back(7); indices->push_back(4);
	// 右面
	indices->push_back(1); indices->push_back(2); indices->push_back(6); indices->push_back(5);
	// 底面
	indices->push_back(0); indices->push_back(1); indices->push_back(5); indices->push_back(4);
	// 顶面
	indices->push_back(2); indices->push_back(3); indices->push_back(7); indices->push_back(6);

	// 设置顶点数组和索引
	geom->setVertexArray(vertices);
	geom->addPrimitiveSet(indices);

	// 设置纹理和着色器
	osg::StateSet* ss = gnode->getOrCreateStateSet();
	osg::Program* program = new osg::Program;
	ss->setMode(GL_BLEND, osg::StateAttribute::ON);
	ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	ss->setTextureAttributeAndModes(0, t3d, osg::StateAttribute::ON);
	ss->setTextureAttributeAndModes(1, t1d, osg::StateAttribute::ON);
	ss->setAttribute(program);
	program->addShader(osgDB::readRefShaderFile(osg::Shader::VERTEX, SHADER_PATH + R"(volume.vert)"));
	program->addShader(osgDB::readRefShaderFile(osg::Shader::FRAGMENT, SHADER_PATH + R"(volume.frag)"));

	ss->addUniform(new osg::Uniform("steps", 100));
	ss->addUniform(new osg::Uniform("densityFactor", 10.0f));
	ss->addUniform(new osg::Uniform("minBound", min));
	ss->addUniform(new osg::Uniform("maxBound", max));
	ss->addUniform(new osg::Uniform("baseTexture", int(0)));
	ss->addUniform(new osg::Uniform("tfTexture", int(1)));

	return gnode;
}

class KeyboardEventHandler : public osgGA::GUIEventHandler {
public:
	KeyboardEventHandler(osg::Node* vtkBox, osg::Node* vtkMesh)
		: _vtkBox(vtkBox), _vtkMesh(vtkMesh), _vtkBox1Visible(true), _vtkMeshVisible(true) {
	}

	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override {
		if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
			switch (ea.getKey()) {
			case 'c':  // 按 'c' 键切换 体渲染结果 的显隐
				_vtkBox1Visible = !_vtkBox1Visible;
				_vtkBox->setNodeMask(_vtkBox1Visible ? 0xFFFFFFFF : 0); // 切换可见性
				return true;
			case 'v':  // 按 'v' 键切换 VTK mesh 的显隐
				_vtkMeshVisible = !_vtkMeshVisible;
				_vtkMesh->setNodeMask(_vtkMeshVisible ? 0xFFFFFFFF : 0); // 切换可见性
				return true;
			default:
				return false;
			}
		}
		return false;
	}

private:
	osg::ref_ptr<osg::Node> _vtkBox;
	osg::ref_ptr<osg::Node> _vtkMesh;
	bool _vtkBox1Visible;
	bool _vtkMeshVisible;
};

// 创建3D噪声纹理,只在下半部分生成水
osg::Texture3D* Create3DNoiseTexture(int size, osg::BoundingBox& bbox)
{
	osg::Texture3D* t3d = new osg::Texture3D;
	osg::Image* image = new osg::Image;
	image->allocateImage(size, size, size, GL_LUMINANCE, GL_UNSIGNED_BYTE);
	t3d->setImage(image);

	const double frequency = 4.0; // 噪声频率
	const int octaves = 4;       // 噪声叠加次数
	unsigned char* imageData = image->data();
	std::memset(imageData, 0.0, size * size * size * 1);
	for (int z = 0; z < size; ++z) {
		for (int y = 0; y < size; ++y) {
			for (int x = 0; x < size; ++x) {
				unsigned char* dataPtr = image->data(x, y, z);
				// 计算归一化的高度(z坐标)
				float heightNorm = (float)z / size;
				
				// 添加一个硬边界,确保上半部分完全为0
				if (heightNorm > 0.5f) {
					break;
				}

				// 在水面附近创建一个过渡区域
				float transitionZone = 0.1f; // 过渡区域的大小
				float waterSurfaceHeight = 0.5f;
				float distanceToSurface = waterSurfaceHeight - heightNorm;
				
				if (distanceToSurface < transitionZone) {
					// 在过渡区域内线性减少密度
					float factor = distanceToSurface / transitionZone;
					*dataPtr = static_cast<unsigned char>(0.0);
					continue;
				}

				float noiseVal = 0.0f;
				float amplitude = 1.0f;
				float totalAmplitude = 0.0f;

				// 叠加多层噪声
				for (int o = 0; o < octaves; ++o) {
					float scale = frequency * (1 << o);
					float sampleX = (float)x / size * scale;
					float sampleY = (float)y / size * scale;
					float sampleZ = (float)z / size * scale;

					noiseVal += simpleNoise(sampleX, sampleY, sampleZ) * amplitude;
					totalAmplitude += amplitude;
					amplitude *= 0.5f;
				}

				// 归一化到[0,1]范围
				noiseVal = (noiseVal / totalAmplitude + 1.0f) * 0.5f;

				// 添加基于高度的渐变,使底部更密集
				float heightFactor = 1.0f - (heightNorm / 0.5f); // 从底部到水面渐变
				noiseVal *= heightFactor * heightFactor; // 使用平方来创建更强的渐变

				// 将噪声值映射到[0,255]范围,并确保上半部分为0
				unsigned char value = static_cast<unsigned char>(noiseVal * 255.0f);
				*dataPtr = value;
			}
		}
	}

	bbox.set(osg::Vec3(-1, -1, -1), osg::Vec3(1, 1, 1));

	t3d->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	t3d->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	t3d->setWrap(osg::Texture::WRAP_R, osg::Texture3D::CLAMP_TO_EDGE);
	t3d->setWrap(osg::Texture::WRAP_T, osg::Texture3D::CLAMP_TO_EDGE);
	t3d->setWrap(osg::Texture::WRAP_S, osg::Texture3D::CLAMP_TO_EDGE);

	return t3d;
}

// 创建水的传递函数纹理
osg::Texture1D* CreateWaterTransferFunction()
{
	osg::Texture1D* t1d = new osg::Texture1D;
	osg::Image* image = new osg::Image;
	image->allocateImage(256, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE);
	t1d->setImage(image);

	// 水的颜色渐变
	osg::Vec4 waterColor1(0.0f, 0.2f, 0.4f, 0.1f);   // 深蓝色,较透明
	osg::Vec4 waterColor2(0.0f, 0.4f, 0.8f, 0.5f);   // 中蓝色,半透明
	osg::Vec4 waterColor3(0.1f, 0.6f, 0.9f, 0.8f);   // 浅蓝色,较不透明

	for (int i = 0; i < 256; ++i)
	{
		unsigned char* dataPtr = image->data(i, 0, 0);
		float t = static_cast<float>(i) / 255.0f;

		if (i == 0) {
			// 完全透明的值
			dataPtr[0] = 0;
			dataPtr[1] = 0;
			dataPtr[2] = 0;
			dataPtr[3] = 0;
		}
		else {
			osg::Vec4 color;
			if (t < 0.5f) {
				float s = t / 0.5f;
				color = waterColor1 * (1.0f - s) + waterColor2 * s;
			}
			else {
				float s = (t - 0.5f) / 0.5f;
				color = waterColor2 * (1.0f - s) + waterColor3 * s;
			}

			dataPtr[0] = static_cast<unsigned char>(color.r() * 255.0f);
			dataPtr[1] = static_cast<unsigned char>(color.g() * 255.0f);
			dataPtr[2] = static_cast<unsigned char>(color.b() * 255.0f);
			dataPtr[3] = static_cast<unsigned char>(color.a() * 255.0f);
		}
	}

	t1d->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
	t1d->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
	t1d->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);

	return t1d;
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	osg::ref_ptr<osg::Group> group = new osg::Group;
	VTKData data = ParseVtkFile(R"(xxx.vtk)");


	//osg::Node* points = CreatePoints(data);
	//group->addChild(points);

	osg::Node* vtkBox = CreateVtkBox(data);
	group->addChild(vtkBox);
	osg::Node* vtkMesh = CreateVtkMesh(data);
	group->addChild(vtkMesh);
	osg::ref_ptr<KeyboardEventHandler> keyboardHandler = new KeyboardEventHandler(vtkBox, vtkMesh);
	viewer->addEventHandler(keyboardHandler);


	viewer->setSceneData(group);
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::StatsHandler());

	return viewer->run();
}



你可能感兴趣的:(着色器,着色器,c++,开发语言)