使用WebGL API,我如何从深度缓冲区获取值,或以任何其他方式从屏幕坐标确定3D坐标(即找到点击的位置),而不是通过执行我自己的光线投射?
我已经设法在OpenGL中实现了一个对数深度缓冲区,主要是来自Outerra的文章(你可以在这里,这里和这里阅读).但是,我遇到了一些问题,我不确定这些问题是否是使用对数深度缓冲区所固有的,或者是否有一些我无法想到的解决方法.
刚开始,这就是我在顶点着色器中计算对数深度的方法:
gl_Position = MVP * vec4(inPosition, 1.0);
gl_Position.z = log2(max(ZNEAR, 1.0 + gl_Position.w)) * FCOEF - 1.0;
flogz = 1.0 + gl_Position.w;
Run Code Online (Sandbox Code Playgroud)
这就是我在片段着色器中修复深度值的方法:
gl_FragDepth = log2(flogz) * HALF_FCOEF;
Run Code Online (Sandbox Code Playgroud)
在哪里ZNEAR = 0.0001,ZFAR = 1000000.0和FCOEF = 2.0 / log2(ZFAR + 1.0),和HALF_FCOEF = 0.5 * FCOEF. C在我的例子中,是1.0,以简化我的代码并减少计算.
对于初学者来说,我对我获得的精确程度非常满意.使用正常的深度缓冲(znear = 0.1,zfar = 1000.0),我会朝视距的边缘进行相当多的z-fighting.现在,随着我的进一步znear:zfar,我已经将第二个地平面放置在第一个以下0.01个单位,我无法找到任何z-fighting,无论我将相机放大多远(我得到一点z-战斗时只有0.0001(0.1毫米),但是meh).
不过,我确实有一些问题/疑虑.
1)我得到的平面剪裁比我的普通深度缓冲更多,看起来很难看.它发生在逻辑上它确实不应该的情况下.以下是我的意思的几个屏幕截图:
这两种情况都是我用普通深度缓冲区没有遇到的情况,我宁愿看不到(特别是前者).编辑:问题1通过使用正式解决glEnable(GL_DEPTH_CLAMP).
2)为了使其工作,我需要写入gl_FragDepth.我试过不这样做,但结果是不可接受的.写入gl_FragDepth意味着我的显卡无法进行早期z优化.这将不可避免地让我爬上墙,所以我想尽快解决它.
3)我需要能够检索存储在深度缓冲区中的值(我已经有了帧缓冲区和纹理),然后将其转换为线性视图空间坐标.我真的不知道从哪里开始这个,我之前做过它的方式涉及逆投影矩阵,但我不能在这里真正做到这一点.有什么建议?
在将当前的延迟渲染器更改为使用对数深度缓冲区后,我无法解决,对于我的生活,如何从深度缓冲区值重建世界空间深度.
当我编写OpenGL默认z/w深度时,我可以通过从窗口空间转换到NDC空间来轻松计算此值,然后执行逆透视变换.
我在第二遍片段着色器中完成了所有这些操作:
uniform sampler2D depth_tex;
uniform mat4 inv_view_proj_mat;
in vec2 uv_f;
vec3 reconstruct_pos(){
float z = texture(depth_tex, uv_f).r;
vec4 pos = vec4(uv_f, z, 1.0) * 2.0 - 1.0;
pos = inv_view_proj_mat * pos;
return pos.xyz / pos.w;
}
Run Code Online (Sandbox Code Playgroud)
并得到一个看起来非常正确的结果:
但现在通往简单z价值的道路并不那么容易(似乎也不应该这么难).
我的第一次传递的顶点着色器具有日志深度:
#version 330 core
#extension GL_ARB_shading_language_420pack : require
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 uv;
uniform mat4 mvp_mat;
uniform float FC;
out vec2 uv_f;
out float logz_f;
out float FC_2_f; …Run Code Online (Sandbox Code Playgroud) 据我所知,我们无法读取OpenGL ES 2.0中的Z(深度)值.所以我想知道如何从2D屏幕上的某个点获取3D世界坐标?
其实我有一些随意的想法可能会奏效.由于我们可以使用glReadPixels读取RGBA值,我们如何复制深度缓冲区并将其存储在颜色缓冲区(比如ColorforDepth)中.当然需要有一些很好的约定,这样我们就不会丢失深度缓冲区的任何信息.然后当我们需要一个点的世界坐标时,我们将这个ColorforDepth颜色缓冲区附加到帧缓冲区然后渲染它.所以当我们使用glReadPixels读取此帧的深度信息时.
但是,这将导致1帧闪存,因为颜色缓冲区是从深度缓冲区转换的奇怪缓冲区.我仍然想知道是否有一些标准的方法来获得OpenGL es 2.0的深度?
Thx提前!:)
我正在为我正在开发的游戏构建一个小型 3D 引擎。我已经整理了我的基础知识:带有背面剔除的纹理三角形。然而,深度排序被证明是一个难题。
我通过平均构成三角形面的 3 个点来计算面 Z。较长的面有时会与较小的面重叠,因为它们具有较大的 Z 值,因此会在深度排序的显示列表中上升。
我该如何解决?如果我只能在编程时获得一些实际帮助,我确信存在已知的深度排序技术。我自己构建了渲染管道,所以我可以访问所有必需的数据 - 三角形、点、纹理、UV 坐标等。
以 3D 程序呈现的大教堂

在我的 3D 引擎中渲染的大教堂

我有时会glDepthMask(GL_FALSE)在渲染帧期间禁用深度缓冲区写入.这在某些GPU(如摩托罗拉Droid的PowerVR)上完全正常,但在HTC EVO和Adreno GPU上,我最终得到的帧缓冲区是完全垃圾(我看到了我在某处渲染的网格痕迹,但是整个屏幕大部分被删除).
如果我强制glDepthMask在整个时间都是真的,那么一切正常.
我需要在alpha渲染的部分期间关闭glDepthMask.什么可以通过转动深度写入导致帧缓冲区被破坏?
我使用SFML来创建窗口.
在此屏幕截图中,多维数据集应位于金字塔后面,但它不起作用.

这是我使用的最小代码:
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <SFML/Graphics.hpp>
#include "ResourcePath.hpp"
void resize();
void drawScene();
void initGL();
float rtri = 0;
float rquad = 0;
float z = -10.0f;
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow *window = new sf::RenderWindow();
window->Create( sf::VideoMode( 800, 600, 32 ), "Collision Detection", sf::Style::Close );
sf::Event event;
bool run = true;
initGL();
resize();
while( run ) {
window->PollEvent( event );
if( event.Type == sf::Event::Closed ) …Run Code Online (Sandbox Code Playgroud) 作为一个DirectX noob,我试图将我的头部包裹在深度缓冲区周围,特别是如何为遮挡像素调用像素着色器.
根据我的理解,光栅化器为覆盖绘制的原始图像的每个像素调用像素着色器,然后在输出合并阶段,输出合并器检查深度缓冲区并丢弃,写入或混合后面缓冲区中的像素.
这看起来很浪费,但是如果我在一个非常复杂的对象前面渲染一个简单的不透明对象,那么让光栅化器检查深度图是有用的甚至在调用复杂对象的像素着色器之前.
做研究我发现早期Z测试/保守Z测试等等,但似乎也没有关于它的文档.我找了一种在rasterizer状态desc对象上配置它的方法,但我只在OM状态desc上找到了类似的东西.
似乎可以在DX9中使用SetRenderState进行设置(尽管我没有使用DX9的经验)
根据我的研究,如果我从前到后渲染对象,这似乎是某些硬件才会这样做,这是正确的吗?我怎么能说出来?所有的Control DirectX都让你看起来很奇怪,因为它似乎是一个很好的优化:)
关于此的任何信息或参考都是适用的
似乎很难找到有关如何在连续渲染过程的着色器中访问深度和模板缓冲区的信息.
在第一个渲染过程中,我不仅渲染颜色和深度信息,还使用模板操作来计算对象.我为此使用了一个多渲染目标FBO,附带了颜色缓冲区和组合深度模板缓冲区.所有这些都是纹理的形式(没有涉及渲染缓冲对象).
在第二个渲染过程中(当渲染到屏幕时),我想基于每个像素访问先前计算的模板索引(但不一定是我正在绘制的相同像素),类似于您想要访问的先前渲染的颜色缓冲区以应用一些后期处理效果.
但是我没能将第二遍中的深度模板纹理绑定到我的着色器程序作为制服.至少只从中读取黑色值,所以我猜它没有正确绑定.
是否可以将深度模板纹理绑定到纹理单元以用于着色器程序?使用"普通"采样器是否无法访问深度和模板纹理?是否可以使用一些"特殊"采样器?它取决于在纹理或类似设置上设置的插值模式吗?
如果没有,在这两个渲染过程之间将模板信息复制到单独的颜色纹理中的最佳(最快)方法是什么?可能涉及使用模板测试绘制单一颜色的第三个渲染过程(我在最终渲染过程中只需要模板缓冲区的二进制版本,确切地说,我需要测试值是否为零).
中间FBO使用的纹理设置如下:
// The textures for color information (GL_COLOR_ATTACHMENT*):
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// The texture for depth and stencil information (GL_DEPTH_STENCIL_ATTACHMENT*):
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0);
Run Code Online (Sandbox Code Playgroud)
在第二个渲染过程中,我目前只尝试"调试"所有纹理的内容.因此,我使用以下值设置着色器:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, <texture>);
glUniform1i(texLocation, 0);
Run Code Online (Sandbox Code Playgroud)
让着色器程序只需将纹理复制到屏幕:
uniform sampler2D tex;
in vec2 texCoord;
out vec4 fragColor;
void main() {
fragColor = texture2D(tex, texCoord);
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
当<texture>上面指的是我的一个颜色纹理时,我看到在第一个渲染过程中渲染的颜色输出,这是我所期望的.
当<texture>上面指深度模板纹理时,着色器不做任何事情(我看到用于清除屏幕的颜色).
将深度模板纹理复制到CPU并进行检查时,我会按预期在打包的24 + 8位数据中看到深度和模板信息.
在WebGL中,是否可以写入片段的深度值或以其他方式控制片段的深度值?
据我所知,gl_FragDepth在webgl 1.x中不存在,但我想知道是否还有其他方法(扩展,浏览器特定支持等)来做到这一点.
我想要存档的是让光线跟踪对象与使用通常的模型,视图,投影绘制的其他元素一起播放.
depth-buffer ×10
opengl ×4
glsl ×3
opengl-es ×3
3d ×2
rendering ×2
webgl ×2
android ×1
c++ ×1
directx ×1
directx-11 ×1
optimization ×1
raytracing ×1
sfml ×1
textures ×1