gpt4 book ai didi

java - 延迟阴影在LWJGL中到底如何工作?

转载 作者:行者123 更新时间:2023-12-01 23:57:13 25 4
gpt4 key购买 nike

我想使用GLSL,Java和openGl启动一个延迟着色项目

1.延迟渲染管线如何工作,是否为每个图像渲染场景?
例如,当我要创建镜面,模糊和阴影纹理时,是否需要为每个这些纹理渲染场景。

我看过一些代码片段,那里没有多个渲染循环。

2.什么是几何缓冲区,它有什么作用?就像场景数据的存储区一样,我可以将其绘制到纹理而无需再次渲染吗?

最佳答案

要添加更具体的内容,您可以开始使用。您需要具有多个附件的FBO,并且需要一种用于着色器写入多个FBO附件的方式。 Google glDrawBuffers。您的FBO附件也需要是纹理,以便可以将信息传递到着色器。 FBO附件的尺寸应与要渲染到的屏幕的尺寸相同。有很多方法可以解决此问题。这是一个例子。

您需要两个FBO

几何缓冲区

1. Diffuse (GL_RGBA)
2. Normal Buffer (GL_RGB16F)
3. Position Buffer (GL_RGB32F)
4. Depth Buffer

注意3)是巨大的浪费,因为我们可以使用深度缓冲区和投影来重建位置。这 便宜很多。至少要有一个位置缓冲才是一个好的开始。一次攻击一个问题。

2)普通缓冲区也可以压缩更多。

聚光缓冲液
1. Light Buffer (GL_RGBA)
2. Depth Buffer

该FBO中的深度缓冲区附件应与几何缓冲区中的附件相同。在此示例中,我们可能不会使用此深度缓冲区信息,但是您迟早会需要它。它将始终包含第一阶段的深度信息。

我们如何渲染这些东西?

我们首先使用非常简单的着色器渲染场景。这些的目的主要是填充几何缓冲区。我们只需用一个非常简单的着色器绘制所有几何图形,即可填充几何图形缓冲区。为简单起见,我使用了120个着色器,没有纹理映射(尽管添加起来非常简单)。

顶点着色器:
#version 120

varying vec3 normal;
varying vec4 position;

void main( void )
{
normal = normalize(gl_NormalMatrix * gl_Normal);
position = gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

片段着色器:
#version 120

uniform vec4 objectColor; // Color of the object you are drawing
varying vec3 normal;
varying vec4 position;

void main( void )
{
// Use glDrawBuffers to configure multiple render targets
gl_FragData[0] = objectColor; // Diffuse
gl_FragData[1] = vec4(normalize(normals.xyz), 0.0); // normals
gl_FragData[2] = vec4(position.xyz, 0.0); // Position
}

例如,我们现在绘制了20个对象,以绘制具有不同颜色的几何缓冲区。如果我们看一下漫反射缓冲区,它是一个带有纯色(或没有照明的纯纹理)的呆板图像,但是我们仍然具有每个片段的 View 位置,法线和深度。这对于下一步照明时将是有值(value)的信息。

轻度累积

现在,我们切换到光累积缓冲区,是时候进行一些灯光魔术了。对于每个单独的光源,我们将在启用了添加剂混合的情况下提取到我们的光累积缓冲区。只要覆盖所有受光影响的片段,如何执行此操作就对结果并不重要。最初可以通过绘制全屏四边形来完成此操作,但这非常昂贵。我们将只覆盖点光源,但这足以覆盖简单的照明原理(简单的点光源制作起来非常琐碎)。一种简单的方法是在按光半径缩放的光位置绘制一个立方体或低多边形球体(光体积)。这使得渲染大量小灯的方式更加有效..但是现在不必担心性能。全屏四边形就可以解决问题。

现在,简单的原理是:
  • 每个片段都有一个存储的x,y,z位置,我们只需通过纹理获取
  • 即可获得
  • 我们传递光
  • 的位置
  • 我们传入光的半径
  • 通过测量位置缓冲区中的值与光源位置
  • 之间的距离,我们可以知道片段是否受光影响
  • 从那里开始,这是相当标准的光照计算

  • 片段着色器:
    (此着色器适用于任何情况。光量,全屏四边形..等等)
    #version 120
    uniform sampler2D diffuseBuffer;
    uniform sampler2D positionBuffer;
    uniform sampler2D normalBuffer;

    uniform float lightRadius; // Radius of our point light
    uniform vec3 lightPos; // Position of our point light
    uniform vec4 lightColor; // Color of our light
    uniform vec2 screensize; // screen resolution

    void main()
    {
    // VU for the current fragment
    vec2 uv = vec2(gl_FragCoord.x / screensize.x, gl_FragCoord.y / screensize.y);
    // Read data from our gbuffer (sent in as textures)
    vec4 diffuse_g = texture2D(diffuseBuffer, uv);
    vec4 position_g = texture2D(positionBuffer, uv);
    vec4 gnormal_g = texture2D(normalBuffer, uv);

    // Distance from the light center and the current pixel
    float distance = length(lightPos - position_g.xyz);

    // If the fragment is NOT affecter by the light we discard it!
    // PS : Don't kill me for using discard. This is for simplicity.
    if(distance > lightRadius) discard;

    // Calculate the intensity value this light will affect the fragment (Standard light stuff!)
    ... Use lightPos and position_g to calculate the light normal ..
    ... Do standard dot product of light normal and normal_g ...
    ... Just standard light stuff ...

    // Super simple attenuation placeholder
    float attenuation = 1.0 - (distance / lightRadius);

    gl_FragColor = diffuse_g * lightColor * attenuation * <multiplier from light calculation>;
    }

    我们为每盏灯重复此操作。渲染灯光的顺序无关紧要,因为添加混合后的结果将始终相同。您也可以通过仅累积光强度来简化操作。从理论上讲,您应该已经在光累积缓冲区中获得了最终的照明结果,但是您可能需要进行其他调整。

    结合

    您可能需要调整一些内容。周围的?色彩校正?多雾路段?其他后期处理的东西。您可以通过一些调整来组合光累积缓冲区和漫反射缓冲区。我们已经在照明阶段完成了此操作,但是如果您仅保存了照明强度,则必须在此处进行简单的 diffuse * light组合。

    通常,只有一个全屏四边形会将最终结果呈现到屏幕上。

    更多东西
  • 如前所述,我们想摆脱位置缓冲区。将深度缓冲区与投影配合使用以重建位置。
  • 您不需要使用轻量。有些人更喜欢简单地渲染一个足以覆盖屏幕区域的四边形。
  • 上面的示例不涉及诸如如何为每个对象定义唯一 Material 的问题。有很多资源和gbuffer格式的变体。有些人喜欢将 Material 索引保存在Alpha channel 中(在漫反射缓冲区中),然后在纹理中查找一行以获取 Material 属性。
  • 通过将全屏四边形渲染到光累积缓冲区
  • 中,可以轻松处理影响整个场景的定向光源和其他光源类型。
  • 聚光灯也很不错,并且也很容易实现
  • 我们可能想要更多的灯光属性
  • 我们可能需要某种方式来权衡如何将漫反射和灯光缓冲区组合在一起以支持环境和发射
  • 有许多以更紧凑的方式存储法线的方法。例如,您可以使用球坐标删除一个值。那里有大量有关延迟照明和gbuffer格式的文章。查看人们使用的格式可以给您一些想法。只要确保您的gbuffer不会太胖即可。
  • 使用线性化的深度值重建 View 位置,并且投影并不难。您需要使用投影常数构造一个 vector 。将其乘以您的深度值(0到1之间)以获取 View 位置。那里有几篇文章。这只是两行代码。

  • 这篇文章可能有很多选择,但希望它能显示出一般的原则。没有一个着色器被编译。内存只是将其从3.3转换为1.2。

    有几种累积光的方法。您可能希望减少绘制调用的数量,以使VBO具有1000个立方体和圆锥体来批量绘制所有内容。对于更现代的GL版本,您还可以使用几何体着色器来计算一个四边形,该四边形将覆盖每个灯光的灯光区域。最好的方法可能是使用计算着色器,但这需要GL 4.3。这样做的好处是,您可以迭代所有光线信息并执行一次写入。您还可以使用伪计算方法将屏幕划分为粗糙的网格并为每个单元格分配一个灯光列表。这只能使用片段着色器完成,但是需要您在CPU上构建光源列表,并通过UBO将数据发送到着色器。

    到目前为止,计算着色器方法是最简单的方法。它消除了跟踪和组织所有内容的旧方法的许多复杂性。只需对灯进行迭代,然后一次写入帧缓冲区即可。

    关于java - 延迟阴影在LWJGL中到底如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16652691/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com