- Added SpotLight light type.
- Implemented spot light shading for lighting (pixel and vertex lighting) and terrain shader git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7893 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
41f417570d
commit
99a4b00c15
@ -52,8 +52,9 @@ uniform float m_Shininess;
|
||||
|
||||
#ifdef HQ_ATTENUATION
|
||||
uniform vec4 g_LightPosition;
|
||||
varying vec3 lightVec;
|
||||
#endif
|
||||
varying vec4 lightVec;
|
||||
varying vec4 spotVec;
|
||||
|
||||
#ifdef USE_REFLECTION
|
||||
uniform float m_ReflectionPower;
|
||||
@ -124,7 +125,7 @@ vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec3 w
|
||||
|
||||
void main(){
|
||||
vec2 newTexCoord;
|
||||
|
||||
|
||||
#if defined(PARALLAXMAP) || defined(NORMALMAP_PARALLAX)
|
||||
float h;
|
||||
#ifdef PARALLAXMAP
|
||||
@ -146,6 +147,23 @@ void main(){
|
||||
#else
|
||||
vec4 diffuseColor = vec4(1.0);
|
||||
#endif
|
||||
#ifndef VERTEX_LIGHTING
|
||||
float spotFallOff = 1.0;
|
||||
if(spotVec.w!=0){
|
||||
vec3 L=normalize(lightVec.xyz);
|
||||
vec3 spotdir = normalize(spotVec.xyz);
|
||||
float curAngleCos = dot(-L, spotdir);
|
||||
float innerAngleCos = spotVec.w;
|
||||
float outerAngleCos = lightVec.w;
|
||||
float innerMinusOuter = innerAngleCos - outerAngleCos;
|
||||
spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0);
|
||||
if(spotFallOff<=0.0){
|
||||
gl_FragColor = AmbientSum * diffuseColor;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
float alpha = DiffuseSum.a * diffuseColor.a;
|
||||
#ifdef ALPHAMAP
|
||||
alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r;
|
||||
@ -202,7 +220,7 @@ void main(){
|
||||
vec4 lightDir = vLightDir;
|
||||
lightDir.xyz = normalize(lightDir.xyz);
|
||||
|
||||
vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz);
|
||||
vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz) * spotFallOff;
|
||||
#ifdef COLORRAMP
|
||||
diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
|
||||
specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
|
||||
|
@ -13,6 +13,7 @@ uniform float m_Shininess;
|
||||
|
||||
uniform vec4 g_LightColor;
|
||||
uniform vec4 g_LightPosition;
|
||||
uniform vec4 g_LightDirection;
|
||||
uniform vec4 g_AmbientLightColor;
|
||||
|
||||
varying vec2 texCoord;
|
||||
@ -29,9 +30,8 @@ attribute vec3 inPosition;
|
||||
attribute vec2 inTexCoord;
|
||||
attribute vec3 inNormal;
|
||||
|
||||
#ifdef HQ_ATTENUATION
|
||||
varying vec3 lightVec;
|
||||
#endif
|
||||
varying vec4 lightVec;
|
||||
varying vec4 spotVec;
|
||||
|
||||
#ifdef VERTEX_COLOR
|
||||
attribute vec4 inColor;
|
||||
@ -45,7 +45,7 @@ attribute vec3 inNormal;
|
||||
#endif
|
||||
varying vec3 vPosition;
|
||||
varying vec3 vViewDir;
|
||||
varying vec4 vLightDir;
|
||||
varying vec4 vLightDir;
|
||||
#endif
|
||||
|
||||
#ifdef USE_REFLECTION
|
||||
@ -81,13 +81,11 @@ attribute vec3 inNormal;
|
||||
void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){
|
||||
float posLight = step(0.5, color.w);
|
||||
vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
|
||||
lightVec.xyz = tempVec;
|
||||
#ifdef ATTENUATION
|
||||
float dist = length(tempVec);
|
||||
lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
|
||||
lightDir.xyz = tempVec / vec3(dist);
|
||||
#ifdef HQ_ATTENUATION
|
||||
lightVec = tempVec;
|
||||
#endif
|
||||
#else
|
||||
lightDir = vec4(normalize(tempVec), 1.0);
|
||||
#endif
|
||||
@ -113,11 +111,20 @@ void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4
|
||||
vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec4 wvLightPos){
|
||||
vec4 lightDir;
|
||||
lightComputeDir(wvPos, g_LightColor, wvLightPos, lightDir);
|
||||
|
||||
float spotFallOff = 1.0;
|
||||
if(spotVec.w!=0){
|
||||
vec3 L=normalize(lightVec.xyz);
|
||||
vec3 spotdir = normalize(spotVec.xyz);
|
||||
float curAngleCos = dot(-L, spotdir);
|
||||
float innerAngleCos = spotVec.w;
|
||||
float outerAngleCos = lightVec.w;
|
||||
float innerMinusOuter = innerAngleCos - outerAngleCos;
|
||||
spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0);
|
||||
}
|
||||
float diffuseFactor = lightComputeDiffuse(wvNorm, lightDir.xyz);
|
||||
float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, lightDir.xyz, m_Shininess);
|
||||
//specularFactor *= step(0.01, diffuseFactor);
|
||||
return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w);
|
||||
return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w)*spotFallOff;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -132,13 +139,13 @@ void main(){
|
||||
vec3 wvPosition = (g_WorldViewMatrix * pos).xyz;
|
||||
vec3 wvNormal = normalize(g_NormalMatrix * inNormal);
|
||||
vec3 viewDir = normalize(-wvPosition);
|
||||
|
||||
|
||||
//vec4 lightColor = g_LightColor[gl_InstanceID];
|
||||
//vec4 lightPos = g_LightPosition[gl_InstanceID];
|
||||
//vec4 wvLightPos = (g_ViewMatrix * vec4(lightPos.xyz, lightColor.w));
|
||||
//wvLightPos.w = lightPos.w;
|
||||
|
||||
vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz, g_LightColor.w));
|
||||
vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0)));
|
||||
wvLightPos.w = g_LightPosition.w;
|
||||
vec4 lightColor = g_LightColor;
|
||||
|
||||
@ -166,6 +173,11 @@ void main(){
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//computing spot direction in view space and unpacking spotlight cos
|
||||
spotVec=(g_ViewMatrix *vec4(g_LightDirection.xyz,0.0) );
|
||||
spotVec.w=floor(g_LightDirection.w)*0.001;
|
||||
lightVec.w = fract(g_LightDirection.w);
|
||||
|
||||
lightColor.w = 1.0;
|
||||
#ifdef MATERIAL_COLORS
|
||||
AmbientSum = m_Ambient * g_AmbientLightColor;
|
||||
|
@ -29,7 +29,6 @@
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.light;
|
||||
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
@ -55,13 +54,14 @@ public class PointLight extends Light {
|
||||
|
||||
protected Vector3f position = new Vector3f();
|
||||
protected float radius = 0;
|
||||
protected float invRadius = 0;
|
||||
|
||||
@Override
|
||||
public void computeLastDistance(Spatial owner) {
|
||||
if (owner.getWorldBound() != null){
|
||||
if (owner.getWorldBound() != null) {
|
||||
BoundingVolume bv = owner.getWorldBound();
|
||||
lastDistance = bv.distanceSquaredTo(position);
|
||||
}else{
|
||||
} else {
|
||||
lastDistance = owner.getWorldTranslation().distanceSquared(position);
|
||||
}
|
||||
}
|
||||
@ -82,7 +82,7 @@ public class PointLight extends Light {
|
||||
*
|
||||
* @param position the world space position of the light.
|
||||
*/
|
||||
public void setPosition(Vector3f position){
|
||||
public void setPosition(Vector3f position) {
|
||||
this.position.set(position);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ public class PointLight extends Light {
|
||||
*
|
||||
* @return the radius of the light
|
||||
*/
|
||||
public float getRadius(){
|
||||
public float getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
@ -109,11 +109,24 @@ public class PointLight extends Light {
|
||||
*
|
||||
* @throws IllegalArgumentException If radius is negative
|
||||
*/
|
||||
public void setRadius(float radius){
|
||||
public void setRadius(float radius) {
|
||||
if (radius < 0) {
|
||||
throw new IllegalArgumentException("Light radius cannot be negative");
|
||||
}
|
||||
this.radius = radius;
|
||||
if(radius!=0){
|
||||
this.invRadius = 1 / radius;
|
||||
}else{
|
||||
this.invRadius = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for internal use only
|
||||
* @return the inverse of the radius
|
||||
*/
|
||||
public float getInvRadius() {
|
||||
return invRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,6 +148,10 @@ public class PointLight extends Light {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
position = (Vector3f) ic.readSavable("position", null);
|
||||
radius = ic.readFloat("radius", 0f);
|
||||
if(radius!=0){
|
||||
this.invRadius = 1 / radius;
|
||||
}else{
|
||||
this.invRadius = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
222
engine/src/core/com/jme3/light/SpotLight.java
Normal file
222
engine/src/core/com/jme3/light/SpotLight.java
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.light;
|
||||
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
import com.jme3.export.InputCapsule;
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
import com.jme3.export.OutputCapsule;
|
||||
import com.jme3.export.Savable;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Spatial;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents a spot light.
|
||||
* A spot light emmit a cone of light from a position and in a direction.
|
||||
* It can be used to fake torch lights or car's lights.
|
||||
* <p>
|
||||
* In addition to a position and a direction, spot lights also have a range which
|
||||
* can be used to attenuate the influence of the light depending on the
|
||||
* distance between the light and the effected object.
|
||||
* Also the angle of the cone can be tweaked by changing the spot inner angle and the spot outer angle.
|
||||
* the spot inner angle determin the cone of light where light has full influence.
|
||||
* the spot outer angle determin the cone global cone of light of the spot light.
|
||||
* the light intensity slowly decrease between the inner cone and the outer cone.
|
||||
* @author Nehon
|
||||
*/
|
||||
public class SpotLight extends Light implements Savable {
|
||||
|
||||
protected Vector3f position = new Vector3f();
|
||||
protected Vector3f direction = new Vector3f(0,-1,0);
|
||||
protected float spotInnerAngle = FastMath.QUARTER_PI / 8;
|
||||
protected float spotOuterAngle = FastMath.QUARTER_PI / 6;
|
||||
protected float spotRange = 100;
|
||||
protected float invSpotRange = 1 / 100;
|
||||
protected float packedAngleCos=0;
|
||||
|
||||
public SpotLight() {
|
||||
super();
|
||||
computePackedCos();
|
||||
}
|
||||
|
||||
private void computePackedCos() {
|
||||
float innerCos=FastMath.cos(spotInnerAngle);
|
||||
float outerCos=FastMath.cos(spotOuterAngle);
|
||||
packedAngleCos=(int)(innerCos*1000);
|
||||
packedAngleCos+=outerCos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeLastDistance(Spatial owner) {
|
||||
if (owner.getWorldBound() != null) {
|
||||
BoundingVolume bv = owner.getWorldBound();
|
||||
lastDistance = bv.distanceSquaredTo(position);
|
||||
} else {
|
||||
lastDistance = owner.getWorldTranslation().distanceSquared(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.Spot;
|
||||
}
|
||||
|
||||
public Vector3f getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Vector3f direction) {
|
||||
this.direction.set(direction);
|
||||
}
|
||||
|
||||
public Vector3f getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(Vector3f position) {
|
||||
this.position.set(position);
|
||||
}
|
||||
|
||||
public float getSpotRange() {
|
||||
return spotRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range of the light influence.
|
||||
* <p>
|
||||
* Setting a non-zero range indicates the light should use attenuation.
|
||||
* If a pixel's distance to this light's position
|
||||
* is greater than the light's range, then the pixel will not be
|
||||
* effected by this light, if the distance is less than the range, then
|
||||
* the magnitude of the influence is equal to distance / range.
|
||||
*
|
||||
* @param spotRange the range of the light influence.
|
||||
*
|
||||
* @throws IllegalArgumentException If spotRange is negative
|
||||
*/
|
||||
public void setSpotRange(float spotRange) {
|
||||
if (spotRange < 0) {
|
||||
throw new IllegalArgumentException("SpotLight range cannot be negative");
|
||||
}
|
||||
this.spotRange = spotRange;
|
||||
if (spotRange != 0) {
|
||||
this.invSpotRange = 1 / spotRange;
|
||||
} else {
|
||||
this.invSpotRange = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for internal use only
|
||||
* @return the inverse of the spot range
|
||||
*/
|
||||
public float getInvSpotRange() {
|
||||
return invSpotRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the spot inner angle
|
||||
* @return the spot inner angle
|
||||
*/
|
||||
public float getSpotInnerAngle() {
|
||||
return spotInnerAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the inner angle of the cone of influence.
|
||||
* This angle is the angle between the spot direction axis and the inner border of the cone of influence.
|
||||
* @param spotInnerAngle
|
||||
*/
|
||||
public void setSpotInnerAngle(float spotInnerAngle) {
|
||||
this.spotInnerAngle = spotInnerAngle;
|
||||
computePackedCos();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the spot outer angle
|
||||
* @return the spot outer angle
|
||||
*/
|
||||
public float getSpotOuterAngle() {
|
||||
return spotOuterAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the outer angle of the cone of influence.
|
||||
* This angle is the angle between the spot direction axis and the outer border of the cone of influence.
|
||||
* this should be greater than the inner angle or the result will be unexpected.
|
||||
* @param spotOuterAngle
|
||||
*/
|
||||
public void setSpotOuterAngle(float spotOuterAngle) {
|
||||
this.spotOuterAngle = spotOuterAngle;
|
||||
computePackedCos();
|
||||
}
|
||||
|
||||
/**
|
||||
* for internal use only
|
||||
* @return the cosines of the inner and outter angle packed in a float
|
||||
*/
|
||||
public float getPackedAngleCos() {
|
||||
return packedAngleCos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
super.write(ex);
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(direction, "direction", new Vector3f());
|
||||
oc.write(position, "position", new Vector3f());
|
||||
oc.write(spotInnerAngle, "spotInnerAngle", FastMath.QUARTER_PI / 8);
|
||||
oc.write(spotOuterAngle, "spotOuterAngle", FastMath.QUARTER_PI / 6);
|
||||
oc.write(spotRange, "spotRange", 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
super.read(im);
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
spotInnerAngle = ic.readFloat("spotInnerAngle", FastMath.QUARTER_PI / 8);
|
||||
spotOuterAngle = ic.readFloat("spotOuterAngle", FastMath.QUARTER_PI / 6);
|
||||
direction = (Vector3f) ic.readSavable("direction", new Vector3f());
|
||||
position = (Vector3f) ic.readSavable("position", new Vector3f());
|
||||
spotRange = ic.readFloat("spotRange", 100);
|
||||
if (spotRange != 0) {
|
||||
this.invSpotRange = 1 / spotRange;
|
||||
} else {
|
||||
this.invSpotRange = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine All rights reserved.
|
||||
* <p/>
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* <p/>
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* <p/>
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* <p/>
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.material;
|
||||
|
||||
@ -46,7 +44,9 @@ import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.LightList;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.TechniqueDef.LightMode;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.math.Vector4f;
|
||||
@ -72,12 +72,15 @@ import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* <code>Material</code> describes the rendering style for a given
|
||||
* {@link Geometry}.
|
||||
*
|
||||
* <p>A material is essentially a list of {@link MatParam parameters}, those parameters
|
||||
* map to uniforms which are defined in a shader.
|
||||
* Setting the parameters can modify the behavior of a shader.
|
||||
*
|
||||
* {
|
||||
* <p/>
|
||||
* @link Geometry}.
|
||||
* <p/>
|
||||
* <p>A material is essentially a list of {
|
||||
* @link MatParam parameters}, those parameters map to uniforms which are
|
||||
* defined in a shader. Setting the parameters can modify the behavior of a
|
||||
* shader.
|
||||
* <p/>
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
@ -96,7 +99,6 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
additiveLight.setBlendMode(RenderState.BlendMode.AlphaAdditive);
|
||||
additiveLight.setDepthWrite(false);
|
||||
}
|
||||
|
||||
private String assetName;
|
||||
private MaterialDef def;
|
||||
private ListMap<String, MatParam> paramValues = new ListMap<String, MatParam>();
|
||||
@ -198,7 +200,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
public Material clone() {
|
||||
try {
|
||||
Material mat = (Material) super.clone();
|
||||
|
||||
|
||||
if (additionalState != null) {
|
||||
mat.additionalState = additionalState.clone();
|
||||
}
|
||||
@ -355,7 +357,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
private String checkSetParam(VarType type, String name) {
|
||||
MatParam paramDef = def.getMaterialParam(name);
|
||||
String newName = name;
|
||||
|
||||
|
||||
if (paramDef == null && name.startsWith("m_")) {
|
||||
newName = name.substring(2);
|
||||
paramDef = def.getMaterialParam(newName);
|
||||
@ -364,7 +366,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
} else {
|
||||
logger.log(Level.WARNING, "Material parameter {0} uses a deprecated naming convention use {1} instead ", new Object[]{name, newName});
|
||||
}
|
||||
}else if (paramDef == null){
|
||||
} else if (paramDef == null) {
|
||||
throw new IllegalArgumentException("Material parameter is not defined: " + name);
|
||||
}
|
||||
|
||||
@ -373,7 +375,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
+ "type {1} doesn't match definition type {2}",
|
||||
name, type.name(), paramDef.getVarType());
|
||||
}
|
||||
|
||||
|
||||
return newName;
|
||||
}
|
||||
|
||||
@ -404,9 +406,9 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
* @param name the name of the parameter to clear
|
||||
*/
|
||||
public void clearParam(String name) {
|
||||
//On removal, we don't check if the param exists in the paramDef, and just go on with the process.
|
||||
// name = checkSetParam(null, name);
|
||||
|
||||
//On removal, we don't check if the param exists in the paramDef, and just go on with the process.
|
||||
// name = checkSetParam(null, name);
|
||||
|
||||
MatParam matParam = getParam(name);
|
||||
if (matParam != null) {
|
||||
paramValues.remove(name);
|
||||
@ -435,9 +437,10 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
name = checkSetParam(null, name);
|
||||
|
||||
MatParamTexture val = getTextureParam(name);
|
||||
if (val == null)
|
||||
if (val == null) {
|
||||
throw new IllegalArgumentException("The given texture parameter is not set.");
|
||||
|
||||
}
|
||||
|
||||
int texUnit = val.getUnit();
|
||||
paramValues.remove(name);
|
||||
nextTexUnit--;
|
||||
@ -478,7 +481,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
if (technique != null) {
|
||||
technique.notifySetParam(name, type, nextTexUnit - 1);
|
||||
}
|
||||
|
||||
|
||||
// need to recompute sort ID
|
||||
sortingId = -1;
|
||||
}
|
||||
@ -492,7 +495,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
*/
|
||||
public void setTexture(String name, Texture value) {
|
||||
if (value == null) {
|
||||
// clear it
|
||||
// clear it
|
||||
clearTextureParam(name);
|
||||
return;
|
||||
}
|
||||
@ -625,21 +628,23 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
* </p>
|
||||
*/
|
||||
protected void updateLightListUniforms(Shader shader, Geometry g, int numLights) {
|
||||
if (numLights == 0){ // this shader does not do lighting, ignore.
|
||||
if (numLights == 0) { // this shader does not do lighting, ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
LightList lightList = g.getWorldLightList();
|
||||
Uniform lightColor = shader.getUniform("g_LightColor");
|
||||
Uniform lightPos = shader.getUniform("g_LightPosition");
|
||||
Uniform lightDir = shader.getUniform("g_LightDirection");
|
||||
lightColor.setVector4Length(numLights);
|
||||
lightPos.setVector4Length(numLights);
|
||||
lightPos.setVector4Length(numLights);
|
||||
lightDir.setVector4Length(numLights);
|
||||
|
||||
Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
|
||||
ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList));
|
||||
|
||||
|
||||
int lightIndex = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < numLights; i++) {
|
||||
if (lightList.size() <= i) {
|
||||
lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex);
|
||||
@ -662,12 +667,19 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
case Point:
|
||||
PointLight pl = (PointLight) l;
|
||||
Vector3f pos = pl.getPosition();
|
||||
float invRadius = pl.getRadius();
|
||||
if (invRadius != 0) {
|
||||
invRadius = 1f / invRadius;
|
||||
}
|
||||
float invRadius = pl.getInvRadius();
|
||||
lightPos.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightIndex);
|
||||
break;
|
||||
case Spot:
|
||||
SpotLight sl = (SpotLight) l;
|
||||
Vector3f pos2 = sl.getPosition();
|
||||
Vector3f dir2 = sl.getDirection();
|
||||
float invRange = sl.getInvSpotRange();
|
||||
float spotAngleCos = sl.getPackedAngleCos();
|
||||
|
||||
lightPos.setVector4InArray(pos2.getX(), pos2.getY(), pos2.getZ(), invRange, lightIndex);
|
||||
lightDir.setVector4InArray(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightIndex);
|
||||
break;
|
||||
case Ambient:
|
||||
// skip this light. Does not increase lightIndex
|
||||
continue;
|
||||
@ -675,20 +687,21 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lightIndex++;
|
||||
}
|
||||
|
||||
while (lightIndex < numLights){
|
||||
|
||||
while (lightIndex < numLights) {
|
||||
lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex);
|
||||
lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex);
|
||||
|
||||
|
||||
lightIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderMultipassLighting(Shader shader, Geometry g, Renderer r) {
|
||||
LightList lightList = g.getWorldLightList();
|
||||
Uniform lightDir = shader.getUniform("g_LightDirection");
|
||||
Uniform lightColor = shader.getUniform("g_LightColor");
|
||||
Uniform lightPos = shader.getUniform("g_LightPosition");
|
||||
Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
|
||||
@ -740,10 +753,7 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
case Point:
|
||||
PointLight pl = (PointLight) l;
|
||||
Vector3f pos = pl.getPosition();
|
||||
float invRadius = pl.getRadius();
|
||||
if (invRadius != 0) {
|
||||
invRadius = 1f / invRadius;
|
||||
}
|
||||
float invRadius = pl.getInvRadius();
|
||||
Quaternion q2;
|
||||
if (lightPos.getValue() != null) {
|
||||
q2 = (Quaternion) lightPos.getValue();
|
||||
@ -752,6 +762,31 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
}
|
||||
q2.set(pos.getX(), pos.getY(), pos.getZ(), invRadius);
|
||||
lightPos.setValue(VarType.Vector4, q2);
|
||||
break;
|
||||
case Spot:
|
||||
SpotLight sl = (SpotLight) l;
|
||||
Vector3f pos2 = sl.getPosition();
|
||||
Vector3f dir2 = sl.getDirection();
|
||||
float invRange = sl.getInvSpotRange();
|
||||
float spotAngleCos = sl.getPackedAngleCos();
|
||||
|
||||
Quaternion q3,q4;
|
||||
if (lightPos.getValue() != null) {
|
||||
q3 = (Quaternion) lightPos.getValue();
|
||||
} else {
|
||||
q3 = new Quaternion();
|
||||
}
|
||||
q3.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange);
|
||||
lightPos.setValue(VarType.Vector4, q3);
|
||||
|
||||
if (lightDir.getValue() != null) {
|
||||
q4 = (Quaternion) lightDir.getValue();
|
||||
} else {
|
||||
q4 = new Quaternion();
|
||||
}
|
||||
q4.set(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos);
|
||||
lightDir.setValue(VarType.Vector4, q4);
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
|
||||
@ -1008,41 +1043,41 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
|
||||
|
||||
additionalState = (RenderState) ic.readSavable("render_state", null);
|
||||
transparent = ic.readBoolean("is_transparent", false);
|
||||
|
||||
// Load the material def
|
||||
String defName = ic.readString("material_def", null);
|
||||
HashMap<String, MatParam> params = (HashMap<String, MatParam>) ic.readStringSavableMap("parameters", null);
|
||||
|
||||
|
||||
boolean enableVcolor = false;
|
||||
boolean separateTexCoord = false;
|
||||
|
||||
if (im.getFormatVersion() == 0){
|
||||
|
||||
if (im.getFormatVersion() == 0) {
|
||||
// Enable compatibility with old models
|
||||
if (defName.equalsIgnoreCase("Common/MatDefs/Misc/VertexColor.j3md")){
|
||||
if (defName.equalsIgnoreCase("Common/MatDefs/Misc/VertexColor.j3md")) {
|
||||
// Using VertexColor, switch to Unshaded and set VertexColor=true
|
||||
enableVcolor = true;
|
||||
defName = "Common/MatDefs/Misc/Unshaded.j3md";
|
||||
}else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/SimpleTextured.j3md")
|
||||
|| defName.equalsIgnoreCase("Common/MatDefs/Misc/SolidColor.j3md")){
|
||||
} else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/SimpleTextured.j3md")
|
||||
|| defName.equalsIgnoreCase("Common/MatDefs/Misc/SolidColor.j3md")) {
|
||||
// Using SimpleTextured/SolidColor, just switch to Unshaded
|
||||
defName = "Common/MatDefs/Misc/Unshaded.j3md";
|
||||
}else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/WireColor.j3md")){
|
||||
} else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/WireColor.j3md")) {
|
||||
// Using WireColor, set wireframe renderstate = true and use Unshaded
|
||||
getAdditionalRenderState().setWireframe(true);
|
||||
defName = "Common/MatDefs/Misc/Unshaded.j3md";
|
||||
}else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/Unshaded.j3md")){
|
||||
} else if (defName.equalsIgnoreCase("Common/MatDefs/Misc/Unshaded.j3md")) {
|
||||
// Uses unshaded, ensure that the proper param is set
|
||||
MatParam value = params.get("SeperateTexCoord");
|
||||
if (value != null && ((Boolean)value.getValue()) == true){
|
||||
if (value != null && ((Boolean) value.getValue()) == true) {
|
||||
params.remove("SeperateTexCoord");
|
||||
separateTexCoord = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def = (MaterialDef) im.getAssetManager().loadAsset(new AssetKey(defName));
|
||||
paramValues = new ListMap<String, MatParam>();
|
||||
|
||||
@ -1065,12 +1100,12 @@ public class Material implements Cloneable, Savable, Comparable<Material> {
|
||||
param.setName(checkSetParam(param.getVarType(), param.getName()));
|
||||
paramValues.put(param.getName(), param);
|
||||
}
|
||||
|
||||
if (enableVcolor){
|
||||
|
||||
if (enableVcolor) {
|
||||
setBoolean("VertexColor", true);
|
||||
}
|
||||
if (separateTexCoord){
|
||||
if (separateTexCoord) {
|
||||
setBoolean("SeparateTexCoord", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ varying vec3 vnPosition;
|
||||
varying vec3 vViewDir;
|
||||
varying vec4 vLightDir;
|
||||
varying vec4 vnLightDir;
|
||||
varying vec4 lightVec;
|
||||
varying vec4 spotVec;
|
||||
|
||||
|
||||
#ifdef DIFFUSEMAP
|
||||
@ -644,6 +646,20 @@ void main(){
|
||||
vec4 diffuseColor = vec4(1.0);
|
||||
#endif
|
||||
|
||||
float spotFallOff = 1.0;
|
||||
if(spotVec.w!=0){
|
||||
vec3 L=normalize(lightVec.xyz);
|
||||
vec3 spotdir = normalize(spotVec.xyz);
|
||||
float curAngleCos = dot(-L, spotdir);
|
||||
float innerAngleCos = spotVec.w;
|
||||
float outerAngleCos = lightVec.w;
|
||||
float innerMinusOuter = innerAngleCos - outerAngleCos;
|
||||
spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0);
|
||||
if(spotFallOff<=0.0){
|
||||
gl_FragColor = AmbientSum * diffuseColor;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------
|
||||
// normal calculations
|
||||
@ -665,7 +681,7 @@ void main(){
|
||||
vec4 lightDir = vLightDir;
|
||||
lightDir.xyz = normalize(lightDir.xyz);
|
||||
|
||||
vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz);
|
||||
vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz)*spotFallOff;
|
||||
|
||||
vec4 specularColor = vec4(1.0);
|
||||
|
||||
|
@ -5,6 +5,7 @@ uniform mat4 g_ViewMatrix;
|
||||
|
||||
uniform vec4 g_LightColor;
|
||||
uniform vec4 g_LightPosition;
|
||||
uniform vec4 g_LightDirection;
|
||||
uniform vec4 g_AmbientLightColor;
|
||||
|
||||
uniform float m_Shininess;
|
||||
@ -23,6 +24,9 @@ varying vec3 vnViewDir;
|
||||
varying vec4 vLightDir;
|
||||
varying vec4 vnLightDir;
|
||||
|
||||
varying vec4 lightVec;
|
||||
varying vec4 spotVec;
|
||||
|
||||
varying vec4 AmbientSum;
|
||||
varying vec4 DiffuseSum;
|
||||
varying vec4 SpecularSum;
|
||||
@ -38,7 +42,7 @@ varying vec4 SpecularSum;
|
||||
void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){
|
||||
float posLight = step(0.5, color.w);
|
||||
vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
|
||||
|
||||
lightVec.xyz = tempVec;
|
||||
float dist = length(tempVec);
|
||||
lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
|
||||
lightDir.xyz = tempVec / vec3(dist);
|
||||
@ -54,7 +58,7 @@ void main(){
|
||||
vec3 wvNormal = normalize(g_NormalMatrix * inNormal);
|
||||
vec3 viewDir = normalize(-wvPosition);
|
||||
|
||||
vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz, g_LightColor.w));
|
||||
vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0)));
|
||||
wvLightPos.w = g_LightPosition.w;
|
||||
vec4 lightColor = g_LightColor;
|
||||
|
||||
@ -84,6 +88,11 @@ void main(){
|
||||
lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir);
|
||||
|
||||
#endif
|
||||
|
||||
//computing spot direction in view space and unpacking spotlight cos
|
||||
spotVec=(g_ViewMatrix *vec4(g_LightDirection.xyz,0.0) );
|
||||
spotVec.w=floor(g_LightDirection.w)*0.001;
|
||||
lightVec.w = fract(g_LightDirection.w);
|
||||
|
||||
AmbientSum = vec4(0.2, 0.2, 0.2, 1.0) * g_AmbientLightColor; // Default: ambient color is dark gray
|
||||
DiffuseSum = lightColor;
|
||||
|
159
engine/src/test/jme3test/light/TestSpotLight.java
Normal file
159
engine/src/test/jme3test/light/TestSpotLight.java
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jme3test.light;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.light.AmbientLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector2f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.scene.shape.Sphere;
|
||||
import com.jme3.texture.Texture.WrapMode;
|
||||
import com.jme3.util.TangentBinormalGenerator;
|
||||
|
||||
public class TestSpotLight extends SimpleApplication {
|
||||
|
||||
private Vector3f lightTarget = new Vector3f(12, 3.5f, 30);
|
||||
|
||||
public static void main(String[] args){
|
||||
TestSpotLight app = new TestSpotLight();
|
||||
app.start();
|
||||
}
|
||||
|
||||
SpotLight spot;
|
||||
Geometry lightMdl;
|
||||
public void setupLighting(){
|
||||
AmbientLight al=new AmbientLight();
|
||||
al.setColor(ColorRGBA.White.mult(0.8f));
|
||||
rootNode.addLight(al);
|
||||
|
||||
spot=new SpotLight();
|
||||
|
||||
spot.setSpotRange(1000);
|
||||
spot.setSpotInnerAngle(5*FastMath.DEG_TO_RAD);
|
||||
spot.setSpotOuterAngle(10*FastMath.DEG_TO_RAD);
|
||||
spot.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
|
||||
spot.setDirection(lightTarget.subtract(spot.getPosition()));
|
||||
spot.setColor(ColorRGBA.White.mult(2));
|
||||
rootNode.addLight(spot);
|
||||
|
||||
|
||||
// PointLight pl=new PointLight();
|
||||
// pl.setPosition(new Vector3f(77.70334f, 34.013165f, 27.1017f));
|
||||
// pl.setRadius(1000);
|
||||
// pl.setColor(ColorRGBA.White.mult(2));
|
||||
// rootNode.addLight(pl);
|
||||
lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
|
||||
lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
|
||||
lightMdl.setLocalTranslation(new Vector3f(77.70334f, 34.013165f, 27.1017f));
|
||||
lightMdl.setLocalScale(5);
|
||||
rootNode.attachChild(lightMdl);
|
||||
|
||||
// DirectionalLight dl = new DirectionalLight();
|
||||
// dl.setDirection(lightTarget.subtract(new Vector3f(77.70334f, 34.013165f, 27.1017f)));
|
||||
// dl.setColor(ColorRGBA.White.mult(2));
|
||||
// rootNode.addLight(dl);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void setupFloor(){
|
||||
Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
|
||||
mat.getTextureParam("DiffuseMap").getTextureValue().setWrap(WrapMode.Repeat);
|
||||
mat.getTextureParam("NormalMap").getTextureValue().setWrap(WrapMode.Repeat);
|
||||
// mat.getTextureParam("ParallaxMap").getTextureValue().setWrap(WrapMode.Repeat);
|
||||
mat.setFloat("Shininess",3);
|
||||
// mat.setBoolean("VertexLighting", true);
|
||||
|
||||
|
||||
Box floor = new Box(Vector3f.ZERO, 50, 1f, 50);
|
||||
TangentBinormalGenerator.generate(floor);
|
||||
floor.scaleTextureCoordinates(new Vector2f(5, 5));
|
||||
Geometry floorGeom = new Geometry("Floor", floor);
|
||||
floorGeom.setMaterial(mat);
|
||||
floorGeom.setShadowMode(ShadowMode.Receive);
|
||||
rootNode.attachChild(floorGeom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setupSignpost(){
|
||||
Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
|
||||
Material mat = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
|
||||
// mat.setBoolean("VertexLighting", true);
|
||||
signpost.setMaterial(mat);
|
||||
signpost.rotate(0, FastMath.HALF_PI, 0);
|
||||
signpost.setLocalTranslation(12, 3.5f, 30);
|
||||
signpost.setLocalScale(4);
|
||||
signpost.setShadowMode(ShadowMode.CastAndReceive);
|
||||
TangentBinormalGenerator.generate(signpost);
|
||||
rootNode.attachChild(signpost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
cam.setLocation(new Vector3f(27.492603f, 29.138166f, -13.232513f));
|
||||
cam.setRotation(new Quaternion(0.25168246f, -0.10547892f, 0.02760565f, 0.96164864f));
|
||||
flyCam.setMoveSpeed(30);
|
||||
|
||||
setupLighting();
|
||||
setupFloor();
|
||||
setupSignpost();
|
||||
|
||||
|
||||
}
|
||||
|
||||
float angle;
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(float tpf) {
|
||||
super.simpleUpdate(tpf);
|
||||
angle += tpf;
|
||||
angle %= FastMath.TWO_PI;
|
||||
|
||||
spot.setPosition(new Vector3f(FastMath.cos(angle) * 30f, 34.013165f, FastMath.sin(angle) * 30f));
|
||||
lightMdl.setLocalTranslation(spot.getPosition());
|
||||
spot.setDirection(lightTarget.subtract(spot.getPosition()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
219
engine/src/test/jme3test/light/TestSpotLightTerrain.java
Normal file
219
engine/src/test/jme3test/light/TestSpotLightTerrain.java
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jme3test.light;
|
||||
|
||||
import jme3tools.converters.ImageToAwt;
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.bounding.BoundingBox;
|
||||
import com.jme3.font.BitmapText;
|
||||
import com.jme3.input.KeyInput;
|
||||
import com.jme3.input.controls.ActionListener;
|
||||
import com.jme3.input.controls.KeyTrigger;
|
||||
import com.jme3.light.AmbientLight;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.shape.Sphere;
|
||||
import com.jme3.terrain.geomipmap.TerrainLodControl;
|
||||
import com.jme3.terrain.heightmap.AbstractHeightMap;
|
||||
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
|
||||
import com.jme3.terrain.geomipmap.TerrainQuad;
|
||||
import com.jme3.texture.Texture;
|
||||
import com.jme3.texture.Texture.WrapMode;
|
||||
import com.jme3.util.SkyFactory;
|
||||
|
||||
/**
|
||||
* Uses the terrain's lighting texture with normal maps and lights.
|
||||
*
|
||||
* @author bowens
|
||||
*/
|
||||
public class TestSpotLightTerrain extends SimpleApplication {
|
||||
|
||||
private TerrainQuad terrain;
|
||||
Material matTerrain;
|
||||
Material matWire;
|
||||
boolean wireframe = false;
|
||||
boolean triPlanar = false;
|
||||
boolean wardiso = false;
|
||||
boolean minnaert = false;
|
||||
protected BitmapText hintText;
|
||||
PointLight pl;
|
||||
Geometry lightMdl;
|
||||
private float grassScale = 64;
|
||||
private float dirtScale = 16;
|
||||
private float rockScale = 128;
|
||||
SpotLight sl;
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestSpotLightTerrain app = new TestSpotLightTerrain();
|
||||
app.start();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
makeTerrain();
|
||||
flyCam.setMoveSpeed(50);
|
||||
|
||||
sl = new SpotLight();
|
||||
sl.setSpotRange(100);
|
||||
sl.setSpotOuterAngle(20 * FastMath.DEG_TO_RAD);
|
||||
sl.setSpotInnerAngle(15 * FastMath.DEG_TO_RAD);
|
||||
sl.setDirection(new Vector3f(-0.39820394f, -0.73094344f, 0.55421597f));
|
||||
sl.setPosition(new Vector3f(-64.61567f, -87.615425f, -202.41328f));
|
||||
rootNode.addLight(sl);
|
||||
|
||||
AmbientLight ambLight = new AmbientLight();
|
||||
ambLight.setColor(new ColorRGBA(0.8f, 0.8f, 0.8f, 0.2f));
|
||||
rootNode.addLight(ambLight);
|
||||
|
||||
cam.setLocation(new Vector3f(-41.219646f, -84.8363f, -171.67267f));
|
||||
cam.setRotation(new Quaternion(-0.04562731f, 0.89917684f, -0.09668826f, -0.4243236f));
|
||||
sl.setDirection(cam.getDirection());
|
||||
sl.setPosition(cam.getLocation());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(float tpf) {
|
||||
super.simpleUpdate(tpf);
|
||||
sl.setDirection(cam.getDirection());
|
||||
sl.setPosition(cam.getLocation());
|
||||
|
||||
}
|
||||
|
||||
private void makeTerrain() {
|
||||
// TERRAIN TEXTURE material
|
||||
matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
|
||||
matTerrain.setBoolean("useTriPlanarMapping", false);
|
||||
matTerrain.setBoolean("WardIso", true);
|
||||
|
||||
// ALPHA map (for splat textures)
|
||||
matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
|
||||
matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
|
||||
|
||||
// HEIGHTMAP image (for the terrain heightmap)
|
||||
Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");
|
||||
|
||||
|
||||
// GRASS texture
|
||||
Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
|
||||
grass.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("DiffuseMap", grass);
|
||||
matTerrain.setFloat("DiffuseMap_0_scale", grassScale);
|
||||
|
||||
// DIRT texture
|
||||
Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
|
||||
dirt.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("DiffuseMap_1", dirt);
|
||||
matTerrain.setFloat("DiffuseMap_1_scale", dirtScale);
|
||||
|
||||
// ROCK texture
|
||||
Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
|
||||
rock.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("DiffuseMap_2", rock);
|
||||
matTerrain.setFloat("DiffuseMap_2_scale", rockScale);
|
||||
|
||||
// BRICK texture
|
||||
Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg");
|
||||
brick.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("DiffuseMap_3", brick);
|
||||
matTerrain.setFloat("DiffuseMap_3_scale", rockScale);
|
||||
|
||||
// RIVER ROCK texture
|
||||
Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.png");
|
||||
riverRock.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("DiffuseMap_4", riverRock);
|
||||
matTerrain.setFloat("DiffuseMap_4_scale", rockScale);
|
||||
|
||||
|
||||
Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
|
||||
normalMap0.setWrap(WrapMode.Repeat);
|
||||
Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
|
||||
normalMap1.setWrap(WrapMode.Repeat);
|
||||
Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
|
||||
normalMap2.setWrap(WrapMode.Repeat);
|
||||
matTerrain.setTexture("NormalMap", normalMap0);
|
||||
matTerrain.setTexture("NormalMap_1", normalMap2);
|
||||
matTerrain.setTexture("NormalMap_2", normalMap2);
|
||||
matTerrain.setTexture("NormalMap_4", normalMap2);
|
||||
|
||||
// WIREFRAME material
|
||||
matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
matWire.getAdditionalRenderState().setWireframe(true);
|
||||
matWire.setColor("Color", ColorRGBA.Green);
|
||||
|
||||
createSky();
|
||||
|
||||
// CREATE HEIGHTMAP
|
||||
AbstractHeightMap heightmap = null;
|
||||
try {
|
||||
//heightmap = new HillHeightMap(1025, 1000, 50, 100, (byte) 3);
|
||||
|
||||
heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0), 1f);
|
||||
heightmap.load();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
|
||||
TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
|
||||
terrain.addControl(control);
|
||||
terrain.setMaterial(matTerrain);
|
||||
terrain.setModelBound(new BoundingBox());
|
||||
terrain.updateModelBound();
|
||||
terrain.setLocalTranslation(0, -100, 0);
|
||||
terrain.setLocalScale(1f, 1f, 1f);
|
||||
rootNode.attachChild(terrain);
|
||||
}
|
||||
|
||||
private void createSky() {
|
||||
Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg");
|
||||
Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg");
|
||||
Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg");
|
||||
Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg");
|
||||
Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg");
|
||||
Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg");
|
||||
|
||||
Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
|
||||
rootNode.attachChild(sky);
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user