All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javafx.scene.paint.PhongMaterial Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2013, 2024, 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.paint;

import com.sun.javafx.beans.event.AbstractNotifyListener;
import com.sun.javafx.scene.paint.MaterialHelper;
import com.sun.javafx.sg.prism.NGPhongMaterial;
import com.sun.javafx.tk.Toolkit;

import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.AmbientLight;
import javafx.scene.LightBase;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javafx.scene.shape.Shape3D;
import javafx.scene.shape.TriangleMesh;

/**
 * A material based on the Phong shading model. This material has several independent components that together give an
 * object its appearance using the Phong shading model. The material interacts with each illuminating light
 * separately, and the contribution from each light is summed.
 * 

* The diffuse and specular components can be specified by a (solid) color and/or a texture map * (represented as an image). If both are applied, their values are multiplied. For example:
* {@link javafx.scene.paint.Color#LIMEGREEN Color#LIMEGREEN} * * Rainbow gradient = * Green gradient *

* {@link javafx.scene.paint.Color#CYAN Color#CYAN} * * Map = * Tinted map *

* Note: the self-illumination component can not currently be specified as a color. However, a color behaves like * a map (of any size) of a single color. Creating a 1x1 pixel map of that color will have the same effect. *

* {@code PhongMaterial} is not suitable for surfaces that act like mirrors and reflect their environment, such as * reflective metals, water, and reflective ceramics. Neither does light refract (bend) when passing through transparent * or translucent materials such as water, glass, or ice. These materials rely on Fresnel effects that are not * implemented for this material. * *

Components

* Incident ray schematic * While in the physical world each light ray goes through a single path of reflection, transmission, or absorption, in * the computational world a number of adjacent rays are averaged into a single one that can split into multiple paths. * This approximation simplifies the computation model greatly while still allowing realistic rendering. The validity of * this approximation depends on microscopic details of the material, but it holds well for the vast majority of cases. * When an averaged incident ray (blue) hits the surface, it can split into many rays depending on the values of the * components of the material: rays that are either transmitted through the material (green) or reflected in all * directions via scattering (purple) depend on the diffuse component; rays that are reflected (orange), which depend on * the incident angle, are controlled by the specular component. *
* * * * * * * * * * * * *
Material types
Transparent schematicLambertian schematicReflective schematic
TransparentLambertianReflective
*

* Materials whose diffuse component allows only transmitted rays are transparent. These still have a specular component, * otherwise they will be invisible (no such material exists). Materials without a specular component and whose diffuse * component allows only reflected rays exhibit Lambertian reflectance. Lambertian materials reflect light in all * directions equally. Materials with a specular component and a diffuse component that only allows weak reflectance are * reflective. *

* *

Diffuse

* The diffuse component, sometimes called albedo, serves as the base color of the surface. It represents light * that is not reflected directly from the surface and instead enters the material.
* The alpha channel of the diffuse component controls the light that passes through it (transmitted). Decreasing the * alpha value increases the transparency of the material and causes the object to appear translucent, and ultimately * makes it transparent. Materials such as glass and plastics can be simulated with a low alpha value.
* Light that isn't transmitted undergoes subsurface scattering that causes it to be absorbed in the material or * be reflected back to the surface, exiting in (approximately) all directions (irrespective of the incident angle). The * RGB channels of the diffuse component controls which colors are absorbed and which are reflected, giving the material * its base color. The higher one of the RGB values is, the more that material reflects that color. *

* The diffuse component interacts with all lights - both those that have directionality and {@code AmbientLight}, which * simulates a light that comes from all directions. *

* Important: there is currently a bug that causes objects with 0 opacity to not render at all (despite having a * specular or a self-illumination component). Setting the opacity to 1/255 instead will give the desirable result. * *

Specular

* The specular component represents light that is reflected directly from the surface. For most materials, the color of * the specular component is on the gray scale regardless of the diffuse component's color. This means that the specular * highlight will be the light's color and not the material's color. These materials are sometimes called * dielectrics. Metals, on the other hand, reflect a color similar to their diffuse color (like yellow for gold * or reddish for copper) and get most of their appearance from the specular color. These materials are sometimes called * conductors. *

* The spread of the surface-reflected rays simulates the microgeometry that causes adjacent beams to be reflected in * different directions. Smooth surfaces' microgeometry varies little, causing them to have a strong specular component * that results in a glossy look, such as plastics, finished wood, and polished metals. Conversely, rough surfaces have * a varying microgeometry, weak specular component, and a matte look, such as unfinished wood, fabric, and cardboard. * This spread is controlled by the specular power, sometimes called smoothness or, conversely, roughness. * A larger specular power simulates a smoother object, which results in a smaller reflection. *

* The specular component interacts only with lights that have directionality (not {@code AmbientLight}) as it depends * on the incident ray direction, and also on the viewer (camera) position since it depends on the reflectance direction. *

* The alpha component of the specular color is not used at this time. * *

Self-Illumination

* The self-illumination component, also called emissive, represents light emitted by the object. It does not * interact with light sources and as such the viewer position does not matter. Specifying this component does not cause * the object to serve as a light source - a light has to be added at the position of the object with a color that * matches this color. If a multi-colored map is used, several lights of matching colors can be positioned appropriately * in the object's volume to give a realistic appearance. *

* The alpha component of the self-illumination color is not used at this time. * *

Bump

* The bump component gives the illusion of small height changes on the surface, like bumps and ridges. It is a * normal map (not a height map or a displacement map), which works by modifying the normals of * surfaces on the object, causing light to interact differently with the surface than it would have without it. * Tree trunks and rough stones can be simulated with a bump map. *

* Bump maps are less expensive than changing a mesh by subdividing a surface into many polygons facing different ways. * If the physical geometry of the surface is not important (for example, for intersection calculations), it's advised * to use a bump map. *

* The alpha component of the bump map is not used at this time. * *

Mathematical Model

*
* Vectors in the Phong model The image on * the left depicts a standard schematic of a scene with a mesh, a light source, and a camera. The black curve is the * required geometry, and the blue lines are the polygons (mesh) representing this geometry. Four normalized vectors are * considered for each point on the surface:
* L - the vector from the surface to the light source;
* N - the normal vector of the surface;
* V - the vector from the surface to the viewer (camera);
* R - the reflection vector of L from the surface. R can be calculated from L and N: * R=2(L⋅N)N - L. *

* The diffuse and specular components are comprised of 3 factors: the geometry, the light's color, and the material's * color, each considered at every point on the surface. The light's color computation is described in {@link LightBase} * (and its subclasses). The material's color computation, as described above, is the multiplication of the color and * map properties. These factors are multiplied to get the final color. *

* *

Bump

* The default normal vector of a point on the polygon is N=(0, 0, 1) (facing away from the surface). If a bump * map is specified, this vector will have a different value based on the RGB values in the bump map: * N=2 * RGB - 1. The default value for a bump map (corresponding to the default normal) is * RGB=(0.5, 0.5, 1), which is why bump maps tend to be blueish. *

* We will treat N as the normal vector after applying a bump map, if available. * *

Diffuse

* The diffuse component represents light scattered from the surface in all directions, hence, it depends on the * interaction between the light and the surface (and independent of the viewer position): L⋅N. L⋅N * is the geometric factor of the diffuse component. It moderates the intensity of the color resulting from the light * hitting the surface at different angles. If the light ray is parallel to the surface, L⋅N=0 and the diffuse * contribution of the light will be 0; if the light ray is perpendicular to the surface (coincides with the normal * vector), L⋅N=1 and no reduction in intensity occurs. *

* Defining the light's color as CL, and the material's diffuse color as CDM, we * multiply the 3 factors described above: L⋅N * CL * CDM. For i lights illuminating * the surface, the contribution of each light is summed:
* Σi(Li⋅N * CLi * CDM) * = Σi(Li⋅N * CLi) * CDM * (since CDM is a property of the material and is the same for all lights). *

* Since {@link AmbientLight} simulates a light coming from and scattered in all directions, it contributes fully to the * diffuse component (L⋅N=1). We will define all the ambient lights' contribution as * A=Σi(CLi) and all the other lights' (that have a light vector) as * D=Σi(Li⋅N * CLi). The total diffuse component contribution is then * (A+D) * CDM. * *

Specular

* The specular component represents light reflected from the surface in a mirror-like reflection, hence, it depends on * the interaction between the reflected light and the viewer position: R⋅V. As similarly explained in the * diffuse component section, the geometric contribution is strongest when the viewer is aligned with the reflection * vector and is non-existent when they are perpendicular. *

* High specular power * Low specular power * The specular power, P, represents the smoothness of the surface. Smoother surfaces have more narrow * reflections and their specular power is smaller (right image), while rougher surfaces have more dispersed reflections * and their specular power is larger (left image). Since 0≤R⋅V≤1, the term (R⋅V)P decreases * as P increases, giving a smaller contribution. *

* Like with the diffuse component, the resulting specular color is computed by multiplying the geometric factor, the * light's color, and the material's specular color, CSM, for each light:
* Σi((Ri⋅V)P * CLi) * CSM, * and defining the specular lights' contribution as * S=Σi((Ri⋅V)P * CLi), * the total specular component contribution is S * CSM. * *

Self-Illumination

* The self-illumination component represents light emanating from the surface, hence, it is not affected by lights, the * geometry, or the viewer position. Its contribution is just the material's self-illumination color, * CLM. * *

Summary

* * The final color at the point of the computation is then: * (A+D) * CDM + S * CSM + CLM. * *

Examples

* This section shows examples for simulating various common materials. Each image will be accompanied by the values * used for the material. Values that aren't specified are the default ones. * *

Gloss

* The specular power controls the size of specular highlights, which changes the gloss or smoothness look. Lower powers * create larger highlights and vice versa. Some plastics and marble exhibit this behavior, as shown here with 2 * billiard balls: * * * * * * * * * * * * * * * * * * * * * * * *
Materials values
ImageYellow ball with low specular powerRed ball with high specular power
Diffuse color{@code Color.YELLOW.darker()}{@code Color.RED.darker()}
Specular color{@code Color.WHITE}{@code Color.WHITE}
Specular power10150
* *

Transparency

* Some materials are transparent/translucent, allowing most of the light through, like glass and plastics. This is * achieved with low diffuse opacity (alpha) values. Tint can be achieved with small RGB values in addition. The * smoothness of these materials also means a specular component is present with strength that depends on the * finish/polish of the material. A high brightness specular color gives a more glossy look and a low brightness one * gives a more matte look. * * * * * * * * * * * * * * * * * * * * * * * * *
Material values
ImageTransparency with no specular reflectionTransparency with low specular reflectionTransparency with high specular reflectionTinted transparency with low specular reflection
Diffuse color{@code Color.rgb(0, 0, 0, 0.3)}{@code Color.rgb(0, 0, 0, 0.3)}{@code Color.rgb(0, 0, 0, 0.3)}{@code Color.rgb(75, 0, 0, 0.15)}
Specular color{@code Color.hsb(0, 0, 0)}{@code Color.hsb(0, 0, 45)}{@code Color.hsb(0, 0, 90)}{@code Color.hsb(0, 0, 45)}
* *

Specular Color

* Metals reflect their own color rather than the light's full color. In this case, the specular color should be similar * to the diffuse color, with its brightness affecting the shininess/polish levels. Copper and gold are shown here. * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Material values
ImageCopper with low specular reflectionCopper with medium specular reflectionCopper with high specular reflectionGold with low specular reflectionGold with high specular reflection
Diffuse color{@code Color.hsb(20, 85, 70)}{@code Color.hsb(20, 85, 70)}{@code Color.hsb(20, 85, 70)}{@code Color.hsb(41, 82, 92)}{@code Color.hsb(41, 82, 92)}
Specular color{@code Color.hsb(20, 85, 40)}{@code Color.hsb(20, 85, 70)}{@code Color.hsb(20, 85, 100)}{@code Color.hsb(41, 82, 30)}{@code Color.hsb(41, 82, 92)}
* *

Maps and Surface Detail

* The specular and bump maps can provide surface details that make the object look more realistic. A tree trunk, which * has none-to-low specularity, has a lot of grooves that can be emphasized with a bump map: *
*
* Diffuse map *
Diffuse map
*
*
* Bump map *
Bump map
*
*
* * * * * * * * * * * * * *
Model with maps applied
Tree trunk with bump mapTree trunk with diffuse mapTree trunk with diffuse and bump maps
BumpDiffuseBump+Diffuse
* A diffuse color of {@code HSB=(0, 0, 60)} has been used to darken the wood. *

* Polished wood, like that used in housing, has a strong specular component due to the finish and buff. A combination * of a specular and a bump map highlights the details in the wood: *

*
* Diffuse map *
Diffuse map
*
*
* Specular map *
Specular map
*
*
* Bump map *
Bump map
*
*
* * * * * * * * * * * * * * * *
Model with maps applied
Finished wood with diffuse mapFinished wood with diffuse and specular mapsFinished wood with diffuse and bump mapsFinished wood with diffuse, specular, and bump maps
DiffuseDiffuse+SpecularDiffuse+BumpDiffuse+Specular+Bump
* A specular power of 100 has been used to give a more smooth look. * *

Texture Animation

* Texture animation and runtime effects can be achieved in different ways. Firstly, an animated GIF can be used as the * {@code Image} for texture maps, as demonstrated here when used as a diffuse map:
* Animation gif * Animation gif as map *

* Secondly, by using a {@link WritableImage}, the pixel values can be changed programmatically, creating a live texture * as demonstrated for the diffuse map by this code snippet that repaints the image left to right and top to bottom: *

* Writable image as map *
{@code WritableImage diffuseMap = ...
 * material.setDiffuseMap(diffuseMap);
 * var timer = new AnimationTimer() {
 *     int x, y;
 *
 *     @Override
 *     public void handle(long now) {
 *         diffuseMap.getPixelWriter().setColor(x, y, Color.color(0, 0, 1, 0.5));
 *         x++;
 *         if (x > diffuseMap.getWidth() - 1) {
 *             x = 0;
 *             y++;
 *             if (y > diffuseMap.getHeight() - 1) {
 *                 stop();
 *             }
 *         }
 *     }
 * };
 * timer.start();
 * }
*
* Other maps can be modified as well, producing various effects.
* Another way to animate textures is done through changing the {@link TriangleMesh#getTexCoords() texture coordinates} * of the mesh, the explanation for which is out of scope for this class. * * @see LightBase * @see Shape3D * @since JavaFX 8.0 */ public class PhongMaterial extends Material { private boolean diffuseColorDirty = true; private boolean specularColorDirty = true; private boolean specularPowerDirty = true; private boolean diffuseMapDirty = true; private boolean specularMapDirty = true; private boolean bumpMapDirty = true; private boolean selfIlluminationMapDirty = true; /** * Creates a new instance of {@code PhongMaterial} class with a default {@code Color.WHITE diffuseColor} property. */ public PhongMaterial() { setDiffuseColor(Color.WHITE); } /** * Creates a new instance of {@code PhongMaterial} class using the specified * color for its {@code diffuseColor} property. * * @param diffuseColor the color of the diffuseColor property */ public PhongMaterial(Color diffuseColor) { setDiffuseColor(diffuseColor); } /** * Creates a new instance of {@code PhongMaterial} class using the specified * colors and images for its {@code diffuseColor} properties. * * @param diffuseColor the color of the diffuseColor property * @param diffuseMap the image of the diffuseMap property * @param specularMap the image of the specularMap property * @param bumpMap the image of the bumpMap property * @param selfIlluminationMap the image of the selfIlluminationMap property */ public PhongMaterial(Color diffuseColor, Image diffuseMap, Image specularMap, Image bumpMap, Image selfIlluminationMap) { setDiffuseColor(diffuseColor); setDiffuseMap(diffuseMap); setSpecularMap(specularMap); setBumpMap(bumpMap); setSelfIlluminationMap(selfIlluminationMap); } /** * The diffuse color of this {@code PhongMaterial}. * * @defaultValue {@code Color.WHITE} */ private ObjectProperty diffuseColor; public final void setDiffuseColor(Color value) { diffuseColorProperty().set(value); } public final Color getDiffuseColor() { return diffuseColor == null ? null : diffuseColor.get(); } public final ObjectProperty diffuseColorProperty() { if (diffuseColor == null) { diffuseColor = new SimpleObjectProperty<>(PhongMaterial.this, "diffuseColor") { @Override protected void invalidated() { diffuseColorDirty = true; setDirty(true); } }; } return diffuseColor; } /** * The specular color of this {@code PhongMaterial}. * * @defaultValue {@code null} */ private ObjectProperty specularColor; public final void setSpecularColor(Color value) { specularColorProperty().set(value); } public final Color getSpecularColor() { return specularColor == null ? null : specularColor.get(); } public final ObjectProperty specularColorProperty() { if (specularColor == null) { specularColor = new SimpleObjectProperty<>(PhongMaterial.this, "specularColor") { @Override protected void invalidated() { specularColorDirty = true; setDirty(true); } }; } return specularColor; } /** * The specular power of this {@code PhongMaterial}. * * @defaultValue 32.0 */ private DoubleProperty specularPower; public final void setSpecularPower(double value) { specularPowerProperty().set(value); } public final double getSpecularPower() { return specularPower == null ? 32 : specularPower.get(); } public final DoubleProperty specularPowerProperty() { if (specularPower == null) { specularPower = new SimpleDoubleProperty(PhongMaterial.this, "specularPower", 32.0) { @Override public void invalidated() { specularPowerDirty = true; setDirty(true); } }; } return specularPower; } private final AbstractNotifyListener platformImageChangeListener = new AbstractNotifyListener() { @Override public void invalidated(Observable valueModel) { if (oldDiffuseMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldDiffuseMap)) { diffuseMapDirty = true; } else if (oldSpecularMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldSpecularMap)) { specularMapDirty = true; } else if (oldBumpMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldBumpMap)) { bumpMapDirty = true; } else if (oldSelfIlluminationMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldSelfIlluminationMap)) { selfIlluminationMapDirty = true; } setDirty(true); } }; /** * The diffuse map of this {@code PhongMaterial}. * * @defaultValue {@code null} */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty diffuseMap; public final void setDiffuseMap(Image value) { diffuseMapProperty().set(value); } public final Image getDiffuseMap() { return diffuseMap == null ? null : diffuseMap.get(); } private Image oldDiffuseMap; public final ObjectProperty diffuseMapProperty() { if (diffuseMap == null) { diffuseMap = new SimpleObjectProperty<>(PhongMaterial.this, "diffuseMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldDiffuseMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldDiffuseMap = _image; diffuseMapDirty = true; setDirty(true); } }; } return diffuseMap; } /** * The specular map of this {@code PhongMaterial}. * * @defaultValue {@code null} */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty specularMap; public final void setSpecularMap(Image value) { specularMapProperty().set(value); } public final Image getSpecularMap() { return specularMap == null ? null : specularMap.get(); } private Image oldSpecularMap; public final ObjectProperty specularMapProperty() { if (specularMap == null) { specularMap = new SimpleObjectProperty<>(PhongMaterial.this, "specularMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldSpecularMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldSpecularMap = _image; specularMapDirty = true; setDirty(true); } }; } return specularMap; } /** * The bump map of this {@code PhongMaterial}, which is a normal map stored as an RGB image. * * @defaultValue {@code null} */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty bumpMap; public final void setBumpMap(Image value) { bumpMapProperty().set(value); } public final Image getBumpMap() { return bumpMap == null ? null : bumpMap.get(); } private Image oldBumpMap; public final ObjectProperty bumpMapProperty() { if (bumpMap == null) { bumpMap = new SimpleObjectProperty<>(PhongMaterial.this, "bumpMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldBumpMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldBumpMap = _image; bumpMapDirty = true; setDirty(true); } }; } return bumpMap; } /** * The self illumination map of this {@code PhongMaterial}. * * @defaultValue {@code null} */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty selfIlluminationMap; public final void setSelfIlluminationMap(Image value) { selfIlluminationMapProperty().set(value); } public final Image getSelfIlluminationMap() { return selfIlluminationMap == null ? null : selfIlluminationMap.get(); } private Image oldSelfIlluminationMap; public final ObjectProperty selfIlluminationMapProperty() { if (selfIlluminationMap == null) { selfIlluminationMap = new SimpleObjectProperty<>(PhongMaterial.this, "selfIlluminationMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldSelfIlluminationMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldSelfIlluminationMap = _image; selfIlluminationMapDirty = true; setDirty(true); } }; } return selfIlluminationMap; } @Override void setDirty(boolean value) { super.setDirty(value); if (!value) { diffuseColorDirty = false; specularColorDirty = false; specularPowerDirty = false; diffuseMapDirty = false; specularMapDirty = false; bumpMapDirty = false; selfIlluminationMapDirty = false; } } /** The peer node created by the graphics Toolkit/Pipeline implementation */ private NGPhongMaterial peer; @Override NGPhongMaterial getNGMaterial() { if (peer == null) { peer = new NGPhongMaterial(); } return peer; } @Override void updatePG() { if (!isDirty()) { return; } final NGPhongMaterial pMaterial = MaterialHelper.getNGMaterial(this); if (diffuseColorDirty) { pMaterial.setDiffuseColor(getDiffuseColor() == null ? null : Toolkit.getPaintAccessor().getPlatformPaint(getDiffuseColor())); } if (specularColorDirty) { pMaterial.setSpecularColor(getSpecularColor() == null ? null : Toolkit.getPaintAccessor().getPlatformPaint(getSpecularColor())); } if (specularPowerDirty) { pMaterial.setSpecularPower((float)getSpecularPower()); } if (diffuseMapDirty) { pMaterial.setDiffuseMap(getDiffuseMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getDiffuseMap())); } if (specularMapDirty) { pMaterial.setSpecularMap(getSpecularMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getSpecularMap())); } if (bumpMapDirty) { pMaterial.setBumpMap(getBumpMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getBumpMap())); } if (selfIlluminationMapDirty) { pMaterial.setSelfIllumMap(getSelfIlluminationMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getSelfIlluminationMap())); } setDirty(false); } @Override public String toString() { return "PhongMaterial[" + "diffuseColor=" + getDiffuseColor() + ", specularColor=" + getSpecularColor() + ", specularPower=" + getSpecularPower() + ", diffuseMap=" + getDiffuseMap() + ", specularMap=" + getSpecularMap() + ", bumpMap=" + getBumpMap() + ", selfIlluminationMap=" + getSelfIlluminationMap() + "]"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy