diff --git a/android/filament-android/CMakeLists.txt b/android/filament-android/CMakeLists.txt index b00e7f4527..3aed9da6cd 100644 --- a/android/filament-android/CMakeLists.txt +++ b/android/filament-android/CMakeLists.txt @@ -46,7 +46,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -Wl, add_library(filament-jni SHARED src/main/cpp/Camera.cpp src/main/cpp/Colors.cpp - src/main/cpp/VertexBuffer.cpp + src/main/cpp/ColorGrading.cpp src/main/cpp/Engine.cpp src/main/cpp/EntityManager.cpp src/main/cpp/Fence.cpp @@ -66,6 +66,7 @@ add_library(filament-jni SHARED src/main/cpp/Texture.cpp src/main/cpp/TextureSampler.cpp src/main/cpp/TransformManager.cpp + src/main/cpp/VertexBuffer.cpp src/main/cpp/View.cpp # Android specific src/main/cpp/nativewindow/Android.cpp diff --git a/android/filament-android/src/main/cpp/ColorGrading.cpp b/android/filament-android/src/main/cpp/ColorGrading.cpp new file mode 100644 index 0000000000..4c70758f17 --- /dev/null +++ b/android/filament-android/src/main/cpp/ColorGrading.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include + +using namespace filament; +using namespace math; + +extern "C" JNIEXPORT jlong JNICALL +Java_com_google_android_filament_ColorGrading_nCreateBuilder(JNIEnv*, jclass) { + return (jlong) new ColorGrading::Builder(); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nDestroyBuilder(JNIEnv*, jclass, + jlong nativeBuilder) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + delete builder; +} + +extern "C" JNIEXPORT jlong JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderBuild(JNIEnv*, jclass, + jlong nativeBuilder, jlong nativeEngine) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + Engine *engine = (Engine *) nativeEngine; + return (jlong) builder->build(*engine); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderToneMapping(JNIEnv*, jclass, + jlong nativeBuilder, jint toneMapping_) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + ColorGrading::ToneMapping toneMapping = (ColorGrading::ToneMapping) toneMapping_; + builder->toneMapping(toneMapping); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderWhiteBalance(JNIEnv*, jclass, + jlong nativeBuilder, jfloat temperature, jfloat tint) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->whiteBalance(temperature, tint); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderChannelMixer(JNIEnv* env, jclass, + jlong nativeBuilder, jfloatArray outRed_, jfloatArray outGreen_, jfloatArray outBlue_) { + + jfloat* outRed = env->GetFloatArrayElements(outRed_, nullptr); + jfloat* outGreen = env->GetFloatArrayElements(outGreen_, nullptr); + jfloat* outBlue = env->GetFloatArrayElements(outBlue_, nullptr); + + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->channelMixer( + *reinterpret_cast(outRed), + *reinterpret_cast(outGreen), + *reinterpret_cast(outBlue)); + + env->ReleaseFloatArrayElements(outRed_, outRed, JNI_ABORT); + env->ReleaseFloatArrayElements(outGreen_, outGreen, JNI_ABORT); + env->ReleaseFloatArrayElements(outBlue_, outBlue, JNI_ABORT); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderShadowsMidtonesHighlights(JNIEnv* env, jclass, jlong nativeBuilder, + jfloatArray shadows_, jfloatArray midtones_, jfloatArray highlights_, jfloatArray ranges_) { + + jfloat* shadows = env->GetFloatArrayElements(shadows_, nullptr); + jfloat* midtones = env->GetFloatArrayElements(midtones_, nullptr); + jfloat* highlights = env->GetFloatArrayElements(highlights_, nullptr); + jfloat* ranges = env->GetFloatArrayElements(ranges_, nullptr); + + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->shadowsMidtonesHighlights( + *reinterpret_cast(shadows), + *reinterpret_cast(midtones), + *reinterpret_cast(highlights), + *reinterpret_cast(ranges)); + + env->ReleaseFloatArrayElements(shadows_, shadows, JNI_ABORT); + env->ReleaseFloatArrayElements(midtones_, midtones, JNI_ABORT); + env->ReleaseFloatArrayElements(highlights_, highlights, JNI_ABORT); + env->ReleaseFloatArrayElements(ranges_, ranges, JNI_ABORT); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderSlopeOffsetPower(JNIEnv* env, jclass, + jlong nativeBuilder, jfloatArray slope_, jfloatArray offset_, jfloatArray power_) { + + jfloat* slope = env->GetFloatArrayElements(slope_, nullptr); + jfloat* offset = env->GetFloatArrayElements(offset_, nullptr); + jfloat* power = env->GetFloatArrayElements(power_, nullptr); + + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->channelMixer( + *reinterpret_cast(slope), + *reinterpret_cast(offset), + *reinterpret_cast(power)); + + env->ReleaseFloatArrayElements(slope_, slope, JNI_ABORT); + env->ReleaseFloatArrayElements(offset_, offset, JNI_ABORT); + env->ReleaseFloatArrayElements(power_, power, JNI_ABORT); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderContrast(JNIEnv*, jclass, + jlong nativeBuilder, jfloat contrast) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->contrast(contrast); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_ColorGrading_nBuilderSaturation(JNIEnv*, jclass, + jlong nativeBuilder, jfloat saturation) { + ColorGrading::Builder* builder = (ColorGrading::Builder*) nativeBuilder; + builder->saturation(saturation); +} diff --git a/android/filament-android/src/main/cpp/Engine.cpp b/android/filament-android/src/main/cpp/Engine.cpp index bb3d75d340..b3d3e546f6 100644 --- a/android/filament-android/src/main/cpp/Engine.cpp +++ b/android/filament-android/src/main/cpp/Engine.cpp @@ -237,6 +237,14 @@ Java_com_google_android_filament_Engine_nDestroySkybox(JNIEnv*, jclass, return engine->destroy(skybox); } +extern "C" JNIEXPORT jboolean JNICALL +Java_com_google_android_filament_Engine_nDestroyColorGrading(JNIEnv*, jclass, + jlong nativeEngine, jlong nativeColorGrading) { + Engine* engine = (Engine*) nativeEngine; + ColorGrading* colorGrading = (ColorGrading*) nativeColorGrading; + return engine->destroy(colorGrading); +} + extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_Engine_nDestroyTexture(JNIEnv*, jclass, jlong nativeEngine, jlong nativeTexture) { diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index c885f93a53..a68a9a99fa 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -37,12 +37,21 @@ Java_com_google_android_filament_View_nSetScene(JNIEnv*, jclass, jlong nativeVie } extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_View_nSetCamera(JNIEnv*, jclass, jlong nativeView, jlong nativeCamera) { +Java_com_google_android_filament_View_nSetCamera(JNIEnv*, jclass, + jlong nativeView, jlong nativeCamera) { View* view = (View*) nativeView; Camera* camera = (Camera*) nativeCamera; view->setCamera(camera); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_View_nSetColorGrading(JNIEnv*, jclass, + jlong nativeView, jlong nativeColorGrading) { + View* view = (View*) nativeView; + ColorGrading* colorGrading = (ColorGrading*) nativeColorGrading; + view->setColorGrading(colorGrading); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetViewport(JNIEnv*, jclass, jlong nativeView, jint left, jint bottom, jint width, jint height) { @@ -93,18 +102,6 @@ Java_com_google_android_filament_View_nGetAntiAliasing(JNIEnv*, jclass, jlong na return (jint) view->getAntiAliasing(); } -extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_View_nSetToneMapping(JNIEnv*, jclass, jlong nativeView, jint type) { - View* view = (View*) nativeView; - view->setToneMapping(View::ToneMapping(type)); -} - -extern "C" JNIEXPORT jint JNICALL -Java_com_google_android_filament_View_nGetToneMapping(JNIEnv*, jclass, jlong nativeView) { - View* view = (View*) nativeView; - return (jint) view->getToneMapping(); -} - extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetDithering(JNIEnv*, jclass, jlong nativeView, jint dithering) { View* view = (View*) nativeView; diff --git a/android/filament-android/src/main/java/com/google/android/filament/Asserts.java b/android/filament-android/src/main/java/com/google/android/filament/Asserts.java index 8777b02da5..ea718e5971 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Asserts.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Asserts.java @@ -78,6 +78,12 @@ final class Asserts { return out; } + static void assertFloat3In(@NonNull float[] out) { + if (out.length < 3) { + throw new ArrayIndexOutOfBoundsException("Array length must be at least 3"); + } + } + @NonNull @Size(min = 4) static float[] assertFloat4(@Nullable float[] out) { if (out == null) out = new float[4]; @@ -86,4 +92,10 @@ final class Asserts { } return out; } + + static void assertFloat4In(@NonNull float[] out) { + if (out.length < 4) { + throw new ArrayIndexOutOfBoundsException("Array length must be at least 4"); + } + } } diff --git a/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java b/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java new file mode 100644 index 0000000000..174a11c9d3 --- /dev/null +++ b/android/filament-android/src/main/java/com/google/android/filament/ColorGrading.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.filament; + +import androidx.annotation.NonNull; +import androidx.annotation.Size; + +import static com.google.android.filament.Asserts.assertFloat3In; +import static com.google.android.filament.Asserts.assertFloat4In; + +/** + * ColorGrading is used to transform (either to modify or correct) the colors of the + * HDR buffer rendered by Filament. Color grading transforms are applied after lighting, and after any + * lens effects (bloom for instance), and include tone mapping. + * + *

Creation, usage and destruction

+ * + * A ColorGrading object is created using the ColorGrading::Builder and destroyed by calling + * Engine::destroy(const ColorGrading*). A ColorGrading object is meant to be set on a View. + * + *
+ *  Engine engine = Engine.create();
+ *
+ *  ColorGrading colorGrading = ColorGrading.Builder()
+ *              .toneMapping(ColorGrading.ToneMapping.ACES)
+ *              .build(engine);
+ *
+ *  myView.setColorGrading(colorGrading);
+ *
+ *  engine.destroy(colorGrading);
+ * 
+ * + *

Performance

+ * + * Creating a new ColorGrading object may be more expensive than other Filament objects as a + * 3D LUT may need to be generated. The generation of a 3D LUT, if necessary, may happen on + * the CPU. + * + *

Ordering

+ * + * The various transforms held by ColorGrading are applied in the following order: + * + * + *

Defaults

+ * + * Here are the default color grading options: + * + * + * @see View + * @see ToneMapping + */ +public class ColorGrading { + long mNativeObject; + + /** + * List of available tone-mapping operators. + */ + public enum ToneMapping { + /** Linear tone mapping (i.e. no tone mapping). */ + LINEAR, + /** ACES tone mapping, with a brightness modifier to match Filament's legacy tone mapper. */ + ACES_LEGACY, + /** ACES tone mapping. */ + ACES, + /** Filmic tone mapping, modelled after ACES but applied in sRGB space. */ + FILMIC, + /** Reinhard luma-based tone mapping. */ + REINHARD, + /** Tone mapping used to validate/debug scene exposure. */ + DISPLAY_RANGE, + } + + ColorGrading(long colorGrading) { + mNativeObject = colorGrading; + } + + /** + * Use Builder to construct a ColorGrading object instance. + */ + public static class Builder { + @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources + private final BuilderFinalizer mFinalizer; + private final long mNativeBuilder; + + /** + * Use Builder to construct a ColorGrading object instance. + */ + public Builder() { + mNativeBuilder = nCreateBuilder(); + mFinalizer = new BuilderFinalizer(mNativeBuilder); + } + + /** + * Selects the tone mapping operator to apply to the HDR color buffer as the last + * operation of the color grading post-processing step. + * + * The default tone mapping operator is {@link ToneMapping#ACES_LEGACY}. + * + * @param toneMapping The tone mapping operator to apply to the HDR color buffer + * + * @return This Builder, for chaining calls + */ + public Builder toneMapping(ToneMapping toneMapping) { + nBuilderToneMapping(mNativeBuilder, toneMapping.ordinal()); + return this; + } + + /** + * Adjusts the while balance of the image. This can be used to remove color casts + * and correct the appearance of the white point in the scene, or to alter the + * overall chromaticity of the image for artistic reasons (to make the image appear + * cooler or warmer for instance). + * + * The while balance adjustment is defined with two values: + * + * + * Both values are expected to be in the range [-1.0..+1.0]. Values outside + * of that range will be clipped to that range. + * + * @param temperature Modification on the blue/yellow axis, as a value between -1.0 and +1.0. + * @param tint Modification on the green/magenta axis, as a value between -1.0 and +1.0. + * + * @return This Builder, for chaining calls + */ + public Builder whiteBalance(float temperature, float tint) { + nBuilderWhiteBalance(mNativeBuilder, temperature, tint); + return this; + } + + /** + * The channel mixer adjustment modifies each output color channel using the specified + * mix of the source color channels. + * + * By default each output color channel is set to use 100% of the corresponding source + * channel and 0% of the other channels. For instance, the output red channel is set to + * {1.0, 0.0, 1.0} or 100% red, 0% green and 0% blue. + * + * Each output channel can add or subtract data from the source channel by using values + * in the range [-2.0..+2.0]. Values outside of that range will be clipped + * to that range. + * + * Using the channel mixer adjustment you can for instance create a monochrome output + * by setting all 3 output channels to the same mix. For instance: + * {0.4, 0.4, 0.2} for all 3 output channels(40% red, 40% green and 20% blue). + * + * More complex mixes can be used to create more complex effects. For instance, here is + * a mix that creates a sepia tone effect: + * + * + * @param outRed The mix of source RGB for the output red channel, between -2.0 and +2.0 + * @param outGreen The mix of source RGB for the output green channel, between -2.0 and +2.0 + * @param outBlue The mix of source RGB for the output blue channel, between -2.0 and +2.0 + * + * @return This Builder, for chaining calls + */ + public Builder channelMixer( + @NonNull @Size(min = 3) float[] outRed, + @NonNull @Size(min = 3) float[] outGreen, + @NonNull @Size(min = 3) float[] outBlue) { + + assertFloat3In(outRed); + assertFloat3In(outGreen); + assertFloat3In(outBlue); + + nBuilderChannelMixer(mNativeBuilder, outRed, outGreen, outBlue); + + return this; + } + + /** + * Adjusts the colors separately in 3 distinct tonal ranges or zones: shadows, mid-tones, + * and highlights. + * + * The tonal zones are by the ranges parameter: the x and y components define the beginning + * and end of the transition from shadows to mid-tones, and the z and w components define + * the beginning and end of the transition from mid-tones to highlights. + * + * A smooth transition is applied between the zones which means for instance that the + * correction color of the shadows range will partially apply to the mid-tones, and the + * other way around. This ensure smooth visual transitions in the final image. + * + * Each correction color is defined as a linear RGB color and a weight. The weight is a + * value (which may be positive or negative) that is added to the linear RGB color before + * mixing. This can be used to darken or brighten the selected tonal range. + * + * Shadows/mid-tones/highlights adjustment are performed linear space. + * + * @param shadows Linear RGB color (.rgb) and weight (.w) to apply to the shadows + * @param midtones Linear RGB color (.rgb) and weight (.w) to apply to the mid-tones + * @param highlights Linear RGB color (.rgb) and weight (.w) to apply to the highlights + * @param ranges Range of the shadows (x and y), and range of the highlights (z and w) + * + * @return This Builder, for chaining calls + */ + Builder shadowsMidtonesHighlights( + @NonNull @Size(min = 4) float[] shadows, + @NonNull @Size(min = 4) float[] midtones, + @NonNull @Size(min = 4) float[] highlights, + @NonNull @Size(min = 4) float[] ranges) { + + assertFloat4In(shadows); + assertFloat4In(midtones); + assertFloat4In(highlights); + assertFloat4In(ranges); + + nBuilderShadowsMidtonesHighlights(mNativeBuilder, shadows, midtones, highlights, ranges); + + return this; + } + + /** + * Applies a slope, offset, and power, as defined by the ASC CDL (American Society of + * Cinematographers Color Decision List) to the image. The CDL can be used to adjust the + * colors of different tonal ranges in the image. + * + * The ASC CDL is similar to the lift/gamma/gain controls found in many color grading tools. + * Lift is equivalent to a combination of offset and slope, gain is equivalent to slope, + * and gamma is equivalent to power. + * + * The slope and power values must be strictly positive. Values less than or equal to 0 will + * be clamped to a small positive value, offset can be any positive or negative value. + * + * Version 1.2 of the ASC CDL adds saturation control, which is here provided as a separate + * API. See the saturation() method for more information. + * + * Slope/offset/power adjustments are performed in log space. + * + * @param slope Multiplier of the input color, must be a strictly positive number + * @param offset Added to the input color, can be a negative or positive number, including 0 + * @param power Power exponent of the input color, must be a strictly positive number + * + * @return This Builder, for chaining calls + */ + Builder slopeOffsetPower( + @NonNull @Size(min = 3) float[] slope, + @NonNull @Size(min = 3) float[] offset, + @NonNull @Size(min = 3) float[] power) { + + assertFloat3In(slope); + assertFloat3In(offset); + assertFloat3In(power); + + nBuilderSlopeOffsetPower(mNativeBuilder, slope, offset, power); + + return this; + } + + /** + * Adjusts the contrast of the image. Lower values decrease the contrast of the image + * (the tonal range is narrowed), and higher values increase the contrast of the image + * (the tonal range is widened). A value of 1.0 has no effect. + * + * The contrast is defined as a value in the range [0.0...2.0]. Values + * outside of that range will be clipped to that range. + * + * Contrast adjustment is performed in log space. + * + * @param contrast Contrast expansion, between 0.0 and 2.0. 1.0 leaves contrast unaffected + * + * @return This Builder, for chaining calls + */ + public Builder contrast(float contrast) { + nBuilderContrast(mNativeBuilder, contrast); + return this; + } + + /** + * Adjusts the saturation of the image. Lower values decrease intensity of the colors + * present in the image, and higher values increase the intensity of the colors in the + * image. A value of 1.0 has no effect. + * + * The saturation is defined as a value in the range [0.0...2.0]. + * Values outside of that range will be clipped to that range. + * + * Saturation adjustment is performed in log space. + * + * @param saturation Saturation, between 0.0 and 2.0. 1.0 leaves saturation unaffected + * + * @return This Builder, for chaining calls + */ + public Builder saturation(float saturation) { + nBuilderSaturation(mNativeBuilder, saturation); + return this; + } + + /** + * Creates the IndirectLight object and returns a pointer to it. + * + * @param engine The {@link Engine} to associate this IndirectLight with. + * + * @return A newly created IndirectLight + * + * @exception IllegalStateException if a parameter to a builder function was invalid. + */ + @NonNull + public ColorGrading build(@NonNull Engine engine) { + long nativeColorGrading = nBuilderBuild(mNativeBuilder, engine.getNativeObject()); + if (nativeColorGrading == 0) throw new IllegalStateException("Couldn't create ColorGrading"); + return new ColorGrading(nativeColorGrading); + } + + private static class BuilderFinalizer { + private final long mNativeObject; + + BuilderFinalizer(long nativeObject) { mNativeObject = nativeObject; } + + @Override + public void finalize() { + try { + super.finalize(); + } catch (Throwable t) { // Ignore + } finally { + nDestroyBuilder(mNativeObject); + } + } + } + } + + public long getNativeObject() { + if (mNativeObject == 0) { + throw new IllegalStateException("Calling method on destroyed ColorGrading"); + } + return mNativeObject; + } + + void clearNativeObject() { + mNativeObject = 0; + } + + private static native long nCreateBuilder(); + private static native void nDestroyBuilder(long nativeBuilder); + + private static native void nBuilderToneMapping(long nativeBuilder, int ordinal); + private static native void nBuilderWhiteBalance(long nativeBuilder, float temperature, float tint); + private static native void nBuilderChannelMixer(long nativeBuilder, float[] outRed, float[] outGreen, float[] outBlue); + private static native void nBuilderShadowsMidtonesHighlights(long nativeBuilder, float[] shadows, float[] midtones, float[] highlights, float[] ranges); + private static native void nBuilderSlopeOffsetPower(long nativeBuilder, float[] slope, float[] offset, float[] power); + private static native void nBuilderContrast(long nativeBuilder, float contrast); + private static native void nBuilderSaturation(long nativeBuilder, float saturation); + + private static native long nBuilderBuild(long nativeBuilder, long nativeEngine); +} + diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index c68657d78e..53b53a876a 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -549,6 +549,15 @@ public class Engine { skybox.clearNativeObject(); } + /** + * Destroys a {@link ColorGrading} and frees all its associated resources. + * @param colorGrading the {@link ColorGrading} to destroy + */ + public void destroySkybox(@NonNull ColorGrading colorGrading) { + assertDestroy(nDestroyColorGrading(getNativeObject(), colorGrading.getNativeObject())); + colorGrading.clearNativeObject(); + } + /** * Destroys a {@link Texture} and frees all its associated resources. * @param texture the {@link Texture} to destroy @@ -665,6 +674,7 @@ public class Engine { private static native boolean nDestroyMaterial(long nativeEngine, long nativeMaterial); private static native boolean nDestroyMaterialInstance(long nativeEngine, long nativeMaterialInstance); private static native boolean nDestroySkybox(long nativeEngine, long nativeSkybox); + private static native boolean nDestroyColorGrading(long nativeEngine, long nativeColorGrading); private static native boolean nDestroyTexture(long nativeEngine, long nativeTexture); private static native boolean nDestroyRenderTarget(long nativeEngine, long nativeTarget); private static native void nDestroyEntity(long nativeEngine, int entity); diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index b07a4de609..02882e4fff 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -70,9 +70,10 @@ public class View { private RenderTarget mRenderTarget; private BlendMode mBlendMode; private DepthOfFieldOptions mDepthOfFieldOptions; + private ColorGrading mColorGrading; /** - * Generic Quality Level + * Generic quality level. */ public enum QualityLevel { LOW, @@ -125,9 +126,9 @@ public class View { public float maxScale = 1.0f; /** - * Upscaling quality. LOW: 1 bilinear taps, MEDIUM: 4 bilinear taps, HIGH: 9 bilinear taps. + * Upscaling quality. LOW: 1 bilinear tap, MEDIUM: 4 bilinear taps, HIGH: 9 bilinear taps. * If minScale needs to be very low, it might help to use MEDIUM or HIGH here. - * The default upsacling quality is set to LOW. + * The default upscaling quality is set to LOW. */ @NonNull public QualityLevel quality = QualityLevel.LOW; @@ -733,19 +734,41 @@ public class View { */ @Deprecated public void setToneMapping(@NonNull ToneMapping type) { - nSetToneMapping(getNativeObject(), type.ordinal()); } /** * Returns the tone-mapping function. * @return tone-mapping function. * - * @deprecated Use {@link #getColorGrading()} + * @deprecated Use {@link #getColorGrading()}. This always returns {@link ToneMapping#ACES} */ @Deprecated @NonNull public ToneMapping getToneMapping() { - return ToneMapping.values()[nGetToneMapping(getNativeObject())]; + return ToneMapping.ACES; + } + + /** + * Sets this View's color grading transforms. + * + * @param colorGrading Associate the specified {@link ColorGrading} to this view. A ColorGrading + * can be associated to several View instances. Can be null to dissociate + * the currently set ColorGrading from this View. Doing so will revert to + * the use of the default color grading transforms. + */ + public void setColorGrading(@Nullable ColorGrading colorGrading) { + nSetColorGrading(getNativeObject(), + colorGrading != null ? colorGrading.getNativeObject() : 0); + mColorGrading = colorGrading; + } + + /** + * Returns the {@link ColorGrading} associated to this view. + * + * @return A {@link ColorGrading} or null if the default {@link ColorGrading} is in use + */ + public ColorGrading getColorGrading() { + return mColorGrading; } /** @@ -1063,13 +1086,12 @@ public class View { private static native int nGetSampleCount(long nativeView); private static native void nSetAntiAliasing(long nativeView, int type); private static native int nGetAntiAliasing(long nativeView); - private static native void nSetToneMapping(long nativeView, int type); - private static native int nGetToneMapping(long nativeView); private static native void nSetDithering(long nativeView, int dithering); private static native int nGetDithering(long nativeView); private static native void nSetDynamicResolutionOptions(long nativeView, boolean enabled, boolean homogeneousScaling, float minScale, float maxScale, int quality); private static native void nSetRenderQuality(long nativeView, int hdrColorBufferQuality); private static native void nSetDynamicLightingOptions(long nativeView, float zLightNear, float zLightFar); + private static native void nSetColorGrading(long nativeView, long nativeColorGrading); private static native void nSetPostProcessingEnabled(long nativeView, boolean enabled); private static native boolean nIsPostProcessingEnabled(long nativeView); private static native void nSetFrontFaceWindingInverted(long nativeView, boolean inverted); diff --git a/filament/include/filament/ColorGrading.h b/filament/include/filament/ColorGrading.h index 53de30956a..debc0cb9c6 100644 --- a/filament/include/filament/ColorGrading.h +++ b/filament/include/filament/ColorGrading.h @@ -167,7 +167,7 @@ public: * by setting all 3 output channels to the same mix. For instance: {0.4, 0.4, 0.2} for * all 3 output channels(40% red, 40% green and 20% blue). * - * More complex mixes can be used to create more compelx effects. For instance, here is + * More complex mixes can be used to create more complex effects. For instance, here is * a mix that creates a sepia tone effect: * - outRed = {0.255, 0.858, 0.087} * - outGreen = {0.213, 0.715, 0.072} @@ -209,7 +209,7 @@ public: */ Builder& shadowsMidtonesHighlights( math::float4 shadows, math::float4 midtones, math::float4 highlights, - math::float4 ranges = math::float4{0.0f, 0.333f, 0.550f, 1.0f}) noexcept; + math::float4 ranges) noexcept; /** * Applies a slope, offset, and power, as defined by the ASC CDL (American Society of @@ -246,11 +246,11 @@ public: * * Contrast adjustment is performed in log space. * - * @param constrast Contrast expansion, between 0.0 and 2.0. 1.0 leaves contrast unaffected + * @param contrast Contrast expansion, between 0.0 and 2.0. 1.0 leaves contrast unaffected * * @return This Builder, for chaining calls */ - Builder& contrast(float constrast) noexcept; + Builder& contrast(float contrast) noexcept; /** * Adjusts the saturation of the image. Lower values decrease intensity of the colors @@ -262,7 +262,7 @@ public: * * Saturation adjustment is performed in log space. * - * @param constrast Saturation, between 0.0 and 2.0. 1.0 leaves saturation unaffected + * @param saturation Saturation, between 0.0 and 2.0. 1.0 leaves saturation unaffected * * @return This Builder, for chaining calls */ diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index a37ffb1f16..eb446afccf 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -496,7 +496,7 @@ public: * * @param colorGrading Associate the specified ColorGrading to this View. A ColorGrading can be * associated to several View instances.\n - * \p colorGradingOptions can be nullptr to dissociate the currently set + * \p colorGrading can be nullptr to dissociate the currently set * ColorGrading from this View. Doing so will revert to the use of the * default color grading transforms.\n * The View doesn't take ownership of the ColorGrading pointer (which diff --git a/java/filament/CMakeLists.txt b/java/filament/CMakeLists.txt index c330df4f9d..3926e65a4c 100644 --- a/java/filament/CMakeLists.txt +++ b/java/filament/CMakeLists.txt @@ -42,6 +42,7 @@ include_directories(${JNI_INCLUDE_DIRS} ${ANDROID_DIR}) set(JNI_SOURCE_FILES ${FILAMENT_DIR}/src/main/cpp/Camera.cpp ${FILAMENT_DIR}/src/main/cpp/Colors.cpp + ${FILAMENT_DIR}/src/main/cpp/ColorGrading.cpp ${FILAMENT_DIR}/src/main/cpp/VertexBuffer.cpp ${FILAMENT_DIR}/src/main/cpp/Engine.cpp ${FILAMENT_DIR}/src/main/cpp/EntityManager.cpp @@ -117,6 +118,7 @@ set(JAVA_SOURCE_FILES ${FILAMENT_JAVA_DIR}/com/google/android/filament/Box.java ${FILAMENT_JAVA_DIR}/com/google/android/filament/Camera.java ${FILAMENT_JAVA_DIR}/com/google/android/filament/Colors.java + ${FILAMENT_JAVA_DIR}/com/google/android/filament/ColorGrading.java ${FILAMENT_JAVA_DIR}/com/google/android/filament/Engine.java ${FILAMENT_JAVA_DIR}/com/google/android/filament/Entity.java ${FILAMENT_JAVA_DIR}/com/google/android/filament/EntityInstance.java