javafx.scene.PointLight Maven / Gradle / Ivy
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene;
import com.sun.javafx.scene.DirtyBits;
import com.sun.javafx.scene.PointLightHelper;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.sg.prism.NGPointLight;
import javafx.beans.property.DoubleProperty;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
/**
* A light source that radiates light equally in all directions away from itself. The location of the light
* source is a single point in space. Any pixel within the range of the light will be illuminated by it,
* unless it belongs to a {@code Shape3D} outside of its {@code scope}.
*
* The light's intensity can be set to decrease over distance by attenuating it. The attenuation formula
*
* {@code attn = 1 / (ca + la * dist + qa * dist^2)}
*
* defines 3 coefficients: {@code ca}, {@code la}, and {@code qa}, which control the constant, linear, and
* quadratic behaviors of intensity falloff over distance, respectively. The effective color of the light
* at a given point in space is {@code color * attn}. It is possible, albeit unrealistic, to specify negative
* values to attenuation coefficients. This allows the resulting attenuation factor to be negative, which
* results in the light's color being subtracted from the material instead of added to it, thus creating a
* "shadow caster".
*
* For a realistic effect, {@code maxRange} should be set to a distance at which the attenuation is close to 0
* as this will give a soft cutoff.
*
* @since JavaFX 8.0
* @see PhongMaterial
*/
public class PointLight extends LightBase {
static {
PointLightHelper.setPointLightAccessor(new PointLightHelper.PointLightAccessor() {
@Override
public NGNode doCreatePeer(Node node) {
return ((PointLight) node).doCreatePeer();
}
@Override
public void doUpdatePeer(Node node) {
((PointLight) node).doUpdatePeer();
}
});
}
{
// To initialize the class helper at the beginning each constructor of this class
PointLightHelper.initHelper(this);
}
/**
* Creates a new instance of {@code PointLight} class with a default {@code Color.WHITE} light source.
*/
public PointLight() {
super();
}
/**
* Creates a new instance of {@code PointLight} class using the specified color.
*
* @param color the color of the light source
*/
public PointLight(Color color) {
super(color);
}
/**
* The maximum range of this {@code PointLight}. For a pixel to be affected by this light, its distance to the
* light source must be less than or equal to the light's maximum range. Any negative value will be treated as 0.
*
* Lower {@code maxRange} values can give better performance as pixels outside the range of the light
* will not require complex calculation. The attenuation formula can be used to calculate a realistic
* {@code maxRange} value by finding the distance where the attenuation is close enough to 0.
*
* Nodes that are inside the light's range can still be excluded from the light's effect by removing them from
* its {@link #getScope() scope} (or including them in its {@link #getExclusionScope() exclusion scope}). If a
* node is known to always be outside of the light's range, it is more performant to exclude it from its scope.
*
* @defaultValue {@code Double.POSITIVE_INFINITY}
* @since 16
*/
private DoubleProperty maxRange;
public final void setMaxRange(double value) {
maxRangeProperty().set(value);
}
private static final double DEFAULT_MAX_RANGE = NGPointLight.getDefaultMaxRange();
public final double getMaxRange() {
return maxRange == null ? DEFAULT_MAX_RANGE : maxRange.get();
}
public final DoubleProperty maxRangeProperty() {
if (maxRange == null) {
maxRange = getLightDoubleProperty("maxRange", DEFAULT_MAX_RANGE);
}
return maxRange;
}
/**
* The constant attenuation coefficient. This is the term {@code ca} in the attenuation formula:
*
* {@code attn = 1 / (ca + la * dist + qa * dist^2)}
*
* where {@code dist} is the distance between the light source and the pixel.
*
* @defaultValue 1
* @since 16
*/
private DoubleProperty constantAttenuation;
public final void setConstantAttenuation(double value) {
constantAttenuationProperty().set(value);
}
private static final double DEFAULT_CONSTANT_ATTENUATION = NGPointLight.getDefaultCa();
public final double getConstantAttenuation() {
return constantAttenuation == null ? DEFAULT_CONSTANT_ATTENUATION : constantAttenuation.get();
}
public final DoubleProperty constantAttenuationProperty() {
if (constantAttenuation == null) {
constantAttenuation = getLightDoubleProperty("constantAttenuation", DEFAULT_CONSTANT_ATTENUATION);
}
return constantAttenuation;
}
/**
* The linear attenuation coefficient. This is the term {@code la} in the attenuation formula:
*
* {@code attn = 1 / (ca + la * dist + qa * dist^2)}
*
* where {@code dist} is the distance between the light source and the pixel.
*
* @defaultValue 0
* @since 16
*/
private DoubleProperty linearAttenuation;
public final void setLinearAttenuation(double value) {
linearAttenuationProperty().set(value);
}
private static final double DEFAULT_LINEAR_ATTENUATION = NGPointLight.getDefaultLa();
public final double getLinearAttenuation() {
return linearAttenuation == null ? DEFAULT_LINEAR_ATTENUATION : linearAttenuation.get();
}
public final DoubleProperty linearAttenuationProperty() {
if (linearAttenuation == null) {
linearAttenuation = getLightDoubleProperty("linearAttenuation", DEFAULT_LINEAR_ATTENUATION);
}
return linearAttenuation;
}
/**
* The quadratic attenuation coefficient. This is the term {@code qa} in the attenuation formula:
*
* {@code attn = 1 / (ca + la * dist + qa * dist^2)}
*
* where {@code dist} is the distance between the light source and the pixel.
*
* @defaultValue 0
* @since 16
*/
private DoubleProperty quadraticAttenuation;
public final void setQuadraticAttenuation(double value) {
quadraticAttenuationProperty().set(value);
}
private static final double DEFAULT_QUADRATIC_ATTENUATION = NGPointLight.getDefaultQa();
public final double getQuadraticAttenuation() {
return quadraticAttenuation == null ? DEFAULT_QUADRATIC_ATTENUATION : quadraticAttenuation.get();
}
public final DoubleProperty quadraticAttenuationProperty() {
if (quadraticAttenuation == null) {
quadraticAttenuation = getLightDoubleProperty("quadraticAttenuation", DEFAULT_QUADRATIC_ATTENUATION);
}
return quadraticAttenuation;
}
/*
* Note: This method MUST only be called via its accessor method.
*/
private NGNode doCreatePeer() {
return new NGPointLight();
}
private void doUpdatePeer() {
if (isDirty(DirtyBits.NODE_LIGHT)) {
NGPointLight peer = getPeer();
peer.setCa((float) getConstantAttenuation());
peer.setLa((float) getLinearAttenuation());
peer.setQa((float) getQuadraticAttenuation());
peer.setMaxRange((float) getMaxRange());
}
}
}