在opengl中
使用模板测试绘制的模型描边 在默认帧缓冲中可以被正常绘制出来
但在自制的帧缓冲中无法被渲染
创建帧缓冲时有创建深度 + 模板缓冲对象
且切换帧缓冲时有清理
主循环:
framebuffer->bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
framebuffer->engineCamera(deltaTime);
Light::use();
EngineSystem::draw(app->getWorld());
glDepthFunc(GL_LEQUAL);
UseShader::use(Shader_SkyBox);
glm::mat4 view = glm::mat4(glm::mat3(Engine::view));
UseShader::setMat4("view", view);
// skybox cube
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
framebuffer->update(deltaTime);
Light::use();
EngineSystem::draw(app->getWorld());
模板测试:
if (Engine::selectEntity!= UINT32_MAX) {
glEnable(GL_STENCIL_TEST); // ステンシルテストを有効に 模板测试
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_ALWAYS, 1, 0xFF); // 常にパスし、参照値 1 を書き込む
glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); // パスしたら 1 で置き換える
ModelComponent* mSelect = world->getEntityComponent<ModelComponent>(Engine::selectEntity);
TransformComponent* tSelect = world->getEntityComponent<TransformComponent>(Engine::selectEntity);
if (!mSelect||!tSelect)return;
Transform tran = tSelect->getTransform();
glm::mat4 T = glm::translate(glm::mat4(1.0f), tran.position());
glm::mat4 R = glm::toMat4(tran.rotation());
glm::mat4 S = glm::scale(glm::mat4(1.0f), tran.lossyScale());
glm::mat4 model = T * R * S;
UseShader::setMat4("model", model);
DrawModle::Draw(mSelect->modelID);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthFunc(GL_ALWAYS);//总是通过深度测试
glDepthMask(GL_FALSE); // 不写入深度缓冲
// ステンシルテストを使用して、描画を制限する
glStencilFunc(GL_NOTEQUAL, 1, 0xFF); // ステンシルバッファが 1 でないピクセルのみ描画
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // ステンシルバッファの値を変更しない
UseShader::use(Shader_Collider);
glm::mat4 modelOutLine = model;
//计算平均缩放
glm::vec3 scale;
scale.x = glm::length(glm::vec3(modelOutLine[0][0], modelOutLine[0][1], modelOutLine[0][2]));
scale.y = glm::length(glm::vec3(modelOutLine[1][0], modelOutLine[1][1], modelOutLine[1][2]));
scale.z = glm::length(glm::vec3(modelOutLine[2][0], modelOutLine[2][1], modelOutLine[2][2]));
float averageScale = (scale.x + scale.y + scale.z) / 3.0f;
float outlineWidth = 0.02f;
float scaleFactor = 1.0f + outlineWidth / averageScale;
modelOutLine = modelOutLine * glm::scale(glm::mat4(1.0f), glm::vec3(scaleFactor));
UseShader::setMat4("model", modelOutLine);
DrawModle::Draw(mSelect->modelID);
UseShader::end();
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glDisable(GL_STENCIL_TEST);
}
帧缓冲的创建函数
// 创建帧缓冲及其附件
void createFramebuffer() {
// 创建帧缓冲对象
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// 创建颜色纹理附件
glGenTextures(1, &texColorBuffer);
glBindTexture(GL_TEXTURE_2D, texColorBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Engine::windowWidth, Engine::windowHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// 附加颜色纹理
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
// 创建深度 + 模板缓冲对象(RBO)
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, Engine::windowWidth, Engine::windowHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
// 检查帧缓冲是否完整
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
}
// 解绑
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
```c++
```