Point Of Interest light probe blending start of implementation : basic structure, probes selection and blend factor computation.
This commit is contained in:
parent
9fd90ab799
commit
1276dc583e
@ -253,7 +253,7 @@ public class LightProbe extends Light implements Savable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Light Probe : " + position ;
|
||||
return "Light Probe : " + name + " at " + position + " / " + bounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2015 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.light;
|
||||
|
||||
import com.jme3.bounding.BoundingSphere;
|
||||
import com.jme3.post.SceneProcessor;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.RenderQueue;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.texture.FrameBuffer;
|
||||
import com.jme3.util.TempVars;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* this processor allows to blend several light probes maps together according to a Point of Interest.
|
||||
* This is all based on this article by Sebastien lagarde
|
||||
* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
|
||||
* @author Nehon
|
||||
*/
|
||||
public class LightProbeBlendingProcessor implements SceneProcessor {
|
||||
|
||||
private ViewPort viewPort;
|
||||
private LightFilter prevFilter;
|
||||
private RenderManager renderManager;
|
||||
private LightProbe probe = new LightProbe();
|
||||
private Spatial poi;
|
||||
|
||||
public LightProbeBlendingProcessor(Spatial poi) {
|
||||
this.poi = poi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(RenderManager rm, ViewPort vp) {
|
||||
viewPort = vp;
|
||||
renderManager = rm;
|
||||
prevFilter = rm.getLightFilter();
|
||||
rm.setLightFilter(new PoiLightProbeLightFilter(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reshape(ViewPort vp, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return viewPort != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preFrame(float tpf) {
|
||||
|
||||
}
|
||||
|
||||
/** 1. For POI take a spatial in the constructor and make all calculation against its world pos
|
||||
* - Alternatively compute an arbitrary POI by casting rays from the camera
|
||||
* (one in the center and one for each corner and take the median point)
|
||||
* 2. Take the 4 most weighted probes for default. Maybe allow the user to change this
|
||||
* 3. For the inner influence radius take half of the radius for a start we'll see then how to change this.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void postQueue(RenderQueue rq) {
|
||||
List<BlendFactor> blendFactors = new ArrayList<BlendFactor>();
|
||||
float sumBlendFactors = computeBlendFactors(blendFactors);
|
||||
|
||||
//Sort blend factors according to their weight
|
||||
Collections.sort(blendFactors);
|
||||
|
||||
//normalize blend factors;
|
||||
float normalizer = 1f / sumBlendFactors;
|
||||
for (BlendFactor blendFactor : blendFactors) {
|
||||
blendFactor.ndf *= normalizer;
|
||||
// System.err.println(blendFactor);
|
||||
}
|
||||
|
||||
|
||||
//for now just pick the first probe.
|
||||
if(!blendFactors.isEmpty()){
|
||||
probe = blendFactors.get(0).lightProbe;
|
||||
}else{
|
||||
probe = null;
|
||||
}
|
||||
}
|
||||
|
||||
private float computeBlendFactors(List<BlendFactor> blendFactors) {
|
||||
float sumBlendFactors = 0;
|
||||
for (Spatial scene : viewPort.getScenes()) {
|
||||
for (Light light : scene.getWorldLightList()) {
|
||||
if(light.getType() == Light.Type.Probe){
|
||||
LightProbe p = (LightProbe)light;
|
||||
TempVars vars = TempVars.get();
|
||||
boolean intersect = p.intersectsFrustum(viewPort.getCamera(), vars);
|
||||
vars.release();
|
||||
//check if the probe is inside the camera frustum
|
||||
if(intersect){
|
||||
|
||||
//is the poi inside the bounds of this probe
|
||||
if(poi.getWorldBound().intersects(p.getBounds())){
|
||||
|
||||
//computing the distance as we need it to check if th epoi in in the inner radius and later to compute the weight
|
||||
float outerRadius = ((BoundingSphere)p.getBounds()).getRadius();
|
||||
float innerRadius = outerRadius * 0.5f;
|
||||
float distance = p.getBounds().getCenter().distance(poi.getWorldTranslation());
|
||||
|
||||
// if the poi in inside the inner range of this probe, then this probe is the only one that matters.
|
||||
if( distance < innerRadius ){
|
||||
blendFactors.clear();
|
||||
blendFactors.add(new BlendFactor(p, 1.0f));
|
||||
return 1.0f;
|
||||
}
|
||||
//else we need to compute the weight of this probe and collect it for blending
|
||||
float ndf = (distance - innerRadius) / (outerRadius - innerRadius);
|
||||
sumBlendFactors += ndf;
|
||||
blendFactors.add(new BlendFactor(p, ndf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sumBlendFactors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFrame(FrameBuffer out) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
viewPort = null;
|
||||
renderManager.setLightFilter(prevFilter);
|
||||
}
|
||||
|
||||
public void populateProbe(LightList lightList){
|
||||
if(probe != null && probe.isReady()){
|
||||
lightList.add(probe);
|
||||
}
|
||||
}
|
||||
|
||||
public Spatial getPoi() {
|
||||
return poi;
|
||||
}
|
||||
|
||||
public void setPoi(Spatial poi) {
|
||||
this.poi = poi;
|
||||
}
|
||||
|
||||
|
||||
private class BlendFactor implements Comparable<BlendFactor>{
|
||||
|
||||
LightProbe lightProbe;
|
||||
float ndf;
|
||||
|
||||
public BlendFactor(LightProbe lightProbe, float ndf) {
|
||||
this.lightProbe = lightProbe;
|
||||
this.ndf = ndf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlendFactor{" + "lightProbe=" + lightProbe + ", ndf=" + ndf + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BlendFactor o) {
|
||||
if(o.ndf > ndf){
|
||||
return -1;
|
||||
}else if(o.ndf < ndf){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2015 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.light;
|
||||
|
||||
import com.jme3.bounding.BoundingBox;
|
||||
import com.jme3.bounding.BoundingSphere;
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.util.TempVars;
|
||||
import java.util.HashSet;
|
||||
|
||||
public final class PoiLightProbeLightFilter implements LightFilter {
|
||||
|
||||
private Camera camera;
|
||||
private final HashSet<Light> processedLights = new HashSet<Light>();
|
||||
private final LightProbeBlendingProcessor processor;
|
||||
|
||||
public PoiLightProbeLightFilter(LightProbeBlendingProcessor processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCamera(Camera camera) {
|
||||
this.camera = camera;
|
||||
for (Light light : processedLights) {
|
||||
light.frustumCheckNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filterLights(Geometry geometry, LightList filteredLightList) {
|
||||
TempVars vars = TempVars.get();
|
||||
try {
|
||||
LightList worldLights = geometry.getWorldLightList();
|
||||
|
||||
for (int i = 0; i < worldLights.size(); i++) {
|
||||
Light light = worldLights.get(i);
|
||||
|
||||
if (light.getType() == Light.Type.Probe) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (light.frustumCheckNeeded) {
|
||||
processedLights.add(light);
|
||||
light.frustumCheckNeeded = false;
|
||||
light.intersectsFrustum = light.intersectsFrustum(camera, vars);
|
||||
}
|
||||
|
||||
if (!light.intersectsFrustum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BoundingVolume bv = geometry.getWorldBound();
|
||||
|
||||
if (bv instanceof BoundingBox) {
|
||||
if (!light.intersectsBox((BoundingBox) bv, vars)) {
|
||||
continue;
|
||||
}
|
||||
} else if (bv instanceof BoundingSphere) {
|
||||
if (!Float.isInfinite(((BoundingSphere) bv).getRadius())) {
|
||||
if (!light.intersectsSphere((BoundingSphere) bv, vars)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredLightList.add(light);
|
||||
}
|
||||
|
||||
processor.populateProbe(filteredLightList);
|
||||
|
||||
} finally {
|
||||
vars.release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -754,6 +754,15 @@ public class RenderManager {
|
||||
public void setLightFilter(LightFilter lightFilter) {
|
||||
this.lightFilter = lightFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current LightFilter.
|
||||
*
|
||||
* @return the current light filter
|
||||
*/
|
||||
public LightFilter getLightFilter() {
|
||||
return this.lightFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines what light mode will be selected when a technique offers several light modes.
|
||||
|
Loading…
x
Reference in New Issue
Block a user