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

8217472: Add attenuation for PointLight #43

Closed
Closed
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
This conversation was marked as resolved by nlisker

This comment has been minimized.

@kevinrushforth

kevinrushforth Jul 24, 2020
Member

Update the "last modified year" for 2020 or else revert (this applies to all copyright year updates).

This comment has been minimized.

@nlisker

nlisker Jul 28, 2020
Author Collaborator

Can the script not get it?

This comment has been minimized.

@kevinrushforth

kevinrushforth Jul 28, 2020
Member

Yes, it can. So it would be fine to leave it.

* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,6 +56,12 @@ protected NGNode createPeerImpl(Node node) {
return pointLightAccessor.doCreatePeer(node);
}

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

public static void setPointLightAccessor(final PointLightAccessor newAccessor) {
if (pointLightAccessor != null) {
throw new IllegalStateException();
@@ -66,7 +72,6 @@ public static void setPointLightAccessor(final PointLightAccessor newAccessor) {

public interface PointLightAccessor {
NGNode doCreatePeer(Node node);
void doUpdatePeer(Node node);
}

}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -26,11 +26,94 @@
package com.sun.javafx.sg.prism;

/**
* TODO: 3D - Need documentation
* 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
* values changes. The peer receives its changes by {@code PointLight.doUpdatePeer} calls.
*/
public class NGPointLight extends NGLightBase {

/** Constant attenuation factor default value */
private static final float DEFAULT_CA = 1;
/** Linear attenuation factor default value */
private static final float DEFAULT_LA = 0;
/** Quadratic attenuation factor default value */
private static final float DEFAULT_QA = 0;
/** Max range default value */
private static final float DEFAULT_MAX_RANGE = Float.POSITIVE_INFINITY;

This conversation was marked as resolved by kevinrushforth

This comment has been minimized.

@arapte

arapte Jan 3, 2020
Member

Will it be a good idea to move these constants to PointLight class?
However they look good here too.

This comment has been minimized.

@nlisker

nlisker Jan 3, 2020
Author Collaborator

If they are in PointLight it will be difficult for the peer to access them (will need to do through the accessor). Also, the parent NGLightBase holds the defaults for color and lightOn.

public NGPointLight() {
}

public static float getDefaultCa() {
return DEFAULT_CA;
}

public static float getDefaultLa() {
return DEFAULT_LA;
}

public static float getDefaultQa() {
return DEFAULT_QA;
}

public static float getDefaultMaxRange() {
return DEFAULT_MAX_RANGE;
}


private float ca = DEFAULT_CA;

public float getCa() {
return ca;
}

public void setCa(float ca) {
if (this.ca != ca) {
this.ca = ca;
visualsChanged();
}
}


private float la = DEFAULT_LA;

public float getLa() {
return la;
}

public void setLa(float la) {
if (this.la != la) {
this.la = la;
visualsChanged();
}
}


private float qa = DEFAULT_QA;

public float getQa() {
return qa;
}

public void setQa(float qa) {
if (this.qa != qa) {
this.qa = qa;
visualsChanged();
}
}


private float maxRange = DEFAULT_MAX_RANGE;

public float getMaxRange() {
return maxRange;
}

public void setMaxRange(float maxRange) {
maxRange = maxRange < 0 ? 0 : maxRange;
if (this.maxRange != maxRange) {
this.maxRange = maxRange;
visualsChanged();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -109,14 +109,18 @@ private void renderMeshView(Graphics g) {
int pointLightIdx = 0;
if (g.getLights() == null || g.getLights()[0] == null) {
// If no lights are in scene apply default light. Default light
// is a single point white point light at camera eye position.
// 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);
1.0f, 1.0f, 1.0f, 1.0f,
NGPointLight.getDefaultCa(),
NGPointLight.getDefaultLa(),
NGPointLight.getDefaultQa(),
NGPointLight.getDefaultMaxRange());
} else {
float ambientRed = 0.0f;
float ambientBlue = 0.0f;
@@ -132,7 +136,7 @@ private void renderMeshView(Graphics g) {
float gL = lightBase.getColor().getGreen();
float bL = lightBase.getColor().getBlue();
/* TODO: 3D
* There is a limit on the number of lights that can affect
* 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.
*
@@ -155,7 +159,11 @@ private void renderMeshView(Graphics g) {
(float)lightWT.getMxt(),
(float)lightWT.getMyt(),
(float)lightWT.getMzt(),
rL, gL, bL, 1.0f);
rL, gL, bL, 1.0f,
light.getCa(),
light.getLa(),
light.getQa(),
light.getMaxRange());
}
} else if (lightBase instanceof NGAmbientLight) {
// Accumulate ambient lights
@@ -173,7 +181,10 @@ private void renderMeshView(Graphics g) {
// 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, 0, 0, 0, 0);
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
This conversation was marked as resolved by kevinrushforth

This comment has been minimized.

@kevinrushforth

kevinrushforth Jul 24, 2020
Member

Minor: maybe use the getDefaultXxxx methods of NGPointLight?

This comment has been minimized.

@nlisker

nlisker Jul 29, 2020
Author Collaborator

The only impact this has is that the range will be maximal instead of 0. When these reach the shader, they will run the lighting computation as opposed to skipping it. I'm not sure if this will have any performance impact though.

This comment has been minimized.

@kevinrushforth

kevinrushforth Aug 7, 2020
Member

In that case, it seems like a generally useful optimization (not just at initialization) to send down maxRange as 0 whenever ca, la, and qa are all at their default values.

This comment has been minimized.

@kevinrushforth

kevinrushforth Oct 8, 2020
Member

Actually, my above comment is wrong. A maxRange of 0 will effectively disable the lighting, even in the case whether the other three values are 1, 0, 0. So maxRange should be set to Float.POSITIVE_INFINITY (or else just use the default constants).

This comment has been minimized.

@nlisker

nlisker Oct 9, 2020
Author Collaborator

These lights are fillers for the native lights array in the case where the user set less than 3 lights, they are not supposed to do anything, and their color is black. A range of 0 will guarantee that the computation in the shader will be skipped.

In a WIP that I have locally I have removed the "3 lights constraint" altogether, so this part will change in that proposed patch anyway.

}

meshView.render(g);
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -48,7 +48,8 @@

public void setPointLight(int index,
float x, float y, float z,
float r, float g, float b, float w);
float r, float g, float b, float w,
float ca, float la, float qa, float maxRange);

public void render(Graphics g);
}
@@ -426,7 +426,8 @@ private static native void nSetWireframe(long pContext, long nativeMeshView,
private static native void nSetAmbientLight(long pContext, long nativeMeshView,
float r, float g, float b);
private static native void nSetPointLight(long pContext, long nativeMeshView,
int index, float x, float y, float z, float r, float g, float b, float w);
int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange);
private static native void nRenderMeshView(long pContext, long nativeMeshView);
private static native int nDrawIndexedQuads(long pContext,
float coords[], byte colors[], int numVertices);
@@ -551,8 +552,9 @@ void setAmbientLight(long nativeMeshView, float r, float g, float b) {
nSetAmbientLight(pContext, nativeMeshView, r, g, b);
}

void setPointLight(long nativeMeshView, int index, float x, float y, float z, float r, float g, float b, float w) {
nSetPointLight(pContext, nativeMeshView, index, x, y, z, r, g, b, w);
void setPointLight(long nativeMeshView, int index, float x, float y, float z,
float r, float g, float b, float w, float ca, float la, float qa, float maxRange) {
nSetPointLight(pContext, nativeMeshView, index, x, y, z, r, g, b, w, ca, la, qa, maxRange);
}

@Override
@@ -81,10 +81,11 @@ public void setAmbientLight(float r, float g, float b) {
}

@Override
public void setPointLight(int index, float x, float y, float z, float r, float g, float b, float w) {
public void setPointLight(int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange) {
// NOTE: We only support up to 3 point lights at the present
if (index >= 0 && index <= 2) {
context.setPointLight(nativeHandle, index, x, y, z, r, g, b, w);
context.setPointLight(nativeHandle, index, x, y, z, r, g, b, w, ca, la, qa, maxRange);
}
}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2019, 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
@@ -449,8 +449,9 @@ void setAmbientLight(long nativeHandle, float r, float g, float b) {
glContext.setAmbientLight(nativeHandle, r, g, b);
}

void setPointLight(long nativeHandle, int index, float x, float y, float z, float r, float g, float b, float w) {
glContext.setPointLight(nativeHandle, index, x, y, z, r, g, b, w);
void setPointLight(long nativeHandle, int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange) {
glContext.setPointLight(nativeHandle, index, x, y, z, r, g, b, w, ca, la, qa, maxRange);
}

@Override
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -32,14 +32,19 @@

float x, y, z = 0;
float r, g, b, w = 1;
float ca, la, qa, maxRange;

ES2Light(float ix, float iy, float iz, float ir, float ig, float ib, float iw) {
ES2Light(float ix, float iy, float iz, float ir, float ig, float ib, float iw, float ca, float la, float qa, float maxRange) {
x = ix;
y = iy;
z = iz;
r = ir;
g = ig;
b = ib;
w = iw;
this.ca = ca;
this.la = la;
this.qa = qa;
this.maxRange = maxRange;
}
}
@@ -101,11 +101,12 @@ float getAmbientLightBlue() {
}

@Override
public void setPointLight(int index, float x, float y, float z, float r, float g, float b, float w) {
public void setPointLight(int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange) {
// NOTE: We only support up to 3 point lights at the present
if (index >= 0 && index <= 2) {
lights[index] = new ES2Light(x, y, z, r, g, b, w);
context.setPointLight(nativeHandle, index, x, y, z, r, g, b, w);
lights[index] = new ES2Light(x, y, z, r, g, b, w, ca, la, qa, maxRange);
context.setPointLight(nativeHandle, index, x, y, z, r, g, b, w, ca, la, qa, maxRange);
}
}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@@ -204,10 +204,12 @@ static void setShaderParamaters(ES2Shader shader, ES2MeshView meshView, ES2Conte
meshView.getAmbientLightGreen(), meshView.getAmbientLightBlue());

int i = 0;
for(ES2Light light : meshView.getPointLights()) {
for (ES2Light light : meshView.getPointLights()) {
if (light != null && light.w > 0) {
shader.setConstant("lights[" + i + "].pos", light.x, light.y, light.z, light.w);
shader.setConstant("lights[" + i + "].color", light.r, light.g, light.b);
shader.setConstant("lights[" + i + "].attn", light.ca, light.la, light.qa);
shader.setConstant("lights[" + i + "].range", light.maxRange);
i++;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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
@@ -252,7 +252,8 @@ private static native void nSetWireframe(long nativeCtxInfo, long nativeMeshView
private static native void nSetAmbientLight(long nativeCtxInfo, long nativeMeshViewInfo,
float r, float g, float b);
private static native void nSetPointLight(long nativeCtxInfo, long nativeMeshViewInfo,
int index, float x, float y, float z, float r, float g, float b, float w);
int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange);
private static native void nRenderMeshView(long nativeCtxInfo, long nativeMeshViewInfo);
private static native void nBlit(long nativeCtxInfo, int srcFBO, int dstFBO,
int srcX0, int srcY0, int srcX1, int srcY1,
@@ -808,8 +809,9 @@ void setAmbientLight(long nativeMeshViewInfo, float r, float g, float b) {
nSetAmbientLight(nativeCtxInfo, nativeMeshViewInfo, r, g, b);
}

void setPointLight(long nativeMeshViewInfo, int index, float x, float y, float z, float r, float g, float b, float w) {
nSetPointLight(nativeCtxInfo, nativeMeshViewInfo, index, x, y, z, r, g, b, w);
void setPointLight(long nativeMeshViewInfo, int index, float x, float y, float z, float r, float g, float b, float w,
float ca, float la, float qa, float maxRange) {
nSetPointLight(nativeCtxInfo, nativeMeshViewInfo, index, x, y, z, r, g, b, w, ca, la, qa, maxRange);
}

void renderMeshView(long nativeMeshViewInfo) {
@@ -44,8 +44,10 @@
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
@@ -277,6 +279,20 @@ void scenesChanged(final Scene newScene, final SubScene newSubScene,
}
}

/**
* For use by implementing subclasses. Treat as protected.
*
* Creates and returns a SimpleDoubleProperty with an invalidation scheme.
*/
DoubleProperty getLightDoubleProperty(String name, double initialValue) {
return new SimpleDoubleProperty(this, name, initialValue) {
@Override
protected void invalidated() {
NodeHelper.markDirty(LightBase.this, DirtyBits.NODE_LIGHT);
}
};
}

private void markOwnerDirty() {
// if the light is part of the scene/subScene, we will need to notify
// the owner to mark the entire scene/subScene dirty.
ProTip! Use n and p to navigate between commits in a pull request.