From b14bb34176e6654a8f331399baeb48de3441ed79 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Sun, 1 Sep 2019 17:35:09 +0200 Subject: [PATCH] Accelerated env baker that runs on the GPU. --- .../jme3/environment/LightProbeFactory2.java | 98 ++++++++++ .../com/jme3/environment/baker/EnvBaker.java | 16 ++ .../environment/baker/GenericEnvBaker.java | 165 ++++++++++++++++ .../jme3/environment/baker/IBLEnvBaker.java | 19 ++ .../environment/baker/IBLEnvBakerLight.java | 17 ++ .../jme3/environment/baker/IBLGLEnvBaker.java | 182 ++++++++++++++++++ .../environment/baker/IBLGLEnvBakerLight.java | 104 ++++++++++ .../main/resources/Common/IBL/IBLKernels.frag | 101 ++++++++++ .../main/resources/Common/IBL/IBLKernels.j3md | 37 ++++ .../main/resources/Common/IBL/IBLKernels.vert | 29 +++ .../main/resources/Common/IBL/Math.glsllib | 66 +++++++ .../jme3test/light/pbr/TestPBRLighting.java | 27 +-- 12 files changed, 850 insertions(+), 11 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/environment/LightProbeFactory2.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/EnvBaker.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBaker.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBakerLight.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java create mode 100644 jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBakerLight.java create mode 100644 jme3-core/src/main/resources/Common/IBL/IBLKernels.frag create mode 100644 jme3-core/src/main/resources/Common/IBL/IBLKernels.j3md create mode 100644 jme3-core/src/main/resources/Common/IBL/IBLKernels.vert create mode 100644 jme3-core/src/main/resources/Common/IBL/Math.glsllib diff --git a/jme3-core/src/main/java/com/jme3/environment/LightProbeFactory2.java b/jme3-core/src/main/java/com/jme3/environment/LightProbeFactory2.java new file mode 100644 index 000000000..543682d6f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/LightProbeFactory2.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009-2019 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.environment; + +import com.jme3.asset.AssetManager; +import com.jme3.environment.baker.IBLGLEnvBakerLight; +import com.jme3.environment.util.EnvMapUtils; +import com.jme3.light.LightProbe; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.texture.Image.Format; + + +public class LightProbeFactory2 { + + + public static LightProbe makeProbe(RenderManager rm, + AssetManager am, int size,Vector3f pos, float frustumNear,float frustumFar,Spatial scene) { + IBLGLEnvBakerLight baker=new IBLGLEnvBakerLight(rm, + am, Format.RGB16F, Format.Depth, + size, size); + + baker.bakeEnvironment(scene,pos, frustumNear,frustumFar); + baker.bakeSpecularIBL(); + baker.bakeSphericalHarmonicsCoefficients(); + + LightProbe probe = new LightProbe(); + + probe.setPosition(pos); + probe.setPrefilteredMap(baker.getSpecularIBL()); + probe.setNbMipMaps(probe.getPrefilteredEnvMap().getImage().getMipMapSizes().length); + probe.setShCoeffs(baker.getSphericalHarmonicsCoefficients()); + probe.setReady(true); + + baker.clean(); + + return probe; + + } + + + + + + /** + * For debuging porpose only + * Will return a Node meant to be added to a GUI presenting the 2 cube maps in a cross pattern with all the mip maps. + * + * @param manager the asset manager + * @return a debug node + */ + public static Node getDebugGui(AssetManager manager, LightProbe probe) { + if (!probe.isReady()) { + throw new UnsupportedOperationException("This EnvProbe is not ready yet, try to test isReady()"); + } + + Node debugNode = new Node("debug gui probe"); + Node debugPfemCm = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(probe.getPrefilteredEnvMap(), manager); + debugNode.attachChild(debugPfemCm); + debugPfemCm.setLocalTranslation(520, 0, 0); + + return debugNode; + } + + + +} diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/EnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/EnvBaker.java new file mode 100644 index 000000000..5b73b6824 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/baker/EnvBaker.java @@ -0,0 +1,16 @@ +package com.jme3.environment.baker; + +import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; +import com.jme3.texture.TextureCubeMap; + +/** + * And environment baker. It bakes the environment. ( ͡° ͜ʖ ͡°) + * + * @author Riccardo Balbo + */ +public interface EnvBaker { + public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear, float frustumFar); + public TextureCubeMap getEnvMap(); + public void clean(); +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java new file mode 100644 index 000000000..096a66d14 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/baker/GenericEnvBaker.java @@ -0,0 +1,165 @@ +package com.jme3.environment.baker; + +import java.io.FileOutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; + +import com.jme3.asset.AssetManager; +import com.jme3.environment.baker.EnvBaker; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Spatial; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture.MagFilter; +import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.TextureCubeMap; +import com.jme3.texture.image.ColorSpace; +import com.jme3.util.BufferUtils; + + +/** + * Render the environment into a cubemap + * + * @author Riccardo Balbo + */ +public abstract class GenericEnvBaker implements EnvBaker{ + + protected static Vector3f[] axisX=new Vector3f[6]; + protected static Vector3f[] axisY=new Vector3f[6]; + protected static Vector3f[] axisZ=new Vector3f[6]; + static{ + //PositiveX axis(left, up, direction) + axisX[0]=Vector3f.UNIT_Z.mult(1.0F); + axisY[0]=Vector3f.UNIT_Y.mult(-1.0F); + axisZ[0]=Vector3f.UNIT_X.mult(1.0F); + //NegativeX + axisX[1]=Vector3f.UNIT_Z.mult(-1.0F); + axisY[1]=Vector3f.UNIT_Y.mult(-1.0F); + axisZ[1]=Vector3f.UNIT_X.mult(-1.0F); + //PositiveY + axisX[2]=Vector3f.UNIT_X.mult(-1.0F); + axisY[2]=Vector3f.UNIT_Z.mult(1.0F); + axisZ[2]=Vector3f.UNIT_Y.mult(1.0F); + //NegativeY + axisX[3]=Vector3f.UNIT_X.mult(-1.0F); + axisY[3]=Vector3f.UNIT_Z.mult(-1.0F); + axisZ[3]=Vector3f.UNIT_Y.mult(-1.0F); + //PositiveZ + axisX[4]=Vector3f.UNIT_X.mult(-1.0F); + axisY[4]=Vector3f.UNIT_Y.mult(-1.0F); + axisZ[4]=Vector3f.UNIT_Z; + //NegativeZ + axisX[5]=Vector3f.UNIT_X.mult(1.0F); + axisY[5]=Vector3f.UNIT_Y.mult(-1.0F); + axisZ[5]=Vector3f.UNIT_Z.mult(-1.0F); + } + + protected TextureCubeMap env; + protected Format depthFormat; + + + protected final RenderManager renderManager; + protected final AssetManager assetManager; + protected final Camera cam; + protected final boolean copyToRam; + + + public GenericEnvBaker( + RenderManager rm, + AssetManager am, + Format colorFormat, + Format depthFormat, + int env_size, + boolean copyToRam + ){ + this.copyToRam=copyToRam; + this.depthFormat=depthFormat; + + renderManager=rm; + assetManager=am; + + + cam=new Camera(128,128); + + env=new TextureCubeMap(env_size,env_size,colorFormat); + env.setMagFilter(MagFilter.Bilinear); + env.setMinFilter(MinFilter.BilinearNoMipMaps); + env.setWrap(WrapMode.EdgeClamp); + env.getImage().setColorSpace(ColorSpace.Linear); + } + + public TextureCubeMap getEnvMap(){ + return env; + } + + Camera getCam(int id,int w,int h,Vector3f position,float frustumNear,float frustumFar){ + cam.resize(w,h,false); + cam.setLocation(position); + cam.setFrustumPerspective(90.0F,1F,frustumNear,frustumFar); + cam.setRotation(new Quaternion().fromAxes(axisX[id],axisY[id],axisZ[id])); + return cam; + } + + @Override + public void clean(){ + env.getImage().dispose(); + System.gc(); + System.gc(); + } + + + @Override + public void bakeEnvironment(Spatial scene, Vector3f position, float frustumNear, float frustumFar) { + FrameBuffer envbaker=new FrameBuffer(env.getImage().getWidth(),env.getImage().getHeight(),1); + envbaker.setDepthTarget(FrameBuffer.newTarget(depthFormat)); + envbaker.setSrgb(false); + + for(int i=0;i<6;i++) envbaker.addColorTarget(FrameBuffer.newTarget(env).face(TextureCubeMap.Face.values()[i])); + + for(int i=0;i<6;i++){ + envbaker.setTargetIndex(i); + + ViewPort viewPort=new ViewPort("EnvBaker",getCam(i,envbaker.getWidth(),envbaker.getHeight(),position,frustumNear,frustumFar)); + viewPort.setClearFlags(true,true,true); + viewPort.setBackgroundColor(ColorRGBA.Pink); + + viewPort.setOutputFrameBuffer(envbaker); + viewPort.clearScenes(); + viewPort.attachScene(scene); + + scene.updateLogicalState(0); + scene.updateModelBound(); + scene.updateGeometricState(); + + renderManager.renderViewPort(viewPort,0.16f); + + if(copyToRam){ + ByteBuffer face=BufferUtils.createByteBuffer( + ( + env.getImage().getWidth()*env.getImage().getHeight()*( + env.getImage().getFormat().getBitsPerPixel()/8 + ) + ) + ); + renderManager.getRenderer().readFrameBufferWithFormat(envbaker, face,env.getImage().getFormat()); + face.rewind(); + env.getImage().setData(i,face); + + } + } + + env.getImage().clearUpdateNeeded(); + + envbaker.dispose(); + } + + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBaker.java new file mode 100644 index 000000000..cef731dcd --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBaker.java @@ -0,0 +1,19 @@ +package com.jme3.environment.baker; + +import com.jme3.texture.Texture2D; +import com.jme3.texture.TextureCubeMap; + +/** + * An environment baker, but this one is for Imaged Base Lighting + * + * @author Riccardo Balbo + */ +public interface IBLEnvBaker extends EnvBaker{ + public Texture2D genBRTF() ; + + public void bakeIrradiance(); + public void bakeSpecularIBL() ; + + public TextureCubeMap getSpecularIBL(); + public TextureCubeMap getIrradiance(); +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBakerLight.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBakerLight.java new file mode 100644 index 000000000..794971430 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLEnvBakerLight.java @@ -0,0 +1,17 @@ +package com.jme3.environment.baker; + +import com.jme3.math.Vector3f; +import com.jme3.texture.TextureCubeMap; + +/** + * An environment baker for IBL, that uses spherical harmonics for irradiance. + * + * @author Riccardo Balbo + */ +public interface IBLEnvBakerLight extends EnvBaker{ + public void bakeSpecularIBL(); + public void bakeSphericalHarmonicsCoefficients(); + + public TextureCubeMap getSpecularIBL(); + public Vector3f[] getSphericalHarmonicsCoefficients(); +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java new file mode 100644 index 000000000..83de93808 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/environment/baker/IBLGLEnvBaker.java @@ -0,0 +1,182 @@ +package com.jme3.environment.baker; + +import com.jme3.asset.AssetManager; +import com.jme3.environment.baker.IBLEnvBaker; +import com.jme3.material.Material; +import com.jme3.math.FastMath; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; +import com.jme3.texture.FrameBuffer; +import com.jme3.texture.Image.Format; +import com.jme3.texture.Texture.MagFilter; +import com.jme3.texture.Texture.MinFilter; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.Texture2D; +import com.jme3.texture.TextureCubeMap; +import com.jme3.texture.image.ColorSpace; +import com.jme3.ui.Picture; + + +/** + * An env baker for IBL that runs on the GPU + * + * @author Riccardo Balbo + */ +public class IBLGLEnvBaker extends GenericEnvBaker implements IBLEnvBaker{ + protected Texture2D brtf; + protected TextureCubeMap irradiance; + protected TextureCubeMap specular; + + public IBLGLEnvBaker(RenderManager rm,AssetManager am, + Format format, + Format depthFormat, + int env_size,int specular_size, + int irradiance_size, + int brtf_size + ){ + super(rm,am,format,depthFormat,env_size,false); + + irradiance=new TextureCubeMap(irradiance_size,irradiance_size,format); + irradiance.setMagFilter(MagFilter.Bilinear); + irradiance.setMinFilter(MinFilter.BilinearNoMipMaps); + irradiance.setWrap(WrapMode.EdgeClamp); + irradiance.getImage().setColorSpace(ColorSpace.Linear); + + specular=new TextureCubeMap(specular_size,specular_size,format); + specular.setMagFilter(MagFilter.Bilinear); + specular.setMinFilter(MinFilter.BilinearNoMipMaps); + specular.setWrap(WrapMode.EdgeClamp); + specular.getImage().setColorSpace(ColorSpace.Linear); + int nbMipMaps=(int)(Math.log(specular_size)/Math.log(2)+1); + if(nbMipMaps>6)nbMipMaps=6; + int[] sizes=new int[nbMipMaps]; + for(int i=0;i6)nbMipMaps=6; + int[] sizes=new int[nbMipMaps]; + for(int i=0;i 0.0){ + float G = GeometrySmith(N, V, L, m_Roughness); + float G_Vis = (G * VdotH) / (NdotH * NdotV); + float Fc = pow(1.0 - VdotH, 5.0); + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + A /= float(SAMPLE_COUNT); + B /= float(SAMPLE_COUNT); + outFragColor.rg=vec2(A, B); + outFragColor.ba=vec2(0); +} + +void irradianceKernel(){ + // the sample direction equals the hemisphere's orientation + vec3 N = normalize(LocalPos); + vec3 irradiance = vec3(0.0); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = cross(up, N); + up = cross(N, right); + float sampleDelta = 0.025; + float nrSamples = 0.0; + for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta){ + for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta){ + // spherical to cartesian (in tangent space) + vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); + // tangent space to world + vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; + irradiance += texture(m_EnvMap, sampleVec).rgb * cos(theta) * sin(theta); + nrSamples++; + } + } + irradiance = PI * irradiance * (1.0 / float(nrSamples)); + outFragColor = vec4(irradiance, 1.0); +} + +void prefilteredEnvKernel(){ + vec3 N = normalize(LocalPos); + vec3 R = N; + vec3 V = R; + const uint SAMPLE_COUNT = 1024u; + float totalWeight = 0.0; + vec3 prefilteredColor = vec3(0.0); + for(uint i = 0u; i < SAMPLE_COUNT; ++i) { + vec2 Xi = Hammersley(i, SAMPLE_COUNT); + vec3 H = ImportanceSampleGGX(Xi, N, m_Roughness); + vec3 L = normalize(2.0 * dot(V, H) * H - V); + float NdotL = max(dot(N, L), 0.0); + if(NdotL > 0.0) { + prefilteredColor += texture(m_EnvMap, L).rgb * NdotL; + totalWeight += NdotL; + } + } + prefilteredColor = prefilteredColor / totalWeight; + outFragColor = vec4(prefilteredColor, 1.0); +} + +void main(){ + #if defined(SIBL) + prefilteredEnvKernel(); + #elif defined(IRRADIANCE) + irradianceKernel(); + #else + brdfKernel(); + #endif +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/IBL/IBLKernels.j3md b/jme3-core/src/main/resources/Common/IBL/IBLKernels.j3md new file mode 100644 index 000000000..257fde915 --- /dev/null +++ b/jme3-core/src/main/resources/Common/IBL/IBLKernels.j3md @@ -0,0 +1,37 @@ +MaterialDef IBLKernels { + + MaterialParameters { + TextureCubeMap EnvMap -LINEAR + Float Roughness + Int FaceId : 0 + Boolean UseBRDF + Boolean UseIrradiance + Boolean UseSpecularIBL + } + + Technique { + + VertexShader GLSL150: Common/IBL/IBLKernels.vert + FragmentShader GLSL150: Common/IBL/IBLKernels.frag + + WorldParameters { + WorldMatrix + ViewMatrix + ProjectionMatrix + } + + RenderState { + DepthWrite Off + DepthTest Off + DepthFunc Equal + FaceCull Off + } + + Defines { + BRDF:UseBRDF + IRRADIANCE: UseIrradiance + SIBL: UseSpecularIBL + } + + } +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/IBL/IBLKernels.vert b/jme3-core/src/main/resources/Common/IBL/IBLKernels.vert new file mode 100644 index 000000000..6bd259971 --- /dev/null +++ b/jme3-core/src/main/resources/Common/IBL/IBLKernels.vert @@ -0,0 +1,29 @@ +/** +* This code is based on the following articles: +* https://learnopengl.com/PBR/IBL/Diffuse-irradiance +* https://learnopengl.com/PBR/IBL/Specular-IBL +* - Riccardo Balbo +*/ +in vec3 inPosition; +in vec2 inTexCoord; +in vec3 inNormal; + +out vec2 TexCoords; +out vec3 LocalPos; + +uniform mat4 g_ViewMatrix; +uniform mat4 g_WorldMatrix; +uniform mat4 g_ProjectionMatrix; + +void main() { + LocalPos = inPosition.xyz; + TexCoords = inTexCoord.xy; + #ifdef BRDF + vec2 pos = inPosition.xy * 2.0 - 1.0; + gl_Position = vec4(pos, 0.0, 1.0); + #else + mat4 rotView = mat4(mat3(g_ViewMatrix)); // remove translation from the view matrix + vec4 clipPos = g_ProjectionMatrix * rotView * vec4(LocalPos, 1.0); + gl_Position = clipPos.xyww; + #endif +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/IBL/Math.glsllib b/jme3-core/src/main/resources/Common/IBL/Math.glsllib new file mode 100644 index 000000000..abc4190af --- /dev/null +++ b/jme3-core/src/main/resources/Common/IBL/Math.glsllib @@ -0,0 +1,66 @@ +/** +* This code is based on the following articles: +* https://learnopengl.com/PBR/IBL/Diffuse-irradiance +* https://learnopengl.com/PBR/IBL/Specular-IBL +* - Riccardo Balbo +*/ +const float PI = 3.14159265359; + +float RadicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N){ + return vec2(float(i)/float(N), RadicalInverse_VdC(i)); +} + + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){ + float a = roughness*roughness; + + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // from spherical coordinates to cartesian coordinates + vec3 H; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // from tangent-space vector to world-space sample vector + vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + + vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; + return normalize(sampleVec); +} + + + + +float GeometrySchlickGGX(float NdotV, float roughness){ + float a = roughness; + float k = (a * a) / 2.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} +// ---------------------------------------------------------------------------- +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness){ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java b/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java index d08f57fb6..8de8c0381 100644 --- a/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java +++ b/jme3-examples/src/main/java/jme3test/light/pbr/TestPBRLighting.java @@ -34,6 +34,7 @@ package jme3test.light.pbr; import com.jme3.app.SimpleApplication; import com.jme3.environment.EnvironmentCamera; import com.jme3.environment.LightProbeFactory; +import com.jme3.environment.LightProbeFactory2; import com.jme3.environment.generation.JobProgressAdapter; import com.jme3.environment.util.EnvMapUtils; import com.jme3.environment.util.LightsDebugState; @@ -59,7 +60,8 @@ import com.jme3.util.mikktspace.MikktspaceTangentGenerator; * @author nehon */ public class TestPBRLighting extends SimpleApplication { - + private static final boolean USE_ACCELERATED_BAKING=true; + private static final int RESOLUTION=256; public static void main(String[] args) { TestPBRLighting app = new TestPBRLighting(); app.start(); @@ -107,7 +109,7 @@ public class TestPBRLighting extends SimpleApplication { model.setMaterial(pbrMat); - final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0)); + final EnvironmentCamera envCam = new EnvironmentCamera(RESOLUTION, new Vector3f(0, 3f, 0)); stateManager.attach(envCam); // EnvironmentManager envManager = new EnvironmentManager(); @@ -195,18 +197,21 @@ public class TestPBRLighting extends SimpleApplication { if (frame == 2) { modelNode.removeFromParent(); - final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() { - - @Override - public void done(LightProbe result) { - System.err.println("Done rendering env maps"); - tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); - } - }); + LightProbe probe; + if(USE_ACCELERATED_BAKING){ + probe= LightProbeFactory2.makeProbe(renderManager, assetManager, RESOLUTION, Vector3f.ZERO, 1f, 1000f, rootNode); + }else{ + probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() { + @Override + public void done(LightProbe result) { + System.err.println("Done rendering env maps"); + tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); + } + }); + } ((SphereProbeArea) probe.getArea()).setRadius(100); rootNode.addLight(probe); //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe); - } if (frame > 10 && modelNode.getParent() == null) { rootNode.attachChild(modelNode);