Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

volume #2351

Open
hhhhkrx opened this issue Aug 20, 2024 · 8 comments
Open

volume #2351

hhhhkrx opened this issue Aug 20, 2024 · 8 comments
Assignees
Labels
glTF Rendering Rendering related functions shader Shader related functions
Milestone

Comments

@hhhhkrx
Copy link
Contributor

hhhhkrx commented Aug 20, 2024

GLTF

https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_volume
https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_transmission
根据gltf官方给出的参考,volume的算法需要和KHR_materials_transmission相结合,transmission只模拟了光的透射,volume增加了厚度的算法,折射率的输入则是需要和KHR_materials_ior结合,最终暴露给用户的uniform:

"materials": [
    {
        "extensions": {
            "KHR_materials_volume": {
                "thicknessFactor": 1.0,
                "attenuationDistance":  0.006,
                "attenuationColor": [ 0.5, 0.5, 0.5 ]
            }
        }
    }
]

KHR_materials_transmission参考:

materials: [
  {
    "extensions": {
       "KHR_materials_transmission": {
         "transmissionFactor": 0.8,
         "transmissionTexture": {
           "index": 0
         }
       }
    }
  }
]

three.js

image

  • 基于屏幕空间,通过 getTransmissionSample 函数采样屏幕上的 framebuffer
vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {

		float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );
		return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );

	}

https://github.com/mrdoob/three.js/blob/e6f98724943459ea395c856a253200e8aac61ceb/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js#L170

  • 其中 transmissionSamplerMap 来源:
uniforms.transmission.value = material.transmission;
uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );

babylon

image

https://github.com/BabylonJS/Babylon.js/blob/1e2bc74ead52b91030a6abd9695e5a5f175b0758/packages/dev/core/src/Shaders/ShadersInclude/pbrBlockSubSurface.fx#L36

  • 2d refractionSampler 采样基于屏幕空间:
#ifdef SS_REFRACTIONMAP_3D
                , in samplerCube refractionSampler
                #ifndef LODBASEDMICROSFURACE
                    , in samplerCube refractionSamplerLow
                    , in samplerCube refractionSamplerHigh
                #endif
            #else
                , in sampler2D refractionSampler
                #ifndef LODBASEDMICROSFURACE
                    , in sampler2D refractionSamplerLow
                    , in sampler2D refractionSamplerHigh
                #endif
            #endif
  if (this._refractionTexture && StandardMaterial.RefractionTextureEnabled) {
                    if (this._refractionTexture.isCube) {
                        effect.setTexture("refractionCubeSampler", this._refractionTexture);
                    } else {
                        effect.setTexture("refraction2DSampler", this._refractionTexture);
                    }
                }

折射坐标
https://github.com/BabylonJS/Babylon.js/blob/ba1b14818cbcfbc244b96ca2b127544fd19b5c15/packages/dev/core/src/ShadersWGSL/default.fragment.fx#L224

vec3 vRefractionUVW = vec3(refractionMatrix * (view * vec4(vPositionW + refractionVector * vRefractionInfos.z, 1.0)));

		vec2 refractionCoords = vRefractionUVW.xy / vRefractionUVW.z;

		refractionCoords.y = 1.0 - refractionCoords.y;

		refractionColor = texture2D(refraction2DSampler, refractionCoords);

filament

image
image

    // compute the point where the ray exits the medium, if needed
    vec4 p = vec4(getClipFromWorldMatrix() * vec4(ray.position, 1.0));
    p.xy = uvToRenderTargetUV(p.xy * (0.5 / p.w) + 0.5);

UNITY HDRP

https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@8.0/manual/Refraction-in-HDRP.html
unity的内置折射是基于HDRP管线,并且采用屏幕空间计算,需要反射探针配合。

总结

● 优先实现屏幕空间效果,等后续探针功能接入,再考虑cubemap
● 如果按照屏幕空间算法的话,直接调用opaque texture能满足最基本效果

@hhhhkrx hhhhkrx added glTF material Rendering Rendering related functions shader Shader related functions labels Aug 20, 2024
@hhhhkrx hhhhkrx self-assigned this Aug 20, 2024
@GuoLei1990 GuoLei1990 added this to the 1.4 milestone Aug 21, 2024
@zhuxudong
Copy link
Member

@zhuxudong
Copy link
Member

zhuxudong commented Sep 10, 2024

采样立方体贴图的方式会更真实,场景细节会更多,屏幕空间不需要采样立方体贴图,实时高效

现阶段考虑到性能,以及不支持立方体探针,我建议先屏幕空间,Three 的这个效果在移动端上可以接受:https://threejs.org/examples/?q=transmission#webgl_loader_gltf_transmission

@zhuxudong
Copy link
Member

zhuxudong commented Sep 10, 2024

这个pass处理了opaque object和transmissive object

我感觉这个版本都不用特殊加一个 pass,用 OpaqueTexturePass 也能满足;我看 three 那个代码transmission队列只考虑了双面渲染的 case 的时候,先渲染背面再渲染正面,但是抓帧看折射效果,基本上采样 opaque 队列作为折射纹理就能满足视觉效果和性能

image

@zhuxudong
Copy link
Member

zhuxudong commented Sep 10, 2024

管线部分可能需要改造的地方,直接写这里了,到时候一起讨论下:

1. 是否只允许 PBR 才支持 Volume + transmission

2. opaque pass 执行时机更改

把这行本来基于 opaqueTextureEnabled 开关判断:
https://github.com/galacean/engine/blob/main/packages/core/src/RenderPipeline/BasicRenderPipeline.ts#L183

改为开关 + 队列数量判断

if(camera.opaqueTextureEnabled || transmissionQueue.elements.length)

3. RenderQueue 队列新增 Transmission 队列

4. Material 新增属性

  • transmission,改这个会改动 RenderQueue
  • thickness
  • ......

5. 其他

  • 是否需要支持 transmission pass
  • 折射坐标需要其他引擎改动不

@zhuxudong
Copy link
Member

以及需要引擎提供基于折射角度计算的RefractionTexture

这个是从哪里来?需要引擎提供啥

@hhhhkrx
Copy link
Contributor Author

hhhhkrx commented Sep 11, 2024

以及需要引擎提供基于折射角度计算的RefractionTexture

这个是从哪里来?需要引擎提供啥

https://github.com/BabylonJS/Babylon.js/blob/5a96272de06104f2fd793e4a8a6cbd05362623f7/packages/dev/core/src/Materials/Textures/refractionTexture.ts#L7
这里,babylon是做了一次纹理封装,我们是否需要参考。

@hhhhkrx
Copy link
Contributor Author

hhhhkrx commented Sep 11, 2024

采样立方体贴图的方式会更真实,场景细节会更多,屏幕空间不需要采样立方体贴图,实时高效

现阶段考虑到性能,以及不支持立方体探针,我建议先屏幕空间,Three 的这个效果在移动端上可以接受:https://threejs.org/examples/?q=transmission#webgl_loader_gltf_transmission

这个效果我也觉得ok的,可以先屏幕空间,后续等有了探针再加cubemap。

@hhhhkrx
Copy link
Contributor Author

hhhhkrx commented Sep 13, 2024

babylon的 refractionSampler 抓帧显示出来也是 opaqueTexture
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
glTF Rendering Rendering related functions shader Shader related functions
Projects
None yet
Development

No branches or pull requests

3 participants