Skip to content
Permalink
Browse files
8234920: Add SpotLight to the selection of 3D light types
Reviewed-by: kcr, arapte
  • Loading branch information
nlisker committed Jun 24, 2021
1 parent 063bfe8 commit 3fd4c97ff22b9970f13b612209dbcdfe16eaed8c
Showing with 1,678 additions and 439 deletions.
  1. BIN modules/javafx.graphics/src/main/docs/javafx/scene/doc-files/spotlight.png
  2. +77 −0 modules/javafx.graphics/src/main/java/com/sun/javafx/scene/SpotLightHelper.java
  3. +46 −0 modules/javafx.graphics/src/main/java/com/sun/javafx/sg/prism/NGPointLight.java
  4. +81 −66 modules/javafx.graphics/src/main/java/com/sun/javafx/sg/prism/NGShape3D.java
  5. +129 −0 modules/javafx.graphics/src/main/java/com/sun/javafx/sg/prism/NGSpotLight.java
  6. +3 −4 modules/javafx.graphics/src/main/java/com/sun/prism/MeshView.java
  7. +8 −6 modules/javafx.graphics/src/main/java/com/sun/prism/d3d/D3DContext.java
  8. +5 −3 modules/javafx.graphics/src/main/java/com/sun/prism/d3d/D3DMeshView.java
  9. +5 −3 modules/javafx.graphics/src/main/java/com/sun/prism/es2/ES2Context.java
  10. +21 −8 modules/javafx.graphics/src/main/java/com/sun/prism/es2/ES2Light.java
  11. +8 −5 modules/javafx.graphics/src/main/java/com/sun/prism/es2/ES2MeshView.java
  12. +29 −8 modules/javafx.graphics/src/main/java/com/sun/prism/es2/ES2PhongShader.java
  13. +8 −6 modules/javafx.graphics/src/main/java/com/sun/prism/es2/GLContext.java
  14. +251 −0 modules/javafx.graphics/src/main/java/javafx/scene/SpotLight.java
  15. +7 −6 modules/javafx.graphics/src/main/native-prism-d3d/D3DContext.cc
  16. +14 −13 modules/javafx.graphics/src/main/native-prism-d3d/D3DLight.cc
  17. +7 −3 modules/javafx.graphics/src/main/native-prism-d3d/D3DLight.h
  18. +86 −29 modules/javafx.graphics/src/main/native-prism-d3d/D3DMeshView.cc
  19. +7 −4 modules/javafx.graphics/src/main/native-prism-d3d/D3DMeshView.h
  20. +32 −20 modules/javafx.graphics/src/main/native-prism-d3d/D3DPhongShader.h
  21. +1 −1 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/Mtl1PS.hlsl
  22. +6 −5 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/psConstants.h
  23. +69 −15 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/psMath.h
  24. +6 −6 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/vs2ps.h
  25. +11 −8 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/vsConstants.h
  26. +5 −5 modules/javafx.graphics/src/main/native-prism-d3d/hlsl/vsMath.h
  27. +41 −28 modules/javafx.graphics/src/main/native-prism-es2/GLContext.c
  28. +10 −6 modules/javafx.graphics/src/main/native-prism-es2/PrismES2Defs.h
  29. +14 −0 modules/javafx.graphics/src/main/resources/com/sun/prism/es2/glsl/main.vert
  30. +72 −12 modules/javafx.graphics/src/main/resources/com/sun/prism/es2/glsl/main1Light.frag
  31. +69 −16 modules/javafx.graphics/src/main/resources/com/sun/prism/es2/glsl/main2Lights.frag
  32. +70 −26 modules/javafx.graphics/src/main/resources/com/sun/prism/es2/glsl/main3Lights.frag
  33. +56 −9 tests/performance/3DLighting/attenuation/AttenLightingSample.java
  34. +8 −1 tests/performance/3DLighting/attenuation/CameraScene3D.java
  35. +45 −14 tests/performance/3DLighting/attenuation/Environment.java
  36. +2 −2 tests/performance/3DLighting/attenuation/FPSCounter.java
  37. +88 −28 tests/performance/3DLighting/attenuation/LightingSample.java
  38. +101 −0 tests/system/src/test/java/test/javafx/scene/lighting3D/LightingTest.java
  39. +63 −73 tests/system/src/test/java/test/javafx/scene/lighting3D/PointLightAttenuationTest.java
  40. +117 −0 tests/system/src/test/java/test/javafx/scene/lighting3D/SpotLightAttenuationTest.java
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,77 @@
/*
* Copyright (c) 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 com.sun.javafx.scene;

import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.util.Utils;
import javafx.scene.SpotLight;
import javafx.scene.Node;

/**
* Used to access internal methods of SpotLight.
*/
public class SpotLightHelper extends PointLightHelper {

private static final SpotLightHelper theInstance;
private static SpotLightAccessor spotLightAccessor;

static {
theInstance = new SpotLightHelper();
Utils.forceInit(SpotLight.class);
}

private static SpotLightHelper getInstance() {
return theInstance;
}

public static void initHelper(SpotLight spotLight) {
setHelper(spotLight, getInstance());
}

@Override
protected NGNode createPeerImpl(Node node) {
return spotLightAccessor.doCreatePeer(node);
}

@Override
protected void updatePeerImpl(Node node) {
super.updatePeerImpl(node);
spotLightAccessor.doUpdatePeer(node);
}

public static void setSpotLightAccessor(final SpotLightAccessor newAccessor) {
if (spotLightAccessor != null) {
throw new IllegalStateException("Accessor already exists");
}

spotLightAccessor = newAccessor;
}

public interface SpotLightAccessor {
NGNode doCreatePeer(Node node);
void doUpdatePeer(Node node);
}
}
@@ -25,6 +25,8 @@

package com.sun.javafx.sg.prism;

import javafx.geometry.Point3D;

/**
* The peer of the {@code PointLight} class. Holds the default values of {@code PointLight}'s
* properties and updates the visuals via {@link NGNode#visualsChanged} when one of the current
@@ -41,6 +43,18 @@
/** Max range default value */
private static final float DEFAULT_MAX_RANGE = Float.POSITIVE_INFINITY;

/**
* The direction of a {@code SpotLight} that simulates a {@code PointLight}.
* Since the light radiates equally in all directions, this value is meaningless.
**/
private static final Point3D SIMULATED_DIRECTION = new Point3D(0, 0, 1);
/** The inner angle value of a {@code SpotLight} that simulates a {@code PointLight} */
private static final float SIMULATED_INNER_ANGLE = 0;
/** The outer angle value of a {@code SpotLight} that simulates a {@code PointLight} */
private static final float SIMULATED_OUTER_ANGLE = 180;
/** The falloff value of a {@code SpotLight} that simulates a {@code PointLight} */
private static final float SIMULATED_FALLOFF = 0;

public NGPointLight() {
}

@@ -60,6 +74,38 @@ public static float getDefaultMaxRange() {
return DEFAULT_MAX_RANGE;
}

public static Point3D getSimulatedDirection() {
return SIMULATED_DIRECTION;
}

public static float getSimulatedInnerAngle() {
return SIMULATED_INNER_ANGLE;
}

public static float getSimulatedOuterAngle() {
return SIMULATED_OUTER_ANGLE;
}

public static float getSimulatedFalloff() {
return SIMULATED_FALLOFF;
}

public Point3D getDirection() {
return SIMULATED_DIRECTION;
}

public float getInnerAngle() {
return SIMULATED_INNER_ANGLE;
}

public float getOuterAngle() {
return SIMULATED_OUTER_ANGLE;
}

public float getFalloff() {
return SIMULATED_FALLOFF;
}


private float ca = DEFAULT_CA;

@@ -31,6 +31,7 @@
import javafx.scene.shape.DrawMode;
import com.sun.javafx.geom.Vec3d;
import com.sun.javafx.geom.transform.Affine3D;
import com.sun.javafx.util.Utils;
import com.sun.prism.Graphics;
import com.sun.prism.Material;
import com.sun.prism.MeshView;
@@ -115,95 +116,109 @@ private void renderMeshView(Graphics g) {
}

// Setup lights
int pointLightIdx = 0;
int lightIndex = 0;
if (g.getLights() == null || g.getLights()[0] == null) {
// If no lights are in scene apply default light. Default light
// is a single white point light at camera eye position.
meshView.setAmbientLight(0.0f, 0.0f, 0.0f);
Vec3d cameraPos = g.getCameraNoClone().getPositionInWorld(null);
meshView.setPointLight(pointLightIdx++,
(float)cameraPos.x,
(float)cameraPos.y,
(float)cameraPos.z,
1.0f, 1.0f, 1.0f, 1.0f,
NGPointLight.getDefaultCa(),
NGPointLight.getDefaultLa(),
NGPointLight.getDefaultQa(),
NGPointLight.getDefaultMaxRange());
meshView.setLight(lightIndex++,
(float) cameraPos.x,
(float) cameraPos.y,
(float) cameraPos.z,
1.0f, 1.0f, 1.0f, 1.0f,
NGPointLight.getDefaultCa(),
NGPointLight.getDefaultLa(),
NGPointLight.getDefaultQa(),
NGPointLight.getDefaultMaxRange(),
(float) NGPointLight.getSimulatedDirection().getX(),
(float) NGPointLight.getSimulatedDirection().getY(),
(float) NGPointLight.getSimulatedDirection().getZ(),
NGPointLight.getSimulatedInnerAngle(),
NGPointLight.getSimulatedOuterAngle(),
NGPointLight.getSimulatedFalloff());
} else {
float ambientRed = 0.0f;
float ambientBlue = 0.0f;
float ambientGreen = 0.0f;

for (int i = 0; i < g.getLights().length; i++) {
NGLightBase lightBase = g.getLights()[i];
for (NGLightBase lightBase : g.getLights()) {
if (lightBase == null) {
// The array of lights can have nulls
break;
} else if (lightBase.affects(this)) {
float rL = lightBase.getColor().getRed();
float gL = lightBase.getColor().getGreen();
float bL = lightBase.getColor().getBlue();
/* TODO: 3D
* There is a limit on the number of point lights that can affect
* a 3D shape. (Currently we simply select the first 3)
* Thus it is important to select the most relevant lights.
*
* One such way would be to sort lights according to
* intensity, which becomes especially relevant when lights
* are attenuated. Only the most intense set of lights
* would be set.
* The approximate intesity a light will have on a given
* shape, could be defined by:
*/
// // Where d is distance from point light
// float attenuationFactor = 1/(c + cL * d + cQ * d * d);
// float intensity = rL * 0.299f + gL * 0.587f + bL * 0.114f;
// intensity *= attenuationFactor;
if (lightBase instanceof NGPointLight) {
NGPointLight light = (NGPointLight)lightBase;
if (rL != 0.0f || gL != 0.0f || bL != 0.0f) {
Affine3D lightWT = light.getWorldTransform();
meshView.setPointLight(pointLightIdx++,
(float)lightWT.getMxt(),
(float)lightWT.getMyt(),
(float)lightWT.getMzt(),
rL, gL, bL, 1.0f,
light.getCa(),
light.getLa(),
light.getQa(),
light.getMaxRange());
}
} else if (lightBase instanceof NGAmbientLight) {
// Accumulate ambient lights
ambientRed += rL;
ambientGreen += gL;
ambientBlue += bL;
}
}
if (!lightBase.affects(this)) {
continue;
}
// Transparent component is ignored
float rL = lightBase.getColor().getRed();
float gL = lightBase.getColor().getGreen();
float bL = lightBase.getColor().getBlue();
// Black color is ignored
if (rL == 0.0f && gL == 0.0f && bL == 0.0f) {
continue;
}
/* TODO: 3D
* There is a limit on the number of point lights that can affect
* a 3D shape. (Currently we simply select the first 3)
* Thus it is important to select the most relevant lights.
*
* One such way would be to sort lights according to
* intensity, which becomes especially relevant when lights
* are attenuated. Only the most intense set of lights
* would be set.
* The approximate intensity a light will have on a given
* shape, could be defined by:
*
* Where d is distance from point light
* float attenuationFactor = 1/(c + cL * d + cQ * d * d);
* float intensity = rL * 0.299f + gL * 0.587f + bL * 0.114f;
* intensity *= attenuationFactor;
*/
if (lightBase instanceof NGPointLight) {
var light = (NGPointLight) lightBase;
Affine3D lightWT = light.getWorldTransform();
meshView.setLight(lightIndex++,
(float) lightWT.getMxt(),
(float) lightWT.getMyt(),
(float) lightWT.getMzt(),
rL, gL, bL, 1.0f,
light.getCa(),
light.getLa(),
light.getQa(),
light.getMaxRange(),
(float) light.getDirection().getX(),
(float) light.getDirection().getY(),
(float) light.getDirection().getZ(),
light.getInnerAngle(),
light.getOuterAngle(),
light.getFalloff());
} else if (lightBase instanceof NGAmbientLight) {
// Accumulate ambient lights
ambientRed += rL;
ambientGreen += gL;
ambientBlue += bL;
}
}
ambientRed = saturate(ambientRed);
ambientGreen = saturate(ambientGreen);
ambientBlue = saturate(ambientBlue);
ambientRed = Utils.clamp(0, ambientRed, 1);
ambientGreen = Utils.clamp(0, ambientGreen, 1);
ambientBlue = Utils.clamp(0, ambientBlue, 1);
meshView.setAmbientLight(ambientRed, ambientGreen, ambientBlue);
}
// TODO: 3D Required for D3D implementation of lights, which is limited to 3
while (pointLightIdx < 3) {
// Reset any previously set lights
meshView.setPointLight(pointLightIdx++,
0, 0, 0, // x y z
0, 0, 0, 0, // r g b w
1, 0, 0, 0); // ca la qa maxRange

while (lightIndex < 3) { // Reset any previously set lights
meshView.setLight(lightIndex++,
0, 0, 0, // x y z
0, 0, 0, 0, // r g b w
1, 0, 0, 0, // ca la qa maxRange
0, 0, 0, // dirX Y Z
0, 0, 0); // inner outer falloff
}

meshView.render(g);
}

// Clamp between [0, 1]
private static float saturate(float value) {
return value < 1.0f ? ((value < 0.0f) ? 0.0f : value) : 1.0f;
}

public void setMesh(NGTriangleMesh triangleMesh) {
this.mesh = triangleMesh;
meshView = null;

1 comment on commit 3fd4c97

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on 3fd4c97 Jun 24, 2021

Please sign in to comment.