读取模型并进行半角切片渲染
#include <iostream>
#include <vector>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
// Function to load the PLY model and extract vertex data using Assimp
void loadPLYModel(const std::string& filePath, std::vector<float>& vertices, int& volumeWidth, int& volumeHeight, int& volumeDepth) {
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filePath, aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || !scene->HasMeshes()) {
std::cerr << "Failed to load PLY model!" << std::endl;
return;
}
// Extract vertex data from the model
const aiMesh* mesh = scene->mMeshes[0];
volumeWidth = mesh->mNumVertices;
volumeHeight = 1; // Set to 1 for simplicity (depends on your model)
volumeDepth = 1; // Set to 1 for simplicity (depends on your model)
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {
aiVector3D position = mesh->mVertices[i];
vertices.push_back(position.x);
vertices.push_back(position.y);
vertices.push_back(position.z);
}
}
// Function to create a 3D texture from vertex data
GLuint create3DTexture(const std::vector<float>& vertices, int volumeWidth, int volumeHeight, int volumeDepth) {
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_3D, textureID);
// Create a 3D texture using the vertex data (we're assuming grayscale data for simplicity)
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, volumeWidth, volumeHeight, volumeDepth, 0, GL_RGB, GL_FLOAT, vertices.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}
// Shader source code
const char* vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
out vec3 texCoord;
void main() {
gl_Position = vec4(aPos, 1.0);
texCoord = aPos; // Pass texture coordinates as the vertex positions
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;
in vec3 texCoord;
uniform sampler3D texture3D;
void main() {
// Sample the texture at the given 3D texture coordinates
FragColor = texture(texture3D, texCoord);
}
)";
// Compile shader
GLuint compileShader(const char* source, GLenum type) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
int success;
char infoLog[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
std::cerr << "Shader compilation failed: " << infoLog << std::endl;
}
return shader;
}
// Create shader program
GLuint createShaderProgram() {
GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
GLuint fragmentShader = compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
int success;
char infoLog[512];
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
std::cerr << "Program linking failed: " << infoLog << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
}
// Render the texture slice based on slice index
void renderSlice(GLuint shaderProgram, GLuint textureID, int sliceIndex, int volumeDepth) {
glUseProgram(shaderProgram);
glBindTexture(GL_TEXTURE_3D, textureID);
// Set texture slice index as a uniform
glUniform1f(glGetUniformLocation(shaderProgram, "sliceIndex"), (float)sliceIndex / (float)volumeDepth);
// Draw a quad to render the texture slice
glBegin(GL_QUADS);
glTexCoord3f(0.0f, 0.0f, sliceIndex / (float)volumeDepth); glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord3f(1.0f, 0.0f, sliceIndex / (float)volumeDepth); glVertex3f(1.0f, -1.0f, 0.0f);
glTexCoord3f(1.0f, 1.0f, sliceIndex / (float)volumeDepth); glVertex3f(1.0f, 1.0f, 0.0f);
glTexCoord3f(0.0f, 1.0f, sliceIndex / (float)volumeDepth); glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd();
}
int main() {
// Initialize GLFW
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW!" << std::endl;
return -1;
}
// Create window
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL 3D Texture Slicing", nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create GLFW window!" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, int width, int height) {
glViewport(0, 0, width, height);
});
// Initialize GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialize GLAD!" << std::endl;
return -1;
}
// Load model and create texture
std::vector<float> vertices;
int volumeWidth, volumeHeight, volumeDepth;
loadPLYModel("spotlight1.ply", vertices, volumeWidth, volumeHeight, volumeDepth);
GLuint textureID = create3DTexture(vertices, volumeWidth, volumeHeight, volumeDepth);
GLuint shaderProgram = createShaderProgram();
// Main render loop
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < volumeDepth; ++i) {
renderSlice(shaderProgram, textureID, i, volumeDepth);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
// Clean up
glDeleteTextures(1, &textureID);
glDeleteProgram(shaderProgram);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}