├── assets
└── MatDefs
│ ├── Grass.frag
│ ├── Grass.j3md
│ ├── Grass.vert
│ ├── TrilinearLighting.frag
│ ├── TrilinearLighting.j3md
│ └── TrilinearLighting.vert
├── build.xml
├── nbproject
├── assets-impl.xml
├── build-impl.xml
├── genfiles.properties
├── project.properties
└── project.xml
└── src
└── main
└── java
├── com
└── simsilica
│ └── iso
│ ├── DensityVolume.java
│ ├── IsoTerrainZone.java
│ ├── IsoTerrainZoneFactory.java
│ ├── MeshGenerator.java
│ ├── collision
│ ├── Collider.java
│ ├── Contact.java
│ └── SimpleVolumeCollider.java
│ ├── fractal
│ ├── GemsFractalDensityVolume.java
│ └── PerlinNoise.java
│ ├── mc
│ ├── MarchingCubesConstants.java
│ └── MarchingCubesMeshGenerator.java
│ ├── plot
│ ├── BatchInstance.java
│ ├── BatchTemplate.java
│ ├── GrassZone.java
│ ├── InstanceTemplate.java
│ ├── InstancedTreeZone.java
│ ├── PlotFrequencyZone.java
│ └── TreeZone.java
│ ├── tri
│ ├── Triangle.java
│ ├── TriangleProcessor.java
│ └── TriangleUtils.java
│ ├── util
│ ├── BilinearArray.java
│ ├── MatrixUtils.java
│ └── MeshCompareUtil.java
│ └── volume
│ ├── ArrayDensityVolume.java
│ ├── CachingDensityVolume.java
│ └── ResamplingVolume.java
└── license.txt
/assets/MatDefs/Grass.frag:
--------------------------------------------------------------------------------
1 | #import "Common/ShaderLib/Parallax.glsllib"
2 | #import "Common/ShaderLib/Optics.glsllib"
3 | #define ATTENUATION
4 | //#define HQ_ATTENUATION
5 |
6 | varying vec2 texCoord;
7 | #ifdef SEPARATE_TEXCOORD
8 | varying vec2 texCoord2;
9 | #endif
10 |
11 | varying vec3 AmbientSum;
12 | varying vec4 DiffuseSum;
13 | varying vec3 SpecularSum;
14 |
15 | varying float vDistance;
16 |
17 |
18 | #ifndef VERTEX_LIGHTING
19 | uniform vec4 g_LightDirection;
20 | //varying vec3 vPosition;
21 | varying vec3 vViewDir;
22 | varying vec4 vLightDir;
23 | varying vec3 lightVec;
24 | #else
25 | varying vec2 vertexLightValues;
26 | #endif
27 |
28 | #ifdef DIFFUSEMAP
29 | uniform sampler2D m_DiffuseMap;
30 | #endif
31 |
32 | #ifdef SPECULARMAP
33 | uniform sampler2D m_SpecularMap;
34 | #endif
35 |
36 | #ifdef PARALLAXMAP
37 | uniform sampler2D m_ParallaxMap;
38 | #endif
39 | #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
40 | uniform float m_ParallaxHeight;
41 | #endif
42 |
43 | #ifdef LIGHTMAP
44 | uniform sampler2D m_LightMap;
45 | #endif
46 |
47 | #ifdef NORMALMAP
48 | uniform sampler2D m_NormalMap;
49 | #else
50 | varying vec3 vNormal;
51 | #endif
52 |
53 | #ifdef ALPHAMAP
54 | uniform sampler2D m_AlphaMap;
55 | #endif
56 |
57 | #ifdef COLORRAMP
58 | uniform sampler2D m_ColorRamp;
59 | #endif
60 |
61 | uniform float m_AlphaDiscardThreshold;
62 |
63 | uniform float m_DistanceFalloff;
64 |
65 | #ifndef VERTEX_LIGHTING
66 | uniform float m_Shininess;
67 |
68 | #ifdef HQ_ATTENUATION
69 | uniform vec4 g_LightPosition;
70 | #endif
71 |
72 | #ifdef USE_REFLECTION
73 | uniform float m_ReflectionPower;
74 | uniform float m_ReflectionIntensity;
75 | varying vec4 refVec;
76 |
77 | uniform ENVMAP m_EnvMap;
78 | #endif
79 |
80 | float tangDot(in vec3 v1, in vec3 v2){
81 | float d = dot(v1,v2);
82 | #ifdef V_TANGENT
83 | d = 1.0 - d*d;
84 | return step(0.0, d) * sqrt(d);
85 | #else
86 | return d;
87 | #endif
88 | }
89 |
90 | float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){
91 | #ifdef MINNAERT
92 | float NdotL = max(0.0, dot(norm, lightdir));
93 | float NdotV = max(0.0, dot(norm, viewdir));
94 | return NdotL * pow(max(NdotL * NdotV, 0.1), -1.0) * 0.5;
95 | #else
96 | return max(0.0, dot(norm, lightdir));
97 | #endif
98 | }
99 |
100 | float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){
101 | // NOTE: check for shiny <= 1 removed since shininess is now
102 | // 1.0 by default (uses matdefs default vals)
103 | #ifdef LOW_QUALITY
104 | // Blinn-Phong
105 | // Note: preferably, H should be computed in the vertex shader
106 | vec3 H = (viewdir + lightdir) * vec3(0.5);
107 | return pow(max(tangDot(H, norm), 0.0), shiny);
108 | #elif defined(WARDISO)
109 | // Isotropic Ward
110 | vec3 halfVec = normalize(viewdir + lightdir);
111 | float NdotH = max(0.001, tangDot(norm, halfVec));
112 | float NdotV = max(0.001, tangDot(norm, viewdir));
113 | float NdotL = max(0.001, tangDot(norm, lightdir));
114 | float a = tan(acos(NdotH));
115 | float p = max(shiny/128.0, 0.001);
116 | return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL)));
117 | #else
118 | // Standard Phong
119 | vec3 R = reflect(-lightdir, norm);
120 | return pow(max(tangDot(R, viewdir), 0.0), shiny);
121 | #endif
122 | }
123 |
124 | vec2 computeLighting(in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){
125 | float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir);
126 | float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess);
127 |
128 | #ifdef HQ_ATTENUATION
129 | float att = clamp(1.0 - g_LightPosition.w * length(lightVec), 0.0, 1.0);
130 | #else
131 | float att = vLightDir.w;
132 | #endif
133 |
134 | if (m_Shininess <= 1.0) {
135 | specularFactor = 0.0; // should be one instruction on most cards ..
136 | }
137 |
138 | specularFactor *= diffuseFactor;
139 |
140 | return vec2(diffuseFactor, specularFactor) * vec2(att);
141 | }
142 | #endif
143 |
144 | void main(){
145 | vec2 newTexCoord;
146 |
147 | #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
148 |
149 | #ifdef STEEP_PARALLAX
150 | #ifdef NORMALMAP_PARALLAX
151 | //parallax map is stored in the alpha channel of the normal map
152 | newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
153 | #else
154 | //parallax map is a texture
155 | newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
156 | #endif
157 | #else
158 | #ifdef NORMALMAP_PARALLAX
159 | //parallax map is stored in the alpha channel of the normal map
160 | newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
161 | #else
162 | //parallax map is a texture
163 | newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
164 | #endif
165 | #endif
166 | #else
167 | newTexCoord = texCoord;
168 | #endif
169 |
170 | #ifdef DIFFUSEMAP
171 | vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord);
172 | #else
173 | vec4 diffuseColor = vec4(1.0);
174 | #endif
175 |
176 | float alpha = DiffuseSum.a * diffuseColor.a;
177 | #ifdef ALPHAMAP
178 | alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r;
179 | #endif
180 |
181 | // Adjust alpha for distance
182 | // We want full alpha from 0 to mid and fading alpha from
183 | // mid falloff
184 | float mid = m_DistanceFalloff * 0.75;
185 | float fade = clamp((m_DistanceFalloff - vDistance) / mid, 0.0, 1.0);
186 | //float fade = min(1.0, (m_DistanceFalloff - vDistance) / mid);
187 | fade = fade * fade; // more gradual fading
188 |
189 | #ifdef USE_DISCARD
190 | if( (alpha * fade) < m_AlphaDiscardThreshold ) {
191 | discard;
192 | }
193 | #endif
194 |
195 | #ifdef USE_DARKENING
196 | float darken = min(1.0, 2.0 * alpha);
197 |
198 | alpha *= fade;
199 |
200 | #ifdef USE_TAPER
201 | // Far away... we want the
202 | // tapering to be less distinct
203 | //float mid2 = m_DistanceFalloff * 0.5;
204 | //float distFactor = min(1.0, ((m_DistanceFalloff - vDistance) / mid2);
205 | float distFactor = vDistance / (m_DistanceFalloff * 0.25);
206 | darken *= min(1.0, texCoord.y * distFactor);
207 | #endif
208 |
209 | float colorMix = min(0.7, alpha);
210 |
211 | // Mix some darker color in as the fade kicks in to avoid the gray borders
212 | //diffuseColor = mix(vec4(0.2, 0.25, 0.05, fade), diffuseColor, alpha);
213 | diffuseColor = mix(vec4(0.2 * darken, 0.25 * darken, 0.05 * darken, fade), diffuseColor, colorMix);
214 | #endif
215 |
216 | #ifndef VERTEX_LIGHTING
217 | float spotFallOff = 1.0;
218 |
219 | #if __VERSION__ >= 110
220 | // allow use of control flow
221 | if(g_LightDirection.w != 0.0){
222 | #endif
223 |
224 | vec3 L = normalize(lightVec.xyz);
225 | vec3 spotdir = normalize(g_LightDirection.xyz);
226 | float curAngleCos = dot(-L, spotdir);
227 | float innerAngleCos = floor(g_LightDirection.w) * 0.001;
228 | float outerAngleCos = fract(g_LightDirection.w);
229 | float innerMinusOuter = innerAngleCos - outerAngleCos;
230 | spotFallOff = (curAngleCos - outerAngleCos) / innerMinusOuter;
231 |
232 | #if __VERSION__ >= 110
233 | if(spotFallOff <= 0.0){
234 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
235 | gl_FragColor.a = alpha;
236 | return;
237 | }else{
238 | spotFallOff = clamp(spotFallOff, 0.0, 1.0);
239 | }
240 | }
241 | #else
242 | spotFallOff = clamp(spotFallOff, step(g_LightDirection.w, 0.001), 1.0);
243 | #endif
244 | #endif
245 |
246 | // ***********************
247 | // Read from textures
248 | // ***********************
249 | #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
250 | vec4 normalHeight = texture2D(m_NormalMap, newTexCoord);
251 | vec3 normal = normalize((normalHeight.xyz * vec3(2.0) - vec3(1.0)));
252 | #ifdef LATC
253 | normal.z = sqrt(1.0 - (normal.x * normal.x) - (normal.y * normal.y));
254 | #endif
255 | //normal.y = -normal.y;
256 | #elif !defined(VERTEX_LIGHTING)
257 | vec3 normal = vNormal;
258 | #if !defined(LOW_QUALITY) && !defined(V_TANGENT)
259 | normal = normalize(normal);
260 | #endif
261 | #endif
262 |
263 | #ifdef SPECULARMAP
264 | vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
265 | #else
266 | vec4 specularColor = vec4(1.0);
267 | #endif
268 |
269 | #ifdef LIGHTMAP
270 | vec3 lightMapColor;
271 | #ifdef SEPARATE_TEXCOORD
272 | lightMapColor = texture2D(m_LightMap, texCoord2).rgb;
273 | #else
274 | lightMapColor = texture2D(m_LightMap, texCoord).rgb;
275 | #endif
276 | specularColor.rgb *= lightMapColor;
277 | diffuseColor.rgb *= lightMapColor;
278 | #endif
279 |
280 | #ifdef VERTEX_LIGHTING
281 | vec2 light = vertexLightValues.xy;
282 | #ifdef COLORRAMP
283 | light.x = texture2D(m_ColorRamp, vec2(light.x, 0.0)).r;
284 | light.y = texture2D(m_ColorRamp, vec2(light.y, 0.0)).r;
285 | #endif
286 |
287 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb +
288 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
289 | SpecularSum * specularColor.rgb * vec3(light.y);
290 | #else
291 | vec4 lightDir = vLightDir;
292 | lightDir.xyz = normalize(lightDir.xyz);
293 | vec3 viewDir = normalize(vViewDir);
294 |
295 | vec2 light = computeLighting(normal, viewDir, lightDir.xyz) * spotFallOff;
296 | #ifdef COLORRAMP
297 | diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
298 | specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
299 | #endif
300 |
301 | // Workaround, since it is not possible to modify varying variables
302 | vec4 SpecularSum2 = vec4(SpecularSum, 1.0);
303 | #ifdef USE_REFLECTION
304 | vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz);
305 |
306 | // Interpolate light specularity toward reflection color
307 | // Multiply result by specular map
308 | specularColor = mix(SpecularSum2 * light.y, refColor, refVec.w) * specularColor;
309 |
310 | SpecularSum2 = vec4(1.0);
311 | light.y = 1.0;
312 | #endif
313 |
314 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb +
315 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
316 | SpecularSum2.rgb * specularColor.rgb * vec3(light.y);
317 | #endif
318 | gl_FragColor.a = alpha;
319 | }
320 |
--------------------------------------------------------------------------------
/assets/MatDefs/Grass.j3md:
--------------------------------------------------------------------------------
1 | MaterialDef Grass Blades {
2 |
3 | MaterialParameters {
4 |
5 | // Compute vertex lighting in the shader
6 | // For better performance
7 | Boolean VertexLighting
8 |
9 | // Use more efficent algorithms to improve performance
10 | Boolean LowQuality
11 |
12 | // Improve quality at the cost of performance
13 | Boolean HighQuality
14 |
15 | // Output alpha from the diffuse map
16 | Boolean UseAlpha
17 |
18 | // Alpha threshold for fragment discarding
19 | Float AlphaDiscardThreshold (AlphaTestFallOff)
20 |
21 | // Normal map is in BC5/ATI2n/LATC/3Dc compression format
22 | Boolean LATC
23 |
24 | // Use the provided ambient, diffuse, and specular colors
25 | Boolean UseMaterialColors
26 |
27 | // Activate shading along the tangent, instead of the normal
28 | // Requires tangent data to be available on the model.
29 | Boolean VTangent
30 |
31 | // Use minnaert diffuse instead of lambert
32 | Boolean Minnaert
33 |
34 | // Use ward specular instead of phong
35 | Boolean WardIso
36 |
37 | // Use vertex color as an additional diffuse color.
38 | Boolean UseVertexColor
39 |
40 | // Ambient color
41 | Color Ambient (MaterialAmbient)
42 |
43 | // Diffuse color
44 | Color Diffuse (MaterialDiffuse)
45 |
46 | // Specular color
47 | Color Specular (MaterialSpecular)
48 |
49 | // Specular power/shininess
50 | Float Shininess (MaterialShininess) : 1
51 |
52 | // Diffuse map
53 | Texture2D DiffuseMap
54 |
55 | // Normal map
56 | Texture2D NormalMap
57 |
58 | // Specular/gloss map
59 | Texture2D SpecularMap
60 |
61 | // Parallax/height map
62 | Texture2D ParallaxMap
63 |
64 | //Set to true is parallax map is stored in the alpha channel of the normal map
65 | Boolean PackedNormalParallax
66 |
67 | //Sets the relief height for parallax mapping
68 | Float ParallaxHeight : 0.05
69 |
70 | //Set to true to activate Steep Parallax mapping
71 | Boolean SteepParallax
72 |
73 | // Texture that specifies alpha values
74 | Texture2D AlphaMap
75 |
76 | // Color ramp, will map diffuse and specular values through it.
77 | Texture2D ColorRamp
78 |
79 | // Texture of the glowing parts of the material
80 | Texture2D GlowMap
81 |
82 | // Set to Use Lightmap
83 | Texture2D LightMap
84 |
85 | // Set to use TexCoord2 for the lightmap sampling
86 | Boolean SeparateTexCoord
87 |
88 | // The glow color of the object
89 | Color GlowColor
90 |
91 | // Parameters for fresnel
92 | // X = bias
93 | // Y = scale
94 | // Z = power
95 | Vector3 FresnelParams
96 |
97 | // Env Map for reflection
98 | TextureCubeMap EnvMap
99 |
100 | // the env map is a spheremap and not a cube map
101 | Boolean EnvMapAsSphereMap
102 |
103 | //shadows
104 | Int FilterMode
105 | Boolean HardwareShadows
106 |
107 | Texture2D ShadowMap0
108 | Texture2D ShadowMap1
109 | Texture2D ShadowMap2
110 | Texture2D ShadowMap3
111 | //pointLights
112 | Texture2D ShadowMap4
113 | Texture2D ShadowMap5
114 |
115 | Float ShadowIntensity
116 | Vector4 Splits
117 | Vector2 FadeInfo
118 |
119 | Matrix4 LightViewProjectionMatrix0
120 | Matrix4 LightViewProjectionMatrix1
121 | Matrix4 LightViewProjectionMatrix2
122 | Matrix4 LightViewProjectionMatrix3
123 | //pointLight
124 | Matrix4 LightViewProjectionMatrix4
125 | Matrix4 LightViewProjectionMatrix5
126 | Vector3 LightPos
127 |
128 | Float PCFEdge
129 | Float ShadowMapSize
130 |
131 | // For hardware skinning
132 | Int NumberOfBones
133 | Matrix4Array BoneMatrices
134 |
135 |
136 | // Grass parameters
137 | Float DistanceFalloff : 48
138 | Texture2D Noise
139 | Vector3 WorldOffset
140 |
141 | Boolean UseWind : true
142 | Boolean UseDiscard : true
143 | Boolean UseDarkening : true
144 | Boolean UseTaper : true
145 | }
146 |
147 | Technique {
148 |
149 | LightMode MultiPass
150 |
151 | VertexShader GLSL110: MatDefs/Grass.vert
152 | FragmentShader GLSL110: MatDefs/Grass.frag
153 |
154 | WorldParameters {
155 | WorldViewProjectionMatrix
156 | ViewProjectionMatrix
157 | NormalMatrix
158 | WorldViewMatrix
159 | ViewMatrix
160 | CameraPosition
161 | WorldMatrix
162 | Time
163 | }
164 |
165 | Defines {
166 | LATC : LATC
167 | VERTEX_COLOR : UseVertexColor
168 | VERTEX_LIGHTING : VertexLighting
169 | ATTENUATION : Attenuation
170 | MATERIAL_COLORS : UseMaterialColors
171 | V_TANGENT : VTangent
172 | MINNAERT : Minnaert
173 | WARDISO : WardIso
174 | LOW_QUALITY : LowQuality
175 | HQ_ATTENUATION : HighQuality
176 |
177 | DIFFUSEMAP : DiffuseMap
178 | NORMALMAP : NormalMap
179 | SPECULARMAP : SpecularMap
180 | PARALLAXMAP : ParallaxMap
181 | NORMALMAP_PARALLAX : PackedNormalParallax
182 | STEEP_PARALLAX : SteepParallax
183 | ALPHAMAP : AlphaMap
184 | COLORRAMP : ColorRamp
185 | LIGHTMAP : LightMap
186 | SEPARATE_TEXCOORD : SeparateTexCoord
187 |
188 | USE_REFLECTION : EnvMap
189 | SPHERE_MAP : SphereMap
190 |
191 | NUM_BONES : NumberOfBones
192 |
193 | USE_WIND : UseWind
194 | USE_DISCARD : UseDiscard
195 | USE_DARKENING : UseDarkening
196 | USE_TAPER : UseTaper
197 | }
198 | }
199 |
200 | Technique PreShadow {
201 |
202 | VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert
203 | FragmentShader GLSL100 : Common/MatDefs/Shadow/PreShadow.frag
204 |
205 | WorldParameters {
206 | WorldViewProjectionMatrix
207 | WorldViewMatrix
208 | }
209 |
210 | Defines {
211 | COLOR_MAP : ColorMap
212 | DISCARD_ALPHA : AlphaDiscardThreshold
213 | NUM_BONES : NumberOfBones
214 | }
215 |
216 | ForcedRenderState {
217 | FaceCull Off
218 | DepthTest On
219 | DepthWrite On
220 | PolyOffset 5 3
221 | ColorWrite Off
222 | }
223 |
224 | }
225 |
226 |
227 | Technique PostShadow15{
228 | VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert
229 | FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag
230 |
231 | WorldParameters {
232 | WorldViewProjectionMatrix
233 | WorldMatrix
234 | }
235 |
236 | Defines {
237 | HARDWARE_SHADOWS : HardwareShadows
238 | FILTER_MODE : FilterMode
239 | PCFEDGE : PCFEdge
240 | DISCARD_ALPHA : AlphaDiscardThreshold
241 | COLOR_MAP : ColorMap
242 | SHADOWMAP_SIZE : ShadowMapSize
243 | FADE : FadeInfo
244 | PSSM : Splits
245 | POINTLIGHT : LightViewProjectionMatrix5
246 | NUM_BONES : NumberOfBones
247 | }
248 |
249 | ForcedRenderState {
250 | Blend Modulate
251 | DepthWrite Off
252 | PolyOffset -0.1 0
253 | }
254 | }
255 |
256 | Technique PostShadow{
257 | VertexShader GLSL100: Common/MatDefs/Shadow/PostShadow.vert
258 | FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadow.frag
259 |
260 | WorldParameters {
261 | WorldViewProjectionMatrix
262 | WorldMatrix
263 | }
264 |
265 | Defines {
266 | HARDWARE_SHADOWS : HardwareShadows
267 | FILTER_MODE : FilterMode
268 | PCFEDGE : PCFEdge
269 | DISCARD_ALPHA : AlphaDiscardThreshold
270 | COLOR_MAP : ColorMap
271 | SHADOWMAP_SIZE : ShadowMapSize
272 | FADE : FadeInfo
273 | PSSM : Splits
274 | POINTLIGHT : LightViewProjectionMatrix5
275 | NUM_BONES : NumberOfBones
276 | }
277 |
278 | ForcedRenderState {
279 | Blend Modulate
280 | DepthWrite Off
281 | PolyOffset -0.1 0
282 | }
283 | }
284 |
285 | Technique PreNormalPass {
286 |
287 | VertexShader GLSL100 : Common/MatDefs/SSAO/normal.vert
288 | FragmentShader GLSL100 : Common/MatDefs/SSAO/normal.frag
289 |
290 | WorldParameters {
291 | WorldViewProjectionMatrix
292 | WorldViewMatrix
293 | NormalMatrix
294 | }
295 |
296 | Defines {
297 | DIFFUSEMAP_ALPHA : DiffuseMap
298 | NUM_BONES : NumberOfBones
299 | }
300 |
301 | }
302 |
303 | Technique GBuf {
304 |
305 | VertexShader GLSL100: Common/MatDefs/Light/GBuf.vert
306 | FragmentShader GLSL100: Common/MatDefs/Light/GBuf.frag
307 |
308 | WorldParameters {
309 | WorldViewProjectionMatrix
310 | NormalMatrix
311 | WorldViewMatrix
312 | WorldMatrix
313 | }
314 |
315 | Defines {
316 | VERTEX_COLOR : UseVertexColor
317 | MATERIAL_COLORS : UseMaterialColors
318 | V_TANGENT : VTangent
319 | MINNAERT : Minnaert
320 | WARDISO : WardIso
321 |
322 | DIFFUSEMAP : DiffuseMap
323 | NORMALMAP : NormalMap
324 | SPECULARMAP : SpecularMap
325 | PARALLAXMAP : ParallaxMap
326 | }
327 | }
328 |
329 | Technique {
330 | LightMode FixedPipeline
331 | }
332 |
333 | Technique Glow {
334 |
335 | VertexShader GLSL100: Common/MatDefs/Misc/Unshaded.vert
336 | FragmentShader GLSL100: Common/MatDefs/Light/Glow.frag
337 |
338 | WorldParameters {
339 | WorldViewProjectionMatrix
340 | }
341 |
342 | Defines {
343 | NEED_TEXCOORD1
344 | HAS_GLOWMAP : GlowMap
345 | HAS_GLOWCOLOR : GlowColor
346 |
347 | NUM_BONES : NumberOfBones
348 | }
349 | }
350 |
351 | }
352 |
--------------------------------------------------------------------------------
/assets/MatDefs/Grass.vert:
--------------------------------------------------------------------------------
1 | #define ATTENUATION
2 | //#define HQ_ATTENUATION
3 |
4 | #import "Common/ShaderLib/Skinning.glsllib"
5 |
6 | uniform mat4 g_WorldViewProjectionMatrix;
7 | uniform mat4 g_ViewProjectionMatrix;
8 | uniform mat4 g_WorldViewMatrix;
9 | uniform mat4 g_WorldMatrix;
10 | uniform mat3 g_NormalMatrix;
11 | uniform mat4 g_ViewMatrix;
12 | uniform vec3 g_CameraPosition;
13 | uniform float g_Time;
14 |
15 | uniform vec4 m_Ambient;
16 | uniform vec4 m_Diffuse;
17 | uniform vec4 m_Specular;
18 | uniform float m_Shininess;
19 |
20 | uniform vec4 g_LightColor;
21 | uniform vec4 g_LightPosition;
22 | uniform vec4 g_AmbientLightColor;
23 |
24 | varying vec2 texCoord;
25 | #ifdef SEPARATE_TEXCOORD
26 | varying vec2 texCoord2;
27 | attribute vec2 inTexCoord2;
28 | #endif
29 |
30 | varying vec3 AmbientSum;
31 | varying vec4 DiffuseSum;
32 | varying vec3 SpecularSum;
33 |
34 | varying float vDistance;
35 | uniform sampler2D m_Noise;
36 | uniform vec3 m_WorldOffset;
37 |
38 | attribute vec3 inPosition;
39 | attribute vec2 inTexCoord;
40 | attribute vec3 inNormal;
41 |
42 | varying vec3 lightVec;
43 | //varying vec4 spotVec;
44 |
45 | #ifdef VERTEX_COLOR
46 | attribute vec4 inColor;
47 | #endif
48 |
49 | #ifndef VERTEX_LIGHTING
50 | attribute vec4 inTangent;
51 |
52 | #ifndef NORMALMAP
53 | varying vec3 vNormal;
54 | #endif
55 | //varying vec3 vPosition;
56 | varying vec3 vViewDir;
57 | varying vec4 vLightDir;
58 | #else
59 | varying vec2 vertexLightValues;
60 | uniform vec4 g_LightDirection;
61 | #endif
62 |
63 | #ifdef USE_REFLECTION
64 | uniform vec3 g_CameraPosition;
65 | uniform mat4 g_WorldMatrix;
66 |
67 | uniform vec3 m_FresnelParams;
68 | varying vec4 refVec;
69 |
70 |
71 | /**
72 | * Input:
73 | * attribute inPosition
74 | * attribute inNormal
75 | * uniform g_WorldMatrix
76 | * uniform g_CameraPosition
77 | *
78 | * Output:
79 | * varying refVec
80 | */
81 | void computeRef(in vec4 modelSpacePos){
82 | vec3 worldPos = (g_WorldMatrix * modelSpacePos).xyz;
83 |
84 | vec3 I = normalize( g_CameraPosition - worldPos ).xyz;
85 | vec3 N = normalize( (g_WorldMatrix * vec4(inNormal, 0.0)).xyz );
86 |
87 | refVec.xyz = reflect(I, N);
88 | refVec.w = m_FresnelParams.x + m_FresnelParams.y * pow(1.0 + dot(I, N), m_FresnelParams.z);
89 | }
90 | #endif
91 |
92 | // JME3 lights in world space
93 | void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){
94 | float posLight = step(0.5, color.w);
95 | vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
96 | lightVec = tempVec;
97 | #ifdef ATTENUATION
98 | float dist = length(tempVec);
99 | lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
100 | lightDir.xyz = tempVec / vec3(dist);
101 | #else
102 | lightDir = vec4(normalize(tempVec), 1.0);
103 | #endif
104 | }
105 |
106 | #ifdef VERTEX_LIGHTING
107 | float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){
108 | return max(0.0, dot(norm, lightdir));
109 | }
110 |
111 | float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){
112 | if (shiny <= 1.0){
113 | return 0.0;
114 | }
115 | #ifndef LOW_QUALITY
116 | vec3 H = (viewdir + lightdir) * vec3(0.5);
117 | return pow(max(dot(H, norm), 0.0), shiny);
118 | #else
119 | return 0.0;
120 | #endif
121 | }
122 |
123 | vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec4 wvLightPos){
124 | vec4 lightDir;
125 | lightComputeDir(wvPos, g_LightColor, wvLightPos, lightDir);
126 | float spotFallOff = 1.0;
127 | if(g_LightDirection.w != 0.0){
128 | vec3 L=normalize(lightVec.xyz);
129 | vec3 spotdir = normalize(g_LightDirection.xyz);
130 | float curAngleCos = dot(-L, spotdir);
131 | float innerAngleCos = floor(g_LightDirection.w) * 0.001;
132 | float outerAngleCos = fract(g_LightDirection.w);
133 | float innerMinusOuter = innerAngleCos - outerAngleCos;
134 | spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0);
135 | }
136 | float diffuseFactor = lightComputeDiffuse(wvNorm, lightDir.xyz);
137 | float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, lightDir.xyz, m_Shininess);
138 | //specularFactor *= step(0.01, diffuseFactor);
139 | return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w)*spotFallOff;
140 | }
141 | #endif
142 |
143 | void main(){
144 | vec4 modelSpacePos = vec4(inPosition, 1.0);
145 | vec3 modelSpaceNorm = inNormal;
146 |
147 | #ifndef VERTEX_LIGHTING
148 | vec3 modelSpaceTan = inTangent.xyz;
149 | #endif
150 |
151 | #ifdef NUM_BONES
152 | #ifndef VERTEX_LIGHTING
153 | Skinning_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
154 | #else
155 | Skinning_Compute(modelSpacePos, modelSpaceNorm);
156 | #endif
157 | #endif
158 |
159 | // We plot the position of the grass vertexes based on the
160 | // texture coordinates
161 | //gl_Position = g_WorldViewProjectionMatrix * modelSpacePos;
162 | texCoord = inTexCoord;
163 | #ifdef SEPARATE_TEXCOORD
164 | texCoord2 = inTexCoord2;
165 | #endif
166 |
167 | // Find the world location of the vertex. All three corners
168 | // will have the same vertex.
169 | vec3 wPos = (g_WorldMatrix * modelSpacePos).xyz;
170 | vec2 groundPos = wPos.xz + m_WorldOffset.xz;
171 |
172 | // We face the billboarded grass towards the camera's location
173 | // instead of parallel to the screen. This keeps the blades from
174 | // sliding around if we turn the camera.
175 | vec3 cameraOffset = wPos - g_CameraPosition;
176 | vDistance = length(cameraOffset);
177 | vec3 cameraDir = cameraOffset / vDistance;
178 | vec3 posOffset = normalize(vec3(-cameraDir.z, 0.0, cameraDir.x));
179 |
180 | // The whole part of the x coordinate is the atlas cell.
181 | // The fractional part says which corner this is.
182 | // X fract() will be 0.25, 0.5, or 0.0
183 | // Y will be 1 at x=0 and x=0.5 but 0 at x=0.25.
184 | // I kept the decimal part small so that it could be safely
185 | // extracted from the texture coordinate.
186 | float texFract = fract(texCoord.x);
187 | float offsetLength = (texFract * 2.0) - 0.5;
188 | float texY = abs(offsetLength) * 2.0;
189 | float normalProjectionLength = texY - 0.25;
190 | float size = texCoord.y;
191 |
192 | modelSpacePos.xyz += modelSpaceNorm * normalProjectionLength * size;
193 | wPos = (g_WorldMatrix * modelSpacePos).xyz;
194 |
195 | // Move the upper parts of the triangle along the camera-perpendicular
196 | // vector (posOffset)
197 | wPos += posOffset * offsetLength * size;
198 |
199 | #ifdef USE_WIND
200 | // some simple wind
201 | vec4 noise = texture2D(m_Noise, vec2(groundPos.x * 0.01 + g_Time * 0.01, groundPos.y * 0.01));
202 | //wPos.x += (noise.x * 0.5 - 0.25) * normalProjectionLength;
203 | float strength = noise.y * 0.15 * size;
204 | wPos.x += sin(g_Time * (1.0 + noise.x)) * normalProjectionLength * strength;
205 | #endif
206 |
207 | gl_Position = g_ViewProjectionMatrix * vec4(wPos, 1.0);
208 |
209 | // Figure out the texture coordinate from the index
210 | float index = texCoord.x - texFract;
211 | float u = mod(index, 4.0);
212 | float v = mod((index - u) * 0.25, 4.0);
213 | texCoord.x = u * 0.25 + texFract * 0.5;
214 | texCoord.y = v * 0.25 + texY * 0.25;
215 |
216 |
217 | vec3 wvPosition = (g_WorldViewMatrix * modelSpacePos).xyz;
218 | vec3 wvNormal = normalize(g_NormalMatrix * modelSpaceNorm);
219 | vec3 viewDir = normalize(-wvPosition);
220 |
221 | //vec4 lightColor = g_LightColor[gl_InstanceID];
222 | //vec4 lightPos = g_LightPosition[gl_InstanceID];
223 | //vec4 wvLightPos = (g_ViewMatrix * vec4(lightPos.xyz, lightColor.w));
224 | //wvLightPos.w = lightPos.w;
225 |
226 | vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0)));
227 | wvLightPos.w = g_LightPosition.w;
228 | vec4 lightColor = g_LightColor;
229 |
230 | #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
231 | vec3 wvTangent = normalize(g_NormalMatrix * modelSpaceTan);
232 | vec3 wvBinormal = cross(wvNormal, wvTangent);
233 |
234 | mat3 tbnMat = mat3(wvTangent, wvBinormal * -inTangent.w,wvNormal);
235 |
236 | //vPosition = wvPosition * tbnMat;
237 | //vViewDir = viewDir * tbnMat;
238 | vViewDir = -wvPosition * tbnMat;
239 | lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir);
240 | vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz;
241 | #elif !defined(VERTEX_LIGHTING)
242 | vNormal = wvNormal;
243 |
244 | //vPosition = wvPosition;
245 | vViewDir = viewDir;
246 |
247 | lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir);
248 |
249 | #ifdef V_TANGENT
250 | vNormal = normalize(g_NormalMatrix * inTangent.xyz);
251 | vNormal = -cross(cross(vLightDir.xyz, vNormal), vNormal);
252 | #endif
253 | #endif
254 |
255 | //computing spot direction in view space and unpacking spotlight cos
256 | // spotVec = (g_ViewMatrix * vec4(g_LightDirection.xyz, 0.0) );
257 | // spotVec.w = floor(g_LightDirection.w) * 0.001;
258 | // lightVec.w = fract(g_LightDirection.w);
259 |
260 | lightColor.w = 1.0;
261 | #ifdef MATERIAL_COLORS
262 | AmbientSum = (m_Ambient * g_AmbientLightColor).rgb;
263 | DiffuseSum = m_Diffuse * lightColor;
264 | SpecularSum = (m_Specular * lightColor).rgb;
265 | #else
266 | AmbientSum = vec3(0.2, 0.2, 0.2) * g_AmbientLightColor.rgb; // Default: ambient color is dark gray
267 | DiffuseSum = lightColor;
268 | SpecularSum = vec3(0.0);
269 | #endif
270 |
271 | #ifdef VERTEX_COLOR
272 | AmbientSum *= inColor.rgb;
273 | DiffuseSum *= inColor;
274 | #endif
275 |
276 | #ifdef VERTEX_LIGHTING
277 | vertexLightValues = computeLighting(wvPosition, wvNormal, viewDir, wvLightPos);
278 | #endif
279 |
280 | #ifdef USE_REFLECTION
281 | computeRef(modelSpacePos);
282 | #endif
283 | }
284 |
--------------------------------------------------------------------------------
/assets/MatDefs/TrilinearLighting.frag:
--------------------------------------------------------------------------------
1 | #import "Common/ShaderLib/Parallax.glsllib"
2 | #import "Common/ShaderLib/Optics.glsllib"
3 | #define ATTENUATION
4 | //#define HQ_ATTENUATION
5 |
6 | #import "MatDefs/FragScattering.glsllib"
7 |
8 | // Trinlinear mapping related stuff
9 | uniform mat3 g_NormalMatrix;
10 | varying vec3 worldNormal;
11 |
12 | varying vec3 worldTangent;
13 |
14 | varying float z;
15 | uniform sampler2D m_Noise;
16 |
17 | uniform float m_LowResDistance;
18 | uniform sampler2D m_DiffuseMapLow;
19 | uniform sampler2D m_DiffuseMapX;
20 | uniform sampler2D m_NormalMapX;
21 | uniform sampler2D m_DiffuseMapY;
22 | uniform sampler2D m_NormalMapY;
23 | uniform sampler2D m_DiffuseMapZ;
24 | uniform sampler2D m_NormalMapZ;
25 |
26 |
27 | varying vec3 texCoord;
28 | #ifdef SEPARATE_TEXCOORD
29 | varying vec2 texCoord2;
30 | #endif
31 |
32 | varying vec3 AmbientSum;
33 | varying vec4 DiffuseSum;
34 | varying vec3 SpecularSum;
35 |
36 | #ifndef VERTEX_LIGHTING
37 | uniform vec4 g_LightDirection;
38 | //varying vec3 vPosition;
39 | varying vec3 vViewDir;
40 | varying vec4 vLightDir;
41 | varying vec3 lightVec;
42 | #else
43 | varying vec2 vertexLightValues;
44 | #endif
45 |
46 | #ifdef DIFFUSEMAP
47 | uniform sampler2D m_DiffuseMap;
48 | #endif
49 |
50 | #ifdef SPECULARMAP
51 | uniform sampler2D m_SpecularMap;
52 | #endif
53 |
54 | #ifdef PARALLAXMAP
55 | uniform sampler2D m_ParallaxMap;
56 | #endif
57 | #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
58 | uniform float m_ParallaxHeight;
59 | #endif
60 |
61 | #ifdef LIGHTMAP
62 | uniform sampler2D m_LightMap;
63 | #endif
64 |
65 | #ifdef NORMALMAP
66 | uniform sampler2D m_NormalMap;
67 |
68 | // For debugging we want it either way
69 | varying vec3 vNormal;
70 | #else
71 | varying vec3 vNormal;
72 | #endif
73 |
74 | #ifdef ALPHAMAP
75 | uniform sampler2D m_AlphaMap;
76 | #endif
77 |
78 | #ifdef COLORRAMP
79 | uniform sampler2D m_ColorRamp;
80 | #endif
81 |
82 | uniform float m_AlphaDiscardThreshold;
83 |
84 | #ifndef VERTEX_LIGHTING
85 | uniform float m_Shininess;
86 |
87 | #ifdef HQ_ATTENUATION
88 | uniform vec4 g_LightPosition;
89 | #endif
90 |
91 | #ifdef USE_REFLECTION
92 | uniform float m_ReflectionPower;
93 | uniform float m_ReflectionIntensity;
94 | varying vec4 refVec;
95 |
96 | uniform ENVMAP m_EnvMap;
97 | #endif
98 |
99 | float tangDot(in vec3 v1, in vec3 v2){
100 | float d = dot(v1,v2);
101 | #ifdef V_TANGENT
102 | d = 1.0 - d*d;
103 | return step(0.0, d) * sqrt(d);
104 | #else
105 | return d;
106 | #endif
107 | }
108 |
109 | float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){
110 | #ifdef MINNAERT
111 | float NdotL = max(0.0, dot(norm, lightdir));
112 | float NdotV = max(0.0, dot(norm, viewdir));
113 | return NdotL * pow(max(NdotL * NdotV, 0.1), -1.0) * 0.5;
114 | #else
115 | return max(0.0, dot(norm, lightdir));
116 | #endif
117 | }
118 |
119 | float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){
120 | // NOTE: check for shiny <= 1 removed since shininess is now
121 | // 1.0 by default (uses matdefs default vals)
122 | #ifdef LOW_QUALITY
123 | // Blinn-Phong
124 | // Note: preferably, H should be computed in the vertex shader
125 | vec3 H = (viewdir + lightdir) * vec3(0.5);
126 | return pow(max(tangDot(H, norm), 0.0), shiny);
127 | #elif defined(WARDISO)
128 | // Isotropic Ward
129 | vec3 halfVec = normalize(viewdir + lightdir);
130 | float NdotH = max(0.001, tangDot(norm, halfVec));
131 | float NdotV = max(0.001, tangDot(norm, viewdir));
132 | float NdotL = max(0.001, tangDot(norm, lightdir));
133 | float a = tan(acos(NdotH));
134 | float p = max(shiny/128.0, 0.001);
135 | return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL)));
136 | #else
137 | // Standard Phong
138 | vec3 R = reflect(-lightdir, norm);
139 | return pow(max(tangDot(R, viewdir), 0.0), shiny);
140 | #endif
141 | }
142 |
143 | vec2 computeLighting(in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){
144 | float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir);
145 | float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess);
146 |
147 | #ifdef HQ_ATTENUATION
148 | float att = clamp(1.0 - g_LightPosition.w * length(lightVec), 0.0, 1.0);
149 | #else
150 | float att = vLightDir.w;
151 | #endif
152 |
153 | if (m_Shininess <= 1.0) {
154 | specularFactor = 0.0; // should be one instruction on most cards ..
155 | }
156 |
157 | specularFactor *= diffuseFactor;
158 |
159 | return vec2(diffuseFactor, specularFactor) * vec2(att);
160 | }
161 | #endif
162 |
163 | vec4 getColor( in sampler2D diffuseMap, in sampler2D diffuseMapLow, in sampler2D normalMap, in vec2 tc, in float distMix, out vec3 normal ) {
164 |
165 | vec2 tcOffset;
166 | tcOffset = texture2D(m_Noise, tc * 0.01).xy * 6.0 - 3.0;
167 | vec4 diffuseColor = texture2D(diffuseMap, (tc + tcOffset) * 0.75);
168 |
169 | tcOffset.x = (texture2D(m_Noise, tc * 0.01).x * 0.2) - 0.1;
170 | tcOffset.y = (texture2D(m_Noise, tc * 0.03).x * 0.2) - 0.1;
171 | vec4 subColor = texture2D(diffuseMapLow, tc * 0.1 + tcOffset * 0.1);
172 | diffuseColor = mix(diffuseColor, subColor, distMix);
173 |
174 | vec4 normalHeight = texture2D(normalMap, tc);
175 | normal = normalize((normalHeight.xyz * vec3(2.0) - vec3(1.0)));
176 |
177 | return diffuseColor;
178 | }
179 |
180 |
181 | void main(){
182 | vec2 newTexCoord;
183 |
184 | /****
185 | This is taken care of by the trilinear mapping now
186 | #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
187 |
188 | #ifdef STEEP_PARALLAX
189 | #ifdef NORMALMAP_PARALLAX
190 | //parallax map is stored in the alpha channel of the normal map
191 | newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord.xz, m_ParallaxHeight);
192 | #else
193 | //parallax map is a texture
194 | newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord.xz, m_ParallaxHeight);
195 | #endif
196 | #else
197 | #ifdef NORMALMAP_PARALLAX
198 | //parallax map is stored in the alpha channel of the normal map
199 | newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord.xz, m_ParallaxHeight);
200 | #else
201 | //parallax map is a texture
202 | newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord.xz, m_ParallaxHeight);
203 | #endif
204 | #endif
205 | #else
206 | newTexCoord = texCoord.xz;
207 | #endif
208 |
209 | #ifdef DIFFUSEMAP
210 | vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord);
211 | #else
212 | vec4 diffuseColor = vec4(1.0);
213 | #endif
214 |
215 | float alpha = DiffuseSum.a * diffuseColor.a;
216 | #ifdef ALPHAMAP
217 | alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r;
218 | #endif
219 | if(alpha < m_AlphaDiscardThreshold){
220 | discard;
221 | }
222 | */
223 |
224 | //diffuseColor.xyz = normalize(worldNormal);
225 | float alpha = 1.0;
226 |
227 | /*****
228 | This is taken care of by the trilinear mapping now
229 | // ***********************
230 | // Read from textures
231 | // ***********************
232 | #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
233 | vec4 normalHeight = texture2D(m_NormalMap, newTexCoord);
234 | vec3 normal = normalize((normalHeight.xyz * vec3(2.0) - vec3(1.0)));
235 | #ifdef LATC
236 | normal.z = sqrt(1.0 - (normal.x * normal.x) - (normal.y * normal.y));
237 | #endif
238 | //normal.y = -normal.y;
239 | #elif !defined(VERTEX_LIGHTING)
240 | vec3 normal = vNormal;
241 | #if !defined(LOW_QUALITY) && !defined(V_TANGENT)
242 | normal = normalize(normal);
243 | #endif
244 | #endif
245 | */
246 |
247 |
248 | // *************************************
249 | // Trinlinear Mapping
250 | // *************************************
251 |
252 | // We change the low res to hi res based on distance
253 | float lowMix = z / m_LowResDistance;
254 | lowMix = clamp(lowMix, 0.5, 1.0);
255 |
256 | // Collect the basic axis textures for x, y, and z
257 | vec3 normalX;
258 | vec3 normalY;
259 | vec3 normalZ;
260 | vec3 normalTop;
261 |
262 | vec4 xColor = getColor(m_DiffuseMapX, m_DiffuseMapX, m_NormalMapX, texCoord.zy, lowMix, normalX);
263 | vec4 yColor = getColor(m_DiffuseMapY, m_DiffuseMapY, m_NormalMapY, texCoord.xz, lowMix, normalY);
264 | vec4 zColor = getColor(m_DiffuseMapZ, m_DiffuseMapZ, m_NormalMapZ, texCoord.xy, lowMix, normalZ);
265 |
266 | // Turn the normal into the blending ratios.
267 | float up = worldNormal.y;
268 | float offset = texture2D(m_Noise, texCoord.xz).x;
269 |
270 | // We bias the threshold a bit based on a noise value.
271 | float threshold = up + (offset * 0.1 - 0.05);
272 |
273 | // Now bias the y blend factor by the threshold if it exceeds
274 | // 45 degrees, basically. The noise above will give us some
275 | // nice rough edges.
276 | vec3 blend = abs(normalize(worldNormal));
277 | if( threshold > 0.707 ) {
278 | blend.y += 10.0 * offset;
279 | }
280 |
281 | // "normalize" it once with the initial bias in place.
282 | // blend should always add to 1.0
283 | blend /= (blend.x + blend.y + blend.z);
284 |
285 | // The top will use a different texture based on the threshold so far
286 | vec4 topColor = getColor(m_DiffuseMap, m_DiffuseMapLow, m_NormalMapY, texCoord.xz, lowMix, normalTop);
287 |
288 | // Mix a border into the topColor based on an area around the threshold
289 | float edge1 = smoothstep(0.5, 0.72, threshold);
290 | float edge2 = 1.0 - smoothstep(0.72, 0.75, threshold);
291 | topColor = mix(topColor, topColor * vec4(0.6, 0.5, 0.5, 1.0), edge1 * edge2);
292 |
293 | // Top will be 1.0 if normal is up, 0 otherwise
294 | float top = step(worldNormal.y, 0.0);
295 |
296 | // Select the top or the bottom texture based on sign of y
297 | // ...and darken the bottom texture while we are at it
298 | yColor = topColor * (1.0 - top) + yColor * top * 0.5;
299 |
300 | // Bias the y blend value based on the up-ness and
301 | // the edges
302 | blend.y *= max(top, edge1 * edge1);
303 |
304 | // It is important that x, y, z add up to just 1.0 and only 1.0
305 | blend /= (blend.x + blend.y + blend.z);
306 |
307 | // If we are very close to the grass edge then also darken the
308 | // other two axes just a bit.
309 | float darken = min(1.0, 0.9 + (1.0 - edge1) * 0.1);
310 |
311 | vec4 diffuseColor = xColor * blend.x * darken
312 | + yColor * blend.y
313 | + zColor * blend.z * darken;
314 |
315 | // Move the normal map normals into their respective axis world space
316 | // a bit arbitrarily.
317 | normalX = vec3(0.0, -normalX.y, normalX.x);
318 | normalY = vec3(normalY.x, 0.0, normalY.y);
319 | normalZ = vec3(normalZ.x, -normalZ.y, 0.0);
320 |
321 | // Mix the normal map normals together based on blend
322 | vec3 bumpNormal = normalX * blend.x
323 | + normalY * blend.y
324 | + normalZ * blend.z;
325 | vec3 normal = normalize(bumpNormal);
326 |
327 | normal = normalize(vNormal + g_NormalMatrix * bumpNormal);
328 |
329 | // Moved this to after trilinear mapping is performed so that the color
330 | // will be accurate
331 | #ifndef VERTEX_LIGHTING
332 | float spotFallOff = 1.0;
333 |
334 | #if __VERSION__ >= 110
335 | // allow use of control flow
336 | if(g_LightDirection.w != 0.0){
337 | #endif
338 |
339 | vec3 L = normalize(lightVec.xyz);
340 | vec3 spotdir = normalize(g_LightDirection.xyz);
341 | float curAngleCos = dot(-L, spotdir);
342 | float innerAngleCos = floor(g_LightDirection.w) * 0.001;
343 | float outerAngleCos = fract(g_LightDirection.w);
344 | float innerMinusOuter = innerAngleCos - outerAngleCos;
345 | spotFallOff = (curAngleCos - outerAngleCos) / innerMinusOuter;
346 |
347 | #if __VERSION__ >= 110
348 | if(spotFallOff <= 0.0){
349 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
350 | gl_FragColor.a = alpha;
351 | return;
352 | }else{
353 | spotFallOff = clamp(spotFallOff, 0.0, 1.0);
354 | }
355 | }
356 | #else
357 | spotFallOff = clamp(spotFallOff, step(g_LightDirection.w, 0.001), 1.0);
358 | #endif
359 | #endif
360 |
361 | #ifdef SPECULARMAP
362 | vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
363 | #else
364 | vec4 specularColor = vec4(1.0);
365 | #endif
366 |
367 | #ifdef LIGHTMAP
368 | vec3 lightMapColor;
369 | #ifdef SEPARATE_TEXCOORD
370 | lightMapColor = texture2D(m_LightMap, texCoord2).rgb;
371 | #else
372 | lightMapColor = texture2D(m_LightMap, texCoord.xz).rgb;
373 | #endif
374 | specularColor.rgb *= lightMapColor;
375 | diffuseColor.rgb *= lightMapColor;
376 | #endif
377 |
378 | #ifdef VERTEX_LIGHTING
379 | vec2 light = vertexLightValues.xy;
380 | #ifdef COLORRAMP
381 | light.x = texture2D(m_ColorRamp, vec2(light.x, 0.0)).r;
382 | light.y = texture2D(m_ColorRamp, vec2(light.y, 0.0)).r;
383 | #endif
384 |
385 | #ifndef USE_SCATTERING
386 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb +
387 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
388 | SpecularSum * specularColor.rgb * vec3(light.y);
389 | #else
390 | vec3 color = AmbientSum * diffuseColor.rgb +
391 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
392 | SpecularSum * specularColor.rgb * vec3(light.y);
393 | gl_FragColor.rgb = calculateGroundColor(vec4(color, 1.0)).rgb;
394 | #endif
395 | #else
396 | vec4 lightDir = vLightDir;
397 | lightDir.xyz = normalize(lightDir.xyz);
398 | vec3 viewDir = normalize(vViewDir);
399 |
400 | vec2 light = computeLighting(normal, viewDir, lightDir.xyz) * spotFallOff;
401 | #ifdef COLORRAMP
402 | diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
403 | specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
404 | #endif
405 |
406 | // Workaround, since it is not possible to modify varying variables
407 | vec4 SpecularSum2 = vec4(SpecularSum, 1.0);
408 | #ifdef USE_REFLECTION
409 | vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz);
410 |
411 | // Interpolate light specularity toward reflection color
412 | // Multiply result by specular map
413 | specularColor = mix(SpecularSum2 * light.y, refColor, refVec.w) * specularColor;
414 |
415 | SpecularSum2 = vec4(1.0);
416 | light.y = 1.0;
417 | #endif
418 |
419 | #ifndef USE_SCATTERING
420 | gl_FragColor.rgb = AmbientSum * diffuseColor.rgb +
421 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
422 | SpecularSum * specularColor.rgb * vec3(light.y);
423 | #else
424 | vec3 color = AmbientSum * diffuseColor.rgb +
425 | DiffuseSum.rgb * diffuseColor.rgb * vec3(light.x) +
426 | SpecularSum * specularColor.rgb * vec3(light.y);
427 | gl_FragColor.rgb = calculateGroundColor(vec4(color, 1.0)).rgb;
428 | #endif
429 | #endif
430 | gl_FragColor.a = alpha;
431 | }
432 |
--------------------------------------------------------------------------------
/assets/MatDefs/TrilinearLighting.j3md:
--------------------------------------------------------------------------------
1 | MaterialDef Phong Lighting {
2 |
3 | MaterialParameters {
4 |
5 | // Compute vertex lighting in the shader
6 | // For better performance
7 | Boolean VertexLighting
8 |
9 | // Use more efficent algorithms to improve performance
10 | Boolean LowQuality
11 |
12 | // Improve quality at the cost of performance
13 | Boolean HighQuality
14 |
15 | // Output alpha from the diffuse map
16 | Boolean UseAlpha
17 |
18 | // Alpha threshold for fragment discarding
19 | Float AlphaDiscardThreshold (AlphaTestFallOff)
20 |
21 | // Normal map is in BC5/ATI2n/LATC/3Dc compression format
22 | Boolean LATC
23 |
24 | // Use the provided ambient, diffuse, and specular colors
25 | Boolean UseMaterialColors
26 |
27 | // Activate shading along the tangent, instead of the normal
28 | // Requires tangent data to be available on the model.
29 | Boolean VTangent
30 |
31 | // Use minnaert diffuse instead of lambert
32 | Boolean Minnaert
33 |
34 | // Use ward specular instead of phong
35 | Boolean WardIso
36 |
37 | // Use vertex color as an additional diffuse color.
38 | Boolean UseVertexColor
39 |
40 | // Ambient color
41 | Color Ambient (MaterialAmbient)
42 |
43 | // Diffuse color
44 | Color Diffuse (MaterialDiffuse)
45 |
46 | // Specular color
47 | Color Specular (MaterialSpecular)
48 |
49 | // Specular power/shininess
50 | Float Shininess (MaterialShininess) : 1
51 |
52 | // Diffuse map
53 | Texture2D DiffuseMap
54 |
55 | // Normal map
56 | Texture2D NormalMap
57 |
58 | // Specular/gloss map
59 | Texture2D SpecularMap
60 |
61 | // Parallax/height map
62 | Texture2D ParallaxMap
63 |
64 | //Set to true is parallax map is stored in the alpha channel of the normal map
65 | Boolean PackedNormalParallax
66 |
67 | //Sets the relief height for parallax mapping
68 | Float ParallaxHeight : 0.05
69 |
70 | //Set to true to activate Steep Parallax mapping
71 | Boolean SteepParallax
72 |
73 | // Texture that specifies alpha values
74 | Texture2D AlphaMap
75 |
76 | // Color ramp, will map diffuse and specular values through it.
77 | Texture2D ColorRamp
78 |
79 | // Texture of the glowing parts of the material
80 | Texture2D GlowMap
81 |
82 | // Set to Use Lightmap
83 | Texture2D LightMap
84 |
85 | // Set to use TexCoord2 for the lightmap sampling
86 | Boolean SeparateTexCoord
87 |
88 | // The glow color of the object
89 | Color GlowColor
90 |
91 | // Parameters for fresnel
92 | // X = bias
93 | // Y = scale
94 | // Z = power
95 | Vector3 FresnelParams
96 |
97 | // Env Map for reflection
98 | TextureCubeMap EnvMap
99 |
100 | // the env map is a spheremap and not a cube map
101 | Boolean EnvMapAsSphereMap
102 |
103 | //shadows
104 | Int FilterMode
105 | Boolean HardwareShadows
106 |
107 | Texture2D ShadowMap0
108 | Texture2D ShadowMap1
109 | Texture2D ShadowMap2
110 | Texture2D ShadowMap3
111 | //pointLights
112 | Texture2D ShadowMap4
113 | Texture2D ShadowMap5
114 |
115 | Float ShadowIntensity
116 | Vector4 Splits
117 | Vector2 FadeInfo
118 |
119 | Matrix4 LightViewProjectionMatrix0
120 | Matrix4 LightViewProjectionMatrix1
121 | Matrix4 LightViewProjectionMatrix2
122 | Matrix4 LightViewProjectionMatrix3
123 | //pointLight
124 | Matrix4 LightViewProjectionMatrix4
125 | Matrix4 LightViewProjectionMatrix5
126 | Vector3 LightPos
127 |
128 | Float PCFEdge
129 | Float ShadowMapSize
130 |
131 | // For hardware skinning
132 | Int NumberOfBones
133 | Matrix4Array BoneMatrices
134 |
135 | // For the trilinear mapping
136 | Vector3 WorldOffset
137 |
138 | Texture2D DiffuseMapLow
139 |
140 | Texture2D DiffuseMapX
141 | Texture2D DiffuseMapY
142 | Texture2D DiffuseMapZ
143 |
144 | Texture2D NormalMapX
145 | Texture2D NormalMapY
146 | Texture2D NormalMapZ
147 |
148 | Texture2D Noise
149 | Float LowResDistance: 32.0
150 |
151 | // Ground scattering parameters
152 | Boolean UseScattering
153 | Vector3 SunPosition
154 | Float Exposure
155 | Float KmESun
156 | Float InnerRadius
157 | Float RadiusScale
158 | Float PlanetScale : 1
159 | Vector3 InvWavelengthsKrESun
160 | Float AverageDensityScale
161 | Float InvAverageDensityHeight;
162 | Vector3 KWavelengths4PI;
163 |
164 | }
165 |
166 | Technique {
167 |
168 | LightMode MultiPass
169 |
170 | VertexShader GLSL110: MatDefs/TrilinearLighting.vert
171 | FragmentShader GLSL110: MatDefs/TrilinearLighting.frag
172 |
173 | WorldParameters {
174 | WorldViewProjectionMatrix
175 | NormalMatrix
176 | WorldViewMatrix
177 | ViewMatrix
178 | CameraPosition
179 | WorldMatrix
180 | }
181 |
182 | Defines {
183 | LATC : LATC
184 | VERTEX_COLOR : UseVertexColor
185 | VERTEX_LIGHTING : VertexLighting
186 | ATTENUATION : Attenuation
187 | MATERIAL_COLORS : UseMaterialColors
188 | V_TANGENT : VTangent
189 | MINNAERT : Minnaert
190 | WARDISO : WardIso
191 | LOW_QUALITY : LowQuality
192 | HQ_ATTENUATION : HighQuality
193 |
194 | DIFFUSEMAP : DiffuseMap
195 | // For now, we won't set this
196 | // NORMALMAP : NormalMap
197 | SPECULARMAP : SpecularMap
198 | PARALLAXMAP : ParallaxMap
199 | NORMALMAP_PARALLAX : PackedNormalParallax
200 | STEEP_PARALLAX : SteepParallax
201 | ALPHAMAP : AlphaMap
202 | COLORRAMP : ColorRamp
203 | LIGHTMAP : LightMap
204 | SEPARATE_TEXCOORD : SeparateTexCoord
205 |
206 | USE_REFLECTION : EnvMap
207 | SPHERE_MAP : SphereMap
208 |
209 | NUM_BONES : NumberOfBones
210 |
211 | USE_SCATTERING : UseScattering
212 | }
213 | }
214 |
215 | Technique PreShadow {
216 |
217 | VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert
218 | FragmentShader GLSL100 : Common/MatDefs/Shadow/PreShadow.frag
219 |
220 | WorldParameters {
221 | WorldViewProjectionMatrix
222 | WorldViewMatrix
223 | }
224 |
225 | Defines {
226 | COLOR_MAP : ColorMap
227 | DISCARD_ALPHA : AlphaDiscardThreshold
228 | NUM_BONES : NumberOfBones
229 | }
230 |
231 | ForcedRenderState {
232 | FaceCull Off
233 | DepthTest On
234 | DepthWrite On
235 | PolyOffset 5 3
236 | ColorWrite Off
237 | }
238 |
239 | }
240 |
241 |
242 | Technique PostShadow15{
243 | VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert
244 | FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag
245 |
246 | WorldParameters {
247 | WorldViewProjectionMatrix
248 | WorldMatrix
249 | }
250 |
251 | Defines {
252 | HARDWARE_SHADOWS : HardwareShadows
253 | FILTER_MODE : FilterMode
254 | PCFEDGE : PCFEdge
255 | DISCARD_ALPHA : AlphaDiscardThreshold
256 | COLOR_MAP : ColorMap
257 | SHADOWMAP_SIZE : ShadowMapSize
258 | FADE : FadeInfo
259 | PSSM : Splits
260 | POINTLIGHT : LightViewProjectionMatrix5
261 | NUM_BONES : NumberOfBones
262 | }
263 |
264 | ForcedRenderState {
265 | Blend Modulate
266 | DepthWrite Off
267 | PolyOffset -0.1 0
268 | }
269 | }
270 |
271 | Technique PostShadow{
272 | VertexShader GLSL100: Common/MatDefs/Shadow/PostShadow.vert
273 | FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadow.frag
274 |
275 | WorldParameters {
276 | WorldViewProjectionMatrix
277 | WorldMatrix
278 | }
279 |
280 | Defines {
281 | HARDWARE_SHADOWS : HardwareShadows
282 | FILTER_MODE : FilterMode
283 | PCFEDGE : PCFEdge
284 | DISCARD_ALPHA : AlphaDiscardThreshold
285 | COLOR_MAP : ColorMap
286 | SHADOWMAP_SIZE : ShadowMapSize
287 | FADE : FadeInfo
288 | PSSM : Splits
289 | POINTLIGHT : LightViewProjectionMatrix5
290 | NUM_BONES : NumberOfBones
291 | }
292 |
293 | ForcedRenderState {
294 | Blend Modulate
295 | DepthWrite Off
296 | PolyOffset -0.1 0
297 | }
298 | }
299 |
300 | Technique PreNormalPass {
301 |
302 | VertexShader GLSL100 : Common/MatDefs/SSAO/normal.vert
303 | FragmentShader GLSL100 : Common/MatDefs/SSAO/normal.frag
304 |
305 | WorldParameters {
306 | WorldViewProjectionMatrix
307 | WorldViewMatrix
308 | NormalMatrix
309 | }
310 |
311 | Defines {
312 | DIFFUSEMAP_ALPHA : DiffuseMap
313 | NUM_BONES : NumberOfBones
314 | }
315 |
316 | }
317 |
318 | Technique GBuf {
319 |
320 | VertexShader GLSL100: Common/MatDefs/Light/GBuf.vert
321 | FragmentShader GLSL100: Common/MatDefs/Light/GBuf.frag
322 |
323 | WorldParameters {
324 | WorldViewProjectionMatrix
325 | NormalMatrix
326 | WorldViewMatrix
327 | WorldMatrix
328 | }
329 |
330 | Defines {
331 | VERTEX_COLOR : UseVertexColor
332 | MATERIAL_COLORS : UseMaterialColors
333 | V_TANGENT : VTangent
334 | MINNAERT : Minnaert
335 | WARDISO : WardIso
336 |
337 | DIFFUSEMAP : DiffuseMap
338 | NORMALMAP : NormalMap
339 | SPECULARMAP : SpecularMap
340 | PARALLAXMAP : ParallaxMap
341 | }
342 | }
343 |
344 | Technique {
345 | LightMode FixedPipeline
346 | }
347 |
348 | Technique Glow {
349 |
350 | VertexShader GLSL100: Common/MatDefs/Misc/Unshaded.vert
351 | FragmentShader GLSL100: Common/MatDefs/Light/Glow.frag
352 |
353 | WorldParameters {
354 | WorldViewProjectionMatrix
355 | }
356 |
357 | Defines {
358 | NEED_TEXCOORD1
359 | HAS_GLOWMAP : GlowMap
360 | HAS_GLOWCOLOR : GlowColor
361 |
362 | NUM_BONES : NumberOfBones
363 | }
364 | }
365 |
366 | }
367 |
--------------------------------------------------------------------------------
/assets/MatDefs/TrilinearLighting.vert:
--------------------------------------------------------------------------------
1 | #define ATTENUATION
2 | //#define HQ_ATTENUATION
3 |
4 | #import "Common/ShaderLib/Skinning.glsllib"
5 | #import "MatDefs/VertScattering.glsllib"
6 |
7 | uniform mat4 g_WorldViewProjectionMatrix;
8 | uniform mat4 g_WorldViewMatrix;
9 | uniform mat4 g_WorldMatrix;
10 | uniform mat3 g_NormalMatrix;
11 | uniform mat4 g_ViewMatrix;
12 | uniform vec3 g_CameraPosition;
13 |
14 | uniform vec4 m_Ambient;
15 | uniform vec4 m_Diffuse;
16 | uniform vec4 m_Specular;
17 | uniform float m_Shininess;
18 |
19 | uniform vec4 g_LightColor;
20 | uniform vec4 g_LightPosition;
21 | uniform vec4 g_AmbientLightColor;
22 |
23 | // Trilinear mapping related settings
24 | uniform vec3 m_WorldOffset;
25 |
26 | varying vec3 worldNormal;
27 | varying float z;
28 |
29 | varying vec3 worldTangent;
30 |
31 | // end trilinear settings
32 |
33 | varying vec3 texCoord;
34 | #ifdef SEPARATE_TEXCOORD
35 | varying vec2 texCoord2;
36 | attribute vec2 inTexCoord2;
37 | #endif
38 |
39 | varying vec3 AmbientSum;
40 | varying vec4 DiffuseSum;
41 | varying vec3 SpecularSum;
42 |
43 | attribute vec3 inPosition;
44 | attribute vec2 inTexCoord;
45 | attribute vec3 inNormal;
46 |
47 | varying vec3 lightVec;
48 | //varying vec4 spotVec;
49 |
50 | #ifdef VERTEX_COLOR
51 | attribute vec4 inColor;
52 | #endif
53 |
54 | #ifndef VERTEX_LIGHTING
55 | attribute vec4 inTangent;
56 |
57 | #ifndef NORMALMAP
58 | varying vec3 vNormal;
59 | #else
60 | // For debugging we want it either way
61 | varying vec3 vNormal;
62 | #endif
63 | //varying vec3 vPosition;
64 | varying vec3 vViewDir;
65 | varying vec4 vLightDir;
66 | #else
67 | varying vec2 vertexLightValues;
68 | uniform vec4 g_LightDirection;
69 | #endif
70 |
71 |
72 | #ifdef USE_REFLECTION
73 | uniform vec3 g_CameraPosition;
74 | uniform mat4 g_WorldMatrix;
75 |
76 | uniform vec3 m_FresnelParams;
77 | varying vec4 refVec;
78 |
79 |
80 | /**
81 | * Input:
82 | * attribute inPosition
83 | * attribute inNormal
84 | * uniform g_WorldMatrix
85 | * uniform g_CameraPosition
86 | *
87 | * Output:
88 | * varying refVec
89 | */
90 | void computeRef(in vec4 modelSpacePos){
91 | vec3 worldPos = (g_WorldMatrix * modelSpacePos).xyz;
92 |
93 | vec3 I = normalize( g_CameraPosition - worldPos ).xyz;
94 | vec3 N = normalize( (g_WorldMatrix * vec4(inNormal, 0.0)).xyz );
95 |
96 | refVec.xyz = reflect(I, N);
97 | refVec.w = m_FresnelParams.x + m_FresnelParams.y * pow(1.0 + dot(I, N), m_FresnelParams.z);
98 | }
99 | #endif
100 |
101 | // JME3 lights in world space
102 | void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){
103 | float posLight = step(0.5, color.w);
104 | vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
105 | lightVec = tempVec;
106 | #ifdef ATTENUATION
107 | float dist = length(tempVec);
108 | lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
109 | lightDir.xyz = tempVec / vec3(dist);
110 | #else
111 | lightDir = vec4(normalize(tempVec), 1.0);
112 | #endif
113 | }
114 |
115 | #ifdef VERTEX_LIGHTING
116 | float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){
117 | return max(0.0, dot(norm, lightdir));
118 | }
119 |
120 | float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){
121 | if (shiny <= 1.0){
122 | return 0.0;
123 | }
124 | #ifndef LOW_QUALITY
125 | vec3 H = (viewdir + lightdir) * vec3(0.5);
126 | return pow(max(dot(H, norm), 0.0), shiny);
127 | #else
128 | return 0.0;
129 | #endif
130 | }
131 |
132 | vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec4 wvLightPos){
133 | vec4 lightDir;
134 | lightComputeDir(wvPos, g_LightColor, wvLightPos, lightDir);
135 | float spotFallOff = 1.0;
136 | if(g_LightDirection.w != 0.0){
137 | vec3 L=normalize(lightVec.xyz);
138 | vec3 spotdir = normalize(g_LightDirection.xyz);
139 | float curAngleCos = dot(-L, spotdir);
140 | float innerAngleCos = floor(g_LightDirection.w) * 0.001;
141 | float outerAngleCos = fract(g_LightDirection.w);
142 | float innerMinusOuter = innerAngleCos - outerAngleCos;
143 | spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0);
144 | }
145 | float diffuseFactor = lightComputeDiffuse(wvNorm, lightDir.xyz);
146 | float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, lightDir.xyz, m_Shininess);
147 | //specularFactor *= step(0.01, diffuseFactor);
148 | return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w)*spotFallOff;
149 | }
150 | #endif
151 |
152 | void main(){
153 | vec4 modelSpacePos = vec4(inPosition, 1.0);
154 | vec3 modelSpaceNorm = inNormal;
155 |
156 | #ifndef VERTEX_LIGHTING
157 | vec3 modelSpaceTan = inTangent.xyz;
158 | #endif
159 |
160 | #ifdef NUM_BONES
161 | #ifndef VERTEX_LIGHTING
162 | Skinning_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
163 | #else
164 | Skinning_Compute(modelSpacePos, modelSpaceNorm);
165 | #endif
166 | #endif
167 |
168 | gl_Position = g_WorldViewProjectionMatrix * modelSpacePos;
169 |
170 | // Trilinear mapping stores the world location of the vertex in the
171 | // texture coordinate. Not so much for mapping as for noise lookups
172 | texCoord = (g_WorldMatrix * modelSpacePos).xyz + m_WorldOffset;
173 |
174 | // We keep track of the world normal. This calculation would be
175 | // incorrect with non-linear scaling but we know our source mesh
176 | // shouldn't have that.
177 | worldNormal = (g_WorldMatrix * vec4(modelSpaceNorm, 0.0)).xyz;
178 |
179 | //texCoord = inTexCoord;
180 | #ifdef SEPARATE_TEXCOORD
181 | texCoord2 = inTexCoord2;
182 | #endif
183 |
184 | #ifdef USE_SCATTERING
185 | vec4 wPos = g_WorldMatrix * modelSpacePos;
186 | calculateVertexGroundScattering(wPos.xyz, g_CameraPosition);
187 | #endif
188 |
189 | vec3 wvPosition = (g_WorldViewMatrix * modelSpacePos).xyz;
190 | z = length(wvPosition);
191 | vec3 wvNormal = normalize(g_NormalMatrix * modelSpaceNorm);
192 | vec3 viewDir = normalize(-wvPosition);
193 |
194 | //vec4 lightColor = g_LightColor[gl_InstanceID];
195 | //vec4 lightPos = g_LightPosition[gl_InstanceID];
196 | //vec4 wvLightPos = (g_ViewMatrix * vec4(lightPos.xyz, lightColor.w));
197 | //wvLightPos.w = lightPos.w;
198 |
199 | vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0)));
200 | wvLightPos.w = g_LightPosition.w;
201 | vec4 lightColor = g_LightColor;
202 |
203 | #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
204 | // *** For trinlinear mapping we calculate the tangent
205 | // directly from the normal.
206 | //vec3 wvTangent = normalize(g_NormalMatrix * modelSpaceTan);
207 | //vec3 wvBinormal = cross(wvNormal, wvTangent);
208 |
209 | //mat3 tbnMat = mat3(wvTangent, wvBinormal * -inTangent.w,wvNormal);
210 |
211 | // We should probably be doing the tangent generation on the
212 | // frag side but JME is already setup to do lighting in view space
213 | // and I don't really want to unwind it. This is why we need the
214 | // tangent space here so that we can find the proper tangent-space
215 | // lighting vector.
216 | vec3 wn = normalize(worldNormal);
217 |
218 | #define BASIC_TANGENTS
219 | #ifdef BASIC_TANGENTS
220 | vec3 wTangentX = vec3(0.0, 0.0, -1.0);
221 | vec3 wTangentY = vec3(1.0, 0.0, 0.0);
222 | vec3 wTangentZ = vec3(1.0, 0.0, 0.0);
223 |
224 | // You'd think we might need to flip the signs but we
225 | // don't do it for the texture lookups so it's important
226 | // that each axis be reflective.
227 | vec3 blend = abs(wn);
228 | blend /= blend.x + blend.y + blend.z;
229 | #else
230 | vec3 wTangentX = normalize(vec3(wn.z, 0.0, -wn.x));
231 | vec3 wTangentY = normalize(vec3(wn.y, -wn.x, 0.0));
232 | vec3 wTangentZ = normalize(vec3(wn.z, 0.0, -wn.x));
233 |
234 | // Tangent vectors already include signs so mix
235 | // based on abs
236 | vec3 blend = abs(wn);
237 | blend /= blend.x + blend.y + blend.z;
238 | #endif
239 |
240 | // Both of the above approaches leave some oddly bright
241 | // areas of the terrain. I think this is due to dramatic
242 | // interpolation across faces with extremely divergent
243 | // normals. If it's true then the only way to solve it
244 | // would be to do lighting in world space and just assume
245 | // tangents on the frag side.
246 |
247 | // which I think if I just pretend that normal maps don't
248 | // exist here then I can do all tangent stuff on the frag side.
249 |
250 | worldTangent = normalize(wTangentX * blend.x
251 | + wTangentY * blend.y
252 | + wTangentZ * blend.z);
253 | vec3 wvTangent = normalize((g_ViewMatrix * vec4(worldTangent, 0.0)).xyz);
254 | vec3 wvBinormal = normalize(cross(wvNormal, wvTangent));
255 | wvTangent = normalize(cross(wvBinormal, wvNormal));
256 | mat3 tbnMat = mat3(wvTangent, wvBinormal * -1.0, wvNormal);
257 |
258 | //vPosition = wvPosition * tbnMat;
259 | //vViewDir = viewDir * tbnMat;
260 | vViewDir = -wvPosition * tbnMat;
261 | lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir);
262 | vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz;
263 |
264 | // For debugging purposes. Note: when normal maps are used
265 | // the light is in tangent space. In tangent space the normal
266 | // is just a z unit vector
267 | vNormal = vec3(0.0, 0.0, 1.0); //wvNormal;
268 | #elif !defined(VERTEX_LIGHTING)
269 | vNormal = wvNormal;
270 |
271 | //vPosition = wvPosition;
272 | vViewDir = viewDir;
273 |
274 | lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir);
275 |
276 | #ifdef V_TANGENT
277 | vNormal = normalize(g_NormalMatrix * inTangent.xyz);
278 | vNormal = -cross(cross(vLightDir.xyz, vNormal), vNormal);
279 | #endif
280 | #endif
281 |
282 | //computing spot direction in view space and unpacking spotlight cos
283 | // spotVec = (g_ViewMatrix * vec4(g_LightDirection.xyz, 0.0) );
284 | // spotVec.w = floor(g_LightDirection.w) * 0.001;
285 | // lightVec.w = fract(g_LightDirection.w);
286 |
287 | lightColor.w = 1.0;
288 | #ifdef MATERIAL_COLORS
289 | AmbientSum = (m_Ambient * g_AmbientLightColor).rgb;
290 | DiffuseSum = m_Diffuse * lightColor;
291 | SpecularSum = (m_Specular * lightColor).rgb;
292 | #else
293 | AmbientSum = vec3(0.2, 0.2, 0.2) * g_AmbientLightColor.rgb; // Default: ambient color is dark gray
294 | DiffuseSum = lightColor;
295 | SpecularSum = vec3(0.0);
296 | #endif
297 |
298 | #ifdef VERTEX_COLOR
299 | AmbientSum *= inColor.rgb;
300 | DiffuseSum *= inColor;
301 | #endif
302 |
303 | #ifdef VERTEX_LIGHTING
304 | vertexLightValues = computeLighting(wvPosition, wvNormal, viewDir, wvLightPos);
305 | #endif
306 |
307 | #ifdef USE_REFLECTION
308 | computeRef(modelSpacePos);
309 | #endif
310 | }
311 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Builds, tests, and runs the project BasicGameTemplate.
12 |
13 |
14 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/nbproject/assets-impl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/nbproject/genfiles.properties:
--------------------------------------------------------------------------------
1 | build.xml.data.CRC32=94bf7c61
2 | build.xml.script.CRC32=79a29eb7
3 | build.xml.stylesheet.CRC32=958a1d3e@1.32.1.45
4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6 | nbproject/build-impl.xml.data.CRC32=6c4d25c0
7 | nbproject/build-impl.xml.script.CRC32=17b92ddc
8 | nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48
9 |
--------------------------------------------------------------------------------
/nbproject/project.properties:
--------------------------------------------------------------------------------
1 | annotation.processing.enabled=true
2 | annotation.processing.enabled.in.editor=false
3 | annotation.processing.processors.list=
4 | annotation.processing.run.all.processors=true
5 | application.title=IsoSurfaceLib
6 | application.vendor=Simsilica, LLC
7 | assets.jar.name=iso-surface-assets.jar
8 | assets.excludes=**/*.j3odata,**/*.mesh,**/*.skeleton,**/*.mesh.xml,**/*.skeleton.xml,**/*.scene,**/*.material,**/*.obj,**/*.mtl,**/*.3ds,**/*.dae,**/*.blend,**/*.blend*[0-9],**/.backups/**,**/*.psd
9 | assets.folder.name=assets
10 | assets.compress=true
11 | build.classes.dir=${build.dir}/classes
12 | build.classes.excludes=**/*.java,**/*.form,**/.backups/**
13 | # This directory is removed when the project is cleaned:
14 | build.dir=build
15 | build.generated.dir=${build.dir}/generated
16 | build.generated.sources.dir=${build.dir}/generated-sources
17 | # Only compile against the classpath explicitly listed here:
18 | build.sysclasspath=ignore
19 | build.test.classes.dir=${build.dir}/test/classes
20 | build.test.results.dir=${build.dir}/test/results
21 | compile.on.save=true
22 | # Uncomment to specify the preferred debugger connection transport:
23 | #debug.transport=dt_socket
24 | debug.classpath=\
25 | ${run.classpath}
26 | debug.test.classpath=\
27 | ${run.test.classpath}
28 | # This directory is removed when the project is cleaned:
29 | dist.dir=dist
30 | dist.jar=${dist.dir}/${application.title}.jar
31 | dist.javadoc.dir=${dist.dir}/javadoc
32 | endorsed.classpath=
33 | excludes=
34 | file.reference.guava-12.0.jar-1=lib\\guava-12.0.jar
35 | file.reference.slf4j-api-1.7.5.jar-1=lib\\slf4j-api-1.7.5.jar
36 | includes=**
37 | jar.compress=true
38 | javac.classpath=\
39 | ${reference.Pager.jar}:\
40 | ${file.reference.guava-12.0.jar-1}:\
41 | ${file.reference.slf4j-api-1.7.5.jar-1}:\
42 | ${libs.jme3-core.classpath}
43 | # Space-separated list of extra javac options
44 | javac.compilerargs=
45 | javac.deprecation=false
46 | javac.processorpath=\
47 | ${javac.classpath}
48 | javac.source=1.6
49 | javac.target=1.6
50 | javac.test.classpath=\
51 | ${javac.classpath}:\
52 | ${build.classes.dir}
53 | javadoc.additionalparam=
54 | javadoc.author=false
55 | javadoc.encoding=${source.encoding}
56 | javadoc.noindex=false
57 | javadoc.nonavbar=false
58 | javadoc.notree=false
59 | javadoc.private=false
60 | javadoc.splitindex=true
61 | javadoc.use=true
62 | javadoc.version=false
63 | javadoc.windowtitle=
64 | jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
65 | jnlp.codebase.type=local
66 | jnlp.descriptor=application
67 | jnlp.enabled=false
68 | jnlp.offline-allowed=false
69 | jnlp.signed=false
70 | main.class=mygame.Main
71 | meta.inf.dir=${src.dir}/META-INF
72 | manifest.file=MANIFEST.MF
73 | mkdist.disabled=false
74 | platform.active=JDK_1.7
75 | project.Pager=../Pager
76 | reference.Pager.jar=${project.Pager}/dist/Pager.jar
77 | run.classpath=\
78 | ${javac.classpath}:\
79 | ${build.classes.dir}:\
80 | ${assets.folder.name}
81 | # Space-separated list of JVM arguments used when running the project
82 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
83 | # or test-sys-prop.name=value to set system properties for unit tests):
84 | run.jvmargs=
85 | run.test.classpath=\
86 | ${javac.test.classpath}:\
87 | ${build.test.classes.dir}
88 | source.encoding=UTF-8
89 | src.java.dir=src\\main\\java
90 |
--------------------------------------------------------------------------------
/nbproject/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.netbeans.modules.java.j2seproject
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | IsoSurface
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Pager
21 | jar
22 |
23 | jar
24 | clean
25 | jar
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/DensityVolume.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso;
38 |
39 | import com.jme3.math.Vector3f;
40 |
41 |
42 | /**
43 | * Represents a volume of space from which density
44 | * values may be sampled. Default implementations can be
45 | * found in com.simsilica.iso.volume.
46 | *
47 | * @author Paul Speed
48 | */
49 | public interface DensityVolume {
50 |
51 | /**
52 | * Retrieves a density value at a specific integer grid corner.
53 | * For some density volumes this may be optimized to avoid
54 | * trilinear interpolation.
55 | */
56 | public float getDensity( int x, int y, int z );
57 |
58 | /**
59 | * Retrieves a density value from the specified point in
60 | * this volume.
61 | */
62 | public float getDensity( float x, float y, float z );
63 |
64 | /**
65 | * Retrieves the field direction at a particular point in this
66 | * volume. Field direction can be used to define surface normals,
67 | * potentially predict collisions, etc..
68 | */
69 | public Vector3f getFieldDirection( float x, float y, float z, Vector3f target );
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/IsoTerrainZone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso;
38 |
39 | import com.google.common.base.Supplier;
40 | import com.jme3.material.Material;
41 | import com.jme3.math.Vector3f;
42 | import com.jme3.renderer.queue.RenderQueue;
43 | import com.jme3.scene.Geometry;
44 | import com.jme3.scene.Mesh;
45 | import com.jme3.scene.Node;
46 | import com.jme3.scene.Spatial;
47 | import com.jme3.scene.VertexBuffer;
48 | import com.jme3.util.BufferUtils;
49 | import com.simsilica.builder.Builder;
50 | import com.simsilica.iso.volume.ArrayDensityVolume;
51 | import com.simsilica.pager.Grid;
52 | import com.simsilica.pager.Zone;
53 | import java.util.concurrent.locks.ReentrantLock;
54 | import org.slf4j.Logger;
55 | import org.slf4j.LoggerFactory;
56 |
57 |
58 | /**
59 | * A Zone implementation that uses a MeshGenerator and a
60 | * density field to generator a terrain section.
61 | *
62 | * @author Paul Speed
63 | */
64 | public class IsoTerrainZone implements Zone {
65 |
66 | static Logger log = LoggerFactory.getLogger(IsoTerrainZone.class);
67 |
68 | private int xCell;
69 | private int yCell;
70 | private int zCell;
71 | private Grid grid;
72 | private Vector3f volumeSize;
73 | private Vector3f volumeOffset;
74 | private DensityVolume source;
75 | private int priority;
76 | private Node node;
77 | private Spatial land;
78 | private Spatial wire;
79 | private Supplier extends MeshGenerator> generator;
80 | private Material terrainMaterial;
81 | private boolean generateCollisionData;
82 |
83 | // For testing to make sure the builder and the pager are not
84 | // competing. Leaving it in is just a bit of paranoia
85 | private final ReentrantLock accessLock = new ReentrantLock();
86 |
87 | private static ThreadLocal cachedVolume = new ThreadLocal();
88 |
89 | public IsoTerrainZone( int xCell, int yCell, int zCell, Grid grid,
90 | Vector3f volumeSize, Vector3f volumeOffset,
91 | DensityVolume source,
92 | Supplier extends MeshGenerator> generator,
93 | Material terrainMaterial,
94 | boolean generateCollisionData )
95 | {
96 | this.xCell = xCell;
97 | this.yCell = yCell;
98 | this.zCell = zCell;
99 | this.grid = grid;
100 | this.volumeSize = volumeSize;
101 | this.volumeOffset = volumeOffset;
102 | this.source = source;
103 | this.generator = generator;
104 | this.terrainMaterial = terrainMaterial;
105 | this.generateCollisionData = generateCollisionData;
106 | this.node = new Node("Terrain[" + xCell + ", " + yCell + ", " + zCell + "]");
107 | }
108 |
109 | public boolean setRelativeGridLocation( int x, int y, int z ) {
110 | return false;
111 | }
112 |
113 | public boolean setViewLocation( float x, float z ) {
114 | return false;
115 | }
116 |
117 | public Grid getGrid() {
118 | return grid;
119 | }
120 |
121 | public int getXCell() {
122 | return xCell;
123 | }
124 |
125 | public int getYCell() {
126 | return yCell;
127 | }
128 |
129 | public int getZCell() {
130 | return zCell;
131 | }
132 |
133 | public float getXWorld() {
134 | return grid.toWorldX(xCell);
135 | }
136 |
137 | public float getYWorld() {
138 | return grid.toWorldY(yCell);
139 | }
140 |
141 | public float getZWorld() {
142 | return grid.toWorldZ(zCell);
143 | }
144 |
145 | public Vector3f getWorldLocation( Vector3f target ) {
146 | return grid.toWorld(xCell, yCell, zCell, target);
147 | }
148 |
149 | public void setMeshGenerator( Supplier extends MeshGenerator> generator ) {
150 | this.generator = generator;
151 | }
152 |
153 | public void resetPriority( int xCenter, int yCenter, int zCenter, int bias )
154 | {
155 | int dx = xCell - xCenter;
156 | int dz = zCell - zCenter;
157 | this.priority = bias * (int)Math.sqrt(dx * dx + dz * dz);
158 | }
159 |
160 | public int getPriority() {
161 | return priority;
162 | }
163 |
164 | public Node getNode() {
165 | return node;
166 | }
167 |
168 | public Node getZoneRoot() {
169 | return node;
170 | }
171 |
172 | public void setParentZone( Zone parentZone ) {
173 | }
174 |
175 | public void build() {
176 | if( log.isInfoEnabled() ) {
177 | log.info("Building:" + xCell + ", " + yCell + ", " + zCell + " priority:" + priority);
178 | }
179 |
180 | accessLock.lock();
181 | try {
182 | long start = System.nanoTime();
183 |
184 | int x = (int)(volumeOffset.x + xCell * volumeSize.x);
185 | int y = (int)(volumeOffset.y + yCell * volumeSize.y);
186 | int z = (int)(volumeOffset.z + zCell * volumeSize.z);
187 |
188 | MeshGenerator mg = generator.get();
189 | Vector3f size = mg.getRequiredVolumeSize();
190 | int cx = (int)size.x;
191 | int cy = (int)size.y;
192 | int cz = (int)size.z;
193 |
194 | // Note: we presume in this caching strategy that the
195 | // required volume size never changes. But that's a reasonable
196 | // assumption since if it did then a new terrain pager or factory
197 | // should have been created for about a dozen other reasons.
198 | ArrayDensityVolume volume = cachedVolume.get();
199 | if( volume == null ) {
200 | volume = ArrayDensityVolume.extractVolume(source, x, y, z, cx, cy, cz);
201 | cachedVolume.set(volume);
202 | } else {
203 | volume.extract(source, x, y, z);
204 | }
205 |
206 | long time1 = System.nanoTime();
207 | long time2 = time1;
208 |
209 | Mesh landMesh = generator.get().buildMesh(volume);
210 | if( landMesh != null ) {
211 | land = createLand(landMesh, false);
212 | if( log.isDebugEnabled() ) {
213 | log.debug("volume size:" + volumeSize);
214 | log.debug("bounding shape:" + landMesh.getBound());
215 | }
216 | land.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
217 | time2 = System.nanoTime();
218 | if( generateCollisionData ) {
219 | landMesh.createCollisionData();
220 | }
221 | } else {
222 | land = null;
223 | log.debug("Empty mesh.");
224 | }
225 | long end = System.nanoTime();
226 |
227 | if( log.isInfoEnabled() ) {
228 | log.info("Total generation time:" + ((end-start)/1000000.0) + " ms");
229 | log.info(" Density field:" + ((time1-start)/1000000.0) + " ms");
230 | log.info(" Mesh generation:" + ((time2-time1)/1000000.0) + " ms");
231 | log.info(" Collision data generation:" + ((end-time2)/1000000.0) + " ms");
232 | }
233 | } finally {
234 | accessLock.unlock();
235 | }
236 | }
237 |
238 | @Override
239 | public void apply( Builder builder ) {
240 | if( !accessLock.tryLock() ) {
241 | throw new IllegalStateException("Thread is still building.");
242 | }
243 | try {
244 | if( land != null ) {
245 | node.attachChild(land);
246 | }
247 | } finally {
248 | accessLock.unlock();
249 | }
250 | }
251 |
252 | @Override
253 | public void release( Builder builder ) {
254 | if( log.isTraceEnabled() ) {
255 | log.trace("IsoLandReference.release():" + this );
256 | }
257 |
258 | if( !accessLock.tryLock() ) {
259 | throw new IllegalStateException("Thread is still building.");
260 | }
261 | try {
262 | // Should queue the buffers to be freed
263 | // or something.
264 | // ...for now we will free them directly.
265 | if( land != null ) {
266 | Mesh mesh = ((Geometry)land).getMesh();
267 | for( VertexBuffer vb : mesh.getBufferList() ) {
268 | if( log.isTraceEnabled() ) {
269 | log.trace("--destroying buffer:" + vb );
270 | }
271 | BufferUtils.destroyDirectBuffer( vb.getData() );
272 | }
273 | }
274 | } finally {
275 | accessLock.unlock();
276 | }
277 | }
278 |
279 | protected Spatial createLand( Mesh mesh, boolean glass )
280 | {
281 | Geometry geom = new Geometry("landGeometry[" + xCell + ", " + yCell + ", " + zCell + "]", mesh);
282 | geom.setMaterial(terrainMaterial);
283 | return geom;
284 | }
285 |
286 | /*protected Spatial createWireLand( Mesh mesh )
287 | {
288 | Geometry geom = new Geometry("wireLandGeometry[" + xCell + ", " + yCell + ", " + zCell + "]", mesh);
289 | geom.setMaterial(wireMaterial);
290 | geom.setQueueBucket(Bucket.Transparent);
291 | return geom;
292 | }*/
293 |
294 | @Override
295 | public String toString() {
296 | return "IsoLandReference[" + xCell + ", " + yCell + ", " + zCell + "]";
297 | }
298 | }
299 |
300 |
301 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/IsoTerrainZoneFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso;
38 |
39 | import com.google.common.base.Supplier;
40 | import com.jme3.material.Material;
41 | import com.jme3.math.Vector3f;
42 | import com.simsilica.pager.PagedGrid;
43 | import com.simsilica.pager.Zone;
44 | import com.simsilica.pager.ZoneFactory;
45 |
46 |
47 | /**
48 | * Creates IsoTerrainZones that carve out specific sections of
49 | * a supplied world DensityVolume and use a supplied MeshGenerator
50 | * to build meshes.
51 | *
52 | * @author Paul Speed
53 | */
54 | public class IsoTerrainZoneFactory implements ZoneFactory {
55 |
56 | private DensityVolume worldVolume;
57 | private Supplier extends MeshGenerator> generator;
58 | private Vector3f volumeSize;
59 | private Vector3f volumeOffset;
60 | private Material terrainMaterial;
61 | private boolean generateCollisionData;
62 |
63 | public IsoTerrainZoneFactory( DensityVolume worldVolume,
64 | Vector3f volumeSize, Vector3f volumeOffset,
65 | Supplier extends MeshGenerator> generator,
66 | Material terrainMaterial,
67 | boolean generateCollisionData ) {
68 | this.worldVolume = worldVolume;
69 | this.generator = generator;
70 | this.volumeSize = volumeSize;
71 | this.volumeOffset = volumeOffset;
72 | this.terrainMaterial = terrainMaterial;
73 | this.generateCollisionData = generateCollisionData;
74 | }
75 |
76 | public Zone createZone( PagedGrid pg, int xCell, int yCell, int zCell ) {
77 |
78 | IsoTerrainZone result = new IsoTerrainZone(xCell, yCell, zCell, pg.getGrid(),
79 | volumeSize, volumeOffset, worldVolume,
80 | generator, terrainMaterial,
81 | generateCollisionData);
82 |
83 | return result;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/MeshGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso;
38 |
39 | import com.jme3.math.Vector3f;
40 | import com.jme3.scene.Mesh;
41 |
42 |
43 | /**
44 | *
45 | * @author Paul Speed
46 | */
47 | public interface MeshGenerator {
48 |
49 | /**
50 | * Returns the size of the density volume required for mesh
51 | * generation.
52 | */
53 | public Vector3f getRequiredVolumeSize();
54 |
55 | /**
56 | * Returns the predicted size of the generated meshes.
57 | */
58 | public Vector3f getGenerationSize();
59 |
60 | /**
61 | * Builds a mesh from the specified density volume.
62 | */
63 | public Mesh buildMesh( DensityVolume volume );
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/collision/Collider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.collision;
38 |
39 | import com.jme3.math.Vector3f;
40 |
41 |
42 | /**
43 | *
44 | *
45 | * @author Paul Speed
46 | */
47 | public interface Collider {
48 |
49 | public Contact getContact( Vector3f loc, float radius );
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/collision/Contact.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.collision;
38 |
39 | import com.jme3.math.Vector3f;
40 |
41 |
42 | /**
43 | * Simple collider to collider collision information.
44 | *
45 | * @author Paul Speed
46 | */
47 | public class Contact {
48 | public Collider collider1;
49 | public Collider collider2;
50 | public Vector3f contactPoint;
51 | public Vector3f contactNormal;
52 | public float penetration;
53 |
54 | public Contact() {
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return "Contact[cp=" + contactPoint + ", cn=" + contactNormal + ", pen=" + penetration + "]";
60 | }
61 | }
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/collision/SimpleVolumeCollider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.collision;
38 |
39 | import com.jme3.math.Vector3f;
40 | import com.simsilica.iso.DensityVolume;
41 |
42 |
43 | /**
44 | *
45 | *
46 | * @author Paul Speed
47 | */
48 | public class SimpleVolumeCollider implements Collider {
49 | private DensityVolume volume;
50 |
51 | public SimpleVolumeCollider( DensityVolume volume ) {
52 | this.volume = volume;
53 | }
54 |
55 | @Override
56 | public Contact getContact( Vector3f loc, float radius ) {
57 |
58 | // Check the density in the direction of the surface
59 | // to the best of our ability to estimate
60 | Vector3f dir = volume.getFieldDirection(1 + loc.x, 1 + loc.y, 1 + loc.z, null);
61 | float density = volume.getDensity(1 + loc.x - dir.x * radius,
62 | 1 + loc.y - dir.y * radius,
63 | 1 + loc.z - dir.z * radius);
64 |
65 | if( density < 0 ) {
66 | // We are not in contact
67 | return null;
68 | }
69 |
70 | // Else try to calculate the intersection
71 | float center = volume.getDensity(1 + loc.x, 1 + loc.y, 1 + loc.z);
72 |
73 | float pen;
74 | Vector3f cp;
75 |
76 | if( center > 0 ) {
77 | // we are deep in it... try to see if we can guess a way
78 | // out
79 | float outside = volume.getDensity(1 + loc.x + dir.x,
80 | 1 + loc.y + dir.y,
81 | 1 + loc.z + dir.z);
82 | float part = Math.abs(center) / Math.abs(center - outside);
83 | pen = part;
84 | //System.out.println( "outside:" + outside + " center:" + center + " part:" + part + " pen:" + pen );
85 |
86 | // Calculate a contact point
87 | cp = loc.add(dir.mult(radius - pen));
88 | //System.out.println( "loc:" + loc + " cp:" + cp );
89 | } else {
90 | float part = Math.abs(density) / Math.abs(density - center);
91 | pen = radius * part;
92 | //System.out.println( "density:" + density + " center:" + center + " part:" + part + " pen:" + pen );
93 |
94 | // Calculate a contact point
95 | cp = loc.add(dir.mult(radius - pen));
96 | //System.out.println( "loc:" + loc + " cp:" + cp );
97 | }
98 |
99 | Contact result = new Contact();
100 | result.contactPoint = cp;
101 | result.contactNormal = volume.getFieldDirection(1 + cp.x, 1 + cp.y, 1 + cp.z, null);
102 | result.penetration = pen;
103 |
104 | return result;
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/fractal/GemsFractalDensityVolume.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.fractal;
38 |
39 | import com.jme3.math.Quaternion;
40 | import com.jme3.math.Vector3f;
41 | import com.simsilica.iso.DensityVolume;
42 |
43 |
44 | /**
45 | * DensityVolume implementation returning densities based on the
46 | * fractal defined in the GPU Gems book. Some adaptations as necessary
47 | * to convert from a shader-based algorithm to a Java-based one.
48 | *
49 | * @author Paul Speed
50 | */
51 | public class GemsFractalDensityVolume implements DensityVolume {
52 |
53 | private PerlinNoise noise = new PerlinNoise(0);
54 | private PerlinNoise noise2 = new PerlinNoise(1);
55 | private PerlinNoise noise3 = new PerlinNoise(2);
56 |
57 | private Quaternion octaveMat0;
58 | private Quaternion octaveMat1;
59 | private Quaternion octaveMat2;
60 | private Quaternion octaveMat3;
61 | private Quaternion octaveMat4;
62 | private Quaternion octaveMat5;
63 | private Quaternion octaveMat6;
64 | private Quaternion octaveMat7;
65 |
66 |
67 | public GemsFractalDensityVolume() {
68 | octaveMat0 = new Quaternion();
69 | octaveMat1 = new Quaternion().fromAngles(0.1f, 0.01f, -0.1f);
70 | octaveMat2 = new Quaternion().fromAngles(0.2f, 0.02f, -0.2f);
71 | octaveMat3 = new Quaternion().fromAngles(0.3f, 0.03f, -0.3f);
72 | octaveMat4 = new Quaternion().fromAngles(0.4f, 0.04f, -0.4f);
73 | octaveMat5 = new Quaternion().fromAngles(0.5f, 0.05f, -0.5f);
74 | octaveMat6 = new Quaternion().fromAngles(0.6f, 0.06f, -0.6f);
75 | octaveMat7 = new Quaternion().fromAngles(0.7f, 0.07f, -0.7f);
76 | }
77 |
78 | private void warp( Vector3f loc, double frequency, double scale )
79 | {
80 | double x = noise.getNoise(loc.x * frequency, loc.y * frequency, loc.z * frequency);
81 | double y = noise2.getNoise(loc.x * frequency, loc.y * frequency, loc.z * frequency);
82 | double z = noise3.getNoise(loc.x * frequency, loc.y * frequency, loc.z * frequency);
83 |
84 | loc.x = (float)(loc.x + x * scale);
85 | loc.y = (float)(loc.y + y * scale);
86 | loc.z = (float)(loc.z + z * scale);
87 | }
88 |
89 | private double getNoise( Vector3f loc, double scale )
90 | {
91 | //scale *= 0.5f;
92 | //scale *= 4; // 16;
93 | //scale *= 10; //16;
94 | scale *= 16;
95 | return noise.getNoise(loc.x * scale, loc.y * scale, loc.z * scale); // * 2 - 1;
96 | }
97 |
98 | protected float density( Vector3f loc ) {
99 |
100 | double density = -loc.y;
101 |
102 | // Warp the location
103 | warp(loc, 0.004, 8);
104 | //warp(loc, 0.001, 40);
105 |
106 | Vector3f c0 = octaveMat0.mult(loc);
107 | Vector3f c1 = octaveMat1.mult(loc);
108 | Vector3f c2 = octaveMat2.mult(loc);
109 | Vector3f c3 = octaveMat3.mult(loc);
110 | Vector3f c4 = octaveMat4.mult(loc);
111 | Vector3f c5 = octaveMat5.mult(loc);
112 | Vector3f c6 = octaveMat6.mult(loc);
113 | Vector3f c7 = octaveMat7.mult(loc);
114 |
115 | density += getNoise(c0, 0.1600*1.021) * 0.32*1.16;
116 | density += getNoise(c1, 0.0800*0.985) * 0.64*1.12;
117 | density += getNoise(c2, 0.0400*1.051) * 1.28*1.08;
118 | density += getNoise(c3, 0.0200*1.020) * 2.56*1.04;
119 | density += getNoise(c4, 0.0100*0.968) * 5;
120 | density += getNoise(c5, 0.0050*0.994) * 10;
121 | density += getNoise(c6, 0.0025*1.045) * 20*0.9;
122 | density += getNoise(c7, 0.0012*0.972) * 40*0.8;
123 |
124 | return (float)density;
125 | }
126 |
127 | public float getDensity( int x, int y, int z ) {
128 | return density(new Vector3f(x, y, z));
129 | }
130 |
131 | public float getDensity( float x, float y, float z ) {
132 | return density(new Vector3f(x, y, z));
133 | }
134 |
135 | public Vector3f getFieldDirection(float x, float y, float z, Vector3f target) {
136 |
137 | float d = 1f;
138 |
139 | double nx = getDensity(x + d, y, z)
140 | - getDensity(x - d, y, z);
141 | double ny = getDensity(x, y + d, z)
142 | - getDensity(x, y - d, z);
143 | double nz = getDensity(x, y, z + d)
144 | - getDensity(x, y, z - d);
145 |
146 | if( target == null ) {
147 | target = new Vector3f((float)-nx, (float)-ny, (float)-nz).normalizeLocal();
148 | } else {
149 | target.set((float)-nx, (float)-ny, (float)-nz);
150 | target.normalizeLocal();
151 | }
152 |
153 | return target;
154 | }
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/mc/MarchingCubesConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.mc;
38 |
39 |
40 | /**
41 | * Constants used internal to the Marching Cubes mesh generator.
42 | *
43 | * @author Paul Speed
44 | */
45 | public class MarchingCubesConstants {
46 |
47 | public static int[][] edgeStarts = {
48 | {0, 0, 0}, {0, 1, 0}, {1, 0, 0}, {0, 0, 0},
49 | {0, 0, 1}, {0, 1, 1}, {1, 0, 1}, {0, 0, 1},
50 | {0, 0, 0}, {0, 1, 0}, {1, 1, 0}, {1, 0, 0}
51 | };
52 |
53 | public static int[][] edgeDirs = {
54 | {0, 1, 0}, {1, 0, 0}, {0, 1, 0}, {1, 0, 0},
55 | {0, 1, 0}, {1, 0, 0}, {0, 1, 0}, {1, 0, 0},
56 | {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}
57 | };
58 |
59 | public static int[][] edgeEnds = {
60 | {0, 1, 0}, {1, 1, 0 }, {1, 1, 0}, {1, 0, 0},
61 | {0, 1, 1}, {1, 1, 1 }, {1, 1, 1}, {1, 0, 1},
62 | {0, 0, 1}, {0, 1, 1 }, {1, 1, 1}, {1, 0, 1}
63 | };
64 |
65 | // Raw tables
66 | public static int[][][] triEdges = new int[][][] {
67 | {},
68 | {{ 0, 8, 3 }},
69 | {{ 0, 1, 9 }},
70 | {{ 1, 8, 3 }, { 9, 8, 1 }},
71 | {{ 1, 2, 10 }},
72 | {{ 0, 8, 3 }, { 1, 2, 10 }},
73 | {{ 9, 2, 10 }, { 0, 2, 9 }},
74 | {{ 2, 8, 3 }, { 2, 10, 8 }, { 10, 9, 8 }},
75 | {{ 3, 11, 2 }},
76 | {{ 0, 11, 2 }, { 8, 11, 0 }},
77 | {{ 1, 9, 0 }, { 2, 3, 11 }},
78 | {{ 1, 11, 2 }, { 1, 9, 11 }, { 9, 8, 11 }},
79 | {{ 3, 10, 1 }, { 11, 10, 3 }},
80 | {{ 0, 10, 1 }, { 0, 8, 10 }, { 8, 11, 10 }},
81 | {{ 3, 9, 0 }, { 3, 11, 9 }, { 11, 10, 9 }},
82 | {{ 9, 8, 10 }, { 10, 8, 11 }},
83 | {{ 4, 7, 8 }},
84 | {{ 4, 3, 0 }, { 7, 3, 4 }},
85 | {{ 0, 1, 9 }, { 8, 4, 7 }},
86 | {{ 4, 1, 9 }, { 4, 7, 1 }, { 7, 3, 1 }},
87 | {{ 1, 2, 10 }, { 8, 4, 7 }},
88 | {{ 3, 4, 7 }, { 3, 0, 4 }, { 1, 2, 10 }},
89 | {{ 9, 2, 10 }, { 9, 0, 2 }, { 8, 4, 7 }},
90 | {{ 2, 10, 9 }, { 2, 9, 7 }, { 2, 7, 3 }, { 7, 9, 4 }},
91 | {{ 8, 4, 7 }, { 3, 11, 2 }},
92 | {{ 11, 4, 7 }, { 11, 2, 4 }, { 2, 0, 4 }},
93 | {{ 9, 0, 1 }, { 8, 4, 7 }, { 2, 3, 11 }},
94 | {{ 4, 7, 11 }, { 9, 4, 11 }, { 9, 11, 2 }, { 9, 2, 1 }},
95 | {{ 3, 10, 1 }, { 3, 11, 10 }, { 7, 8, 4 }},
96 | {{ 1, 11, 10 }, { 1, 4, 11 }, { 1, 0, 4 }, { 7, 11, 4 }},
97 | {{ 4, 7, 8 }, { 9, 0, 11 }, { 9, 11, 10 }, { 11, 0, 3 }},
98 | {{ 4, 7, 11 }, { 4, 11, 9 }, { 9, 11, 10 }},
99 | {{ 9, 5, 4 }},
100 | {{ 9, 5, 4 }, { 0, 8, 3 }},
101 | {{ 0, 5, 4 }, { 1, 5, 0 }},
102 | {{ 8, 5, 4 }, { 8, 3, 5 }, { 3, 1, 5 }},
103 | {{ 1, 2, 10 }, { 9, 5, 4 }},
104 | {{ 3, 0, 8 }, { 1, 2, 10 }, { 4, 9, 5 }},
105 | {{ 5, 2, 10 }, { 5, 4, 2 }, { 4, 0, 2 }},
106 | {{ 2, 10, 5 }, { 3, 2, 5 }, { 3, 5, 4 }, { 3, 4, 8 }},
107 | {{ 9, 5, 4 }, { 2, 3, 11 }},
108 | {{ 0, 11, 2 }, { 0, 8, 11 }, { 4, 9, 5 }},
109 | {{ 0, 5, 4 }, { 0, 1, 5 }, { 2, 3, 11 }},
110 | {{ 2, 1, 5 }, { 2, 5, 8 }, { 2, 8, 11 }, { 4, 8, 5 }},
111 | {{ 10, 3, 11 }, { 10, 1, 3 }, { 9, 5, 4 }},
112 | {{ 4, 9, 5 }, { 0, 8, 1 }, { 8, 10, 1 }, { 8, 11, 10 }},
113 | {{ 5, 4, 0 }, { 5, 0, 11 }, { 5, 11, 10 }, { 11, 0, 3 }},
114 | {{ 5, 4, 8 }, { 5, 8, 10 }, { 10, 8, 11 }},
115 | {{ 9, 7, 8 }, { 5, 7, 9 }},
116 | {{ 9, 3, 0 }, { 9, 5, 3 }, { 5, 7, 3 }},
117 | {{ 0, 7, 8 }, { 0, 1, 7 }, { 1, 5, 7 }},
118 | {{ 1, 5, 3 }, { 3, 5, 7 }},
119 | {{ 9, 7, 8 }, { 9, 5, 7 }, { 10, 1, 2 }},
120 | {{ 10, 1, 2 }, { 9, 5, 0 }, { 5, 3, 0 }, { 5, 7, 3 }},
121 | {{ 8, 0, 2 }, { 8, 2, 5 }, { 8, 5, 7 }, { 10, 5, 2 }},
122 | {{ 2, 10, 5 }, { 2, 5, 3 }, { 3, 5, 7 }},
123 | {{ 7, 9, 5 }, { 7, 8, 9 }, { 3, 11, 2 }},
124 | {{ 9, 5, 7 }, { 9, 7, 2 }, { 9, 2, 0 }, { 2, 7, 11 }},
125 | {{ 2, 3, 11 }, { 0, 1, 8 }, { 1, 7, 8 }, { 1, 5, 7 }},
126 | {{ 11, 2, 1 }, { 11, 1, 7 }, { 7, 1, 5 }},
127 | {{ 9, 5, 8 }, { 8, 5, 7 }, { 10, 1, 3 }, { 10, 3, 11 }},
128 | {{ 5, 7, 0 }, { 5, 0, 9 }, { 7, 11, 0 }, { 1, 0, 10 }, { 11, 10, 0 }},
129 | {{ 11, 10, 0 }, { 11, 0, 3 }, { 10, 5, 0 }, { 8, 0, 7 }, { 5, 7, 0 }},
130 | {{ 11, 10, 5 }, { 7, 11, 5 }},
131 | {{ 10, 6, 5 }},
132 | {{ 0, 8, 3 }, { 5, 10, 6 }},
133 | {{ 9, 0, 1 }, { 5, 10, 6 }},
134 | {{ 1, 8, 3 }, { 1, 9, 8 }, { 5, 10, 6 }},
135 | {{ 1, 6, 5 }, { 2, 6, 1 }},
136 | {{ 1, 6, 5 }, { 1, 2, 6 }, { 3, 0, 8 }},
137 | {{ 9, 6, 5 }, { 9, 0, 6 }, { 0, 2, 6 }},
138 | {{ 5, 9, 8 }, { 5, 8, 2 }, { 5, 2, 6 }, { 3, 2, 8 }},
139 | {{ 2, 3, 11 }, { 10, 6, 5 }},
140 | {{ 11, 0, 8 }, { 11, 2, 0 }, { 10, 6, 5 }},
141 | {{ 0, 1, 9 }, { 2, 3, 11 }, { 5, 10, 6 }},
142 | {{ 5, 10, 6 }, { 1, 9, 2 }, { 9, 11, 2 }, { 9, 8, 11 }},
143 | {{ 6, 3, 11 }, { 6, 5, 3 }, { 5, 1, 3 }},
144 | {{ 0, 8, 11 }, { 0, 11, 5 }, { 0, 5, 1 }, { 5, 11, 6 }},
145 | {{ 3, 11, 6 }, { 0, 3, 6 }, { 0, 6, 5 }, { 0, 5, 9 }},
146 | {{ 6, 5, 9 }, { 6, 9, 11 }, { 11, 9, 8 }},
147 | {{ 5, 10, 6 }, { 4, 7, 8 }},
148 | {{ 4, 3, 0 }, { 4, 7, 3 }, { 6, 5, 10 }},
149 | {{ 1, 9, 0 }, { 5, 10, 6 }, { 8, 4, 7 }},
150 | {{ 10, 6, 5 }, { 1, 9, 7 }, { 1, 7, 3 }, { 7, 9, 4 }},
151 | {{ 6, 1, 2 }, { 6, 5, 1 }, { 4, 7, 8 }},
152 | {{ 1, 2, 5 }, { 5, 2, 6 }, { 3, 0, 4 }, { 3, 4, 7 }},
153 | {{ 8, 4, 7 }, { 9, 0, 5 }, { 0, 6, 5 }, { 0, 2, 6 }},
154 | {{ 7, 3, 9 }, { 7, 9, 4 }, { 3, 2, 9 }, { 5, 9, 6 }, { 2, 6, 9 }},
155 | {{ 3, 11, 2 }, { 7, 8, 4 }, { 10, 6, 5 }},
156 | {{ 5, 10, 6 }, { 4, 7, 2 }, { 4, 2, 0 }, { 2, 7, 11 }},
157 | {{ 0, 1, 9 }, { 4, 7, 8 }, { 2, 3, 11 }, { 5, 10, 6 }},
158 | {{ 9, 2, 1 }, { 9, 11, 2 }, { 9, 4, 11 }, { 7, 11, 4 }, { 5, 10, 6 }},
159 | {{ 8, 4, 7 }, { 3, 11, 5 }, { 3, 5, 1 }, { 5, 11, 6 }},
160 | {{ 5, 1, 11 }, { 5, 11, 6 }, { 1, 0, 11 }, { 7, 11, 4 }, { 0, 4, 11 }},
161 | {{ 0, 5, 9 }, { 0, 6, 5 }, { 0, 3, 6 }, { 11, 6, 3 }, { 8, 4, 7 }},
162 | {{ 6, 5, 9 }, { 6, 9, 11 }, { 4, 7, 9 }, { 7, 11, 9 }},
163 | {{ 10, 4, 9 }, { 6, 4, 10 }},
164 | {{ 4, 10, 6 }, { 4, 9, 10 }, { 0, 8, 3 }},
165 | {{ 10, 0, 1 }, { 10, 6, 0 }, { 6, 4, 0 }},
166 | {{ 8, 3, 1 }, { 8, 1, 6 }, { 8, 6, 4 }, { 6, 1, 10 }},
167 | {{ 1, 4, 9 }, { 1, 2, 4 }, { 2, 6, 4 }},
168 | {{ 3, 0, 8 }, { 1, 2, 9 }, { 2, 4, 9 }, { 2, 6, 4 }},
169 | {{ 0, 2, 4 }, { 4, 2, 6 }},
170 | {{ 8, 3, 2 }, { 8, 2, 4 }, { 4, 2, 6 }},
171 | {{ 10, 4, 9 }, { 10, 6, 4 }, { 11, 2, 3 }},
172 | {{ 0, 8, 2 }, { 2, 8, 11 }, { 4, 9, 10 }, { 4, 10, 6 }},
173 | {{ 3, 11, 2 }, { 0, 1, 6 }, { 0, 6, 4 }, { 6, 1, 10 }},
174 | {{ 6, 4, 1 }, { 6, 1, 10 }, { 4, 8, 1 }, { 2, 1, 11 }, { 8, 11, 1 }},
175 | {{ 9, 6, 4 }, { 9, 3, 6 }, { 9, 1, 3 }, { 11, 6, 3 }},
176 | {{ 8, 11, 1 }, { 8, 1, 0 }, { 11, 6, 1 }, { 9, 1, 4 }, { 6, 4, 1 }},
177 | {{ 3, 11, 6 }, { 3, 6, 0 }, { 0, 6, 4 }},
178 | {{ 6, 4, 8 }, { 11, 6, 8 }},
179 | {{ 7, 10, 6 }, { 7, 8, 10 }, { 8, 9, 10 }},
180 | {{ 0, 7, 3 }, { 0, 10, 7 }, { 0, 9, 10 }, { 6, 7, 10 }},
181 | {{ 10, 6, 7 }, { 1, 10, 7 }, { 1, 7, 8 }, { 1, 8, 0 }},
182 | {{ 10, 6, 7 }, { 10, 7, 1 }, { 1, 7, 3 }},
183 | {{ 1, 2, 6 }, { 1, 6, 8 }, { 1, 8, 9 }, { 8, 6, 7 }},
184 | {{ 2, 6, 9 }, { 2, 9, 1 }, { 6, 7, 9 }, { 0, 9, 3 }, { 7, 3, 9 }},
185 | {{ 7, 8, 0 }, { 7, 0, 6 }, { 6, 0, 2 }},
186 | {{ 7, 3, 2 }, { 6, 7, 2 }},
187 | {{ 2, 3, 11 }, { 10, 6, 8 }, { 10, 8, 9 }, { 8, 6, 7 }},
188 | {{ 2, 0, 7 }, { 2, 7, 11 }, { 0, 9, 7 }, { 6, 7, 10 }, { 9, 10, 7 }},
189 | {{ 1, 8, 0 }, { 1, 7, 8 }, { 1, 10, 7 }, { 6, 7, 10 }, { 2, 3, 11 }},
190 | {{ 11, 2, 1 }, { 11, 1, 7 }, { 10, 6, 1 }, { 6, 7, 1 }},
191 | {{ 8, 9, 6 }, { 8, 6, 7 }, { 9, 1, 6 }, { 11, 6, 3 }, { 1, 3, 6 }},
192 | {{ 0, 9, 1 }, { 11, 6, 7 }},
193 | {{ 7, 8, 0 }, { 7, 0, 6 }, { 3, 11, 0 }, { 11, 6, 0 }},
194 | {{ 7, 11, 6 }},
195 | {{ 7, 6, 11 }},
196 | {{ 3, 0, 8 }, { 11, 7, 6 }},
197 | {{ 0, 1, 9 }, { 11, 7, 6 }},
198 | {{ 8, 1, 9 }, { 8, 3, 1 }, { 11, 7, 6 }},
199 | {{ 10, 1, 2 }, { 6, 11, 7 }},
200 | {{ 1, 2, 10 }, { 3, 0, 8 }, { 6, 11, 7 }},
201 | {{ 2, 9, 0 }, { 2, 10, 9 }, { 6, 11, 7 }},
202 | {{ 6, 11, 7 }, { 2, 10, 3 }, { 10, 8, 3 }, { 10, 9, 8 }},
203 | {{ 7, 2, 3 }, { 6, 2, 7 }},
204 | {{ 7, 0, 8 }, { 7, 6, 0 }, { 6, 2, 0 }},
205 | {{ 2, 7, 6 }, { 2, 3, 7 }, { 0, 1, 9 }},
206 | {{ 1, 6, 2 }, { 1, 8, 6 }, { 1, 9, 8 }, { 8, 7, 6 }},
207 | {{ 10, 7, 6 }, { 10, 1, 7 }, { 1, 3, 7 }},
208 | {{ 10, 7, 6 }, { 1, 7, 10 }, { 1, 8, 7 }, { 1, 0, 8 }},
209 | {{ 0, 3, 7 }, { 0, 7, 10 }, { 0, 10, 9 }, { 6, 10, 7 }},
210 | {{ 7, 6, 10 }, { 7, 10, 8 }, { 8, 10, 9 }},
211 | {{ 6, 8, 4 }, { 11, 8, 6 }},
212 | {{ 3, 6, 11 }, { 3, 0, 6 }, { 0, 4, 6 }},
213 | {{ 8, 6, 11 }, { 8, 4, 6 }, { 9, 0, 1 }},
214 | {{ 9, 4, 6 }, { 9, 6, 3 }, { 9, 3, 1 }, { 11, 3, 6 }},
215 | {{ 6, 8, 4 }, { 6, 11, 8 }, { 2, 10, 1 }},
216 | {{ 1, 2, 10 }, { 3, 0, 11 }, { 0, 6, 11 }, { 0, 4, 6 }},
217 | {{ 4, 11, 8 }, { 4, 6, 11 }, { 0, 2, 9 }, { 2, 10, 9 }},
218 | {{ 10, 9, 3 }, { 10, 3, 2 }, { 9, 4, 3 }, { 11, 3, 6 }, { 4, 6, 3 }},
219 | {{ 8, 2, 3 }, { 8, 4, 2 }, { 4, 6, 2 }},
220 | {{ 0, 4, 2 }, { 4, 6, 2 }},
221 | {{ 1, 9, 0 }, { 2, 3, 4 }, { 2, 4, 6 }, { 4, 3, 8 }},
222 | {{ 1, 9, 4 }, { 1, 4, 2 }, { 2, 4, 6 }},
223 | {{ 8, 1, 3 }, { 8, 6, 1 }, { 8, 4, 6 }, { 6, 10, 1 }},
224 | {{ 10, 1, 0 }, { 10, 0, 6 }, { 6, 0, 4 }},
225 | {{ 4, 6, 3 }, { 4, 3, 8 }, { 6, 10, 3 }, { 0, 3, 9 }, { 10, 9, 3 }},
226 | {{ 10, 9, 4 }, { 6, 10, 4 }},
227 | {{ 4, 9, 5 }, { 7, 6, 11 }},
228 | {{ 0, 8, 3 }, { 4, 9, 5 }, { 11, 7, 6 }},
229 | {{ 5, 0, 1 }, { 5, 4, 0 }, { 7, 6, 11 }},
230 | {{ 11, 7, 6 }, { 8, 3, 4 }, { 3, 5, 4 }, { 3, 1, 5 }},
231 | {{ 9, 5, 4 }, { 10, 1, 2 }, { 7, 6, 11 }},
232 | {{ 6, 11, 7 }, { 1, 2, 10 }, { 0, 8, 3 }, { 4, 9, 5 }},
233 | {{ 7, 6, 11 }, { 5, 4, 10 }, { 4, 2, 10 }, { 4, 0, 2 }},
234 | {{ 3, 4, 8 }, { 3, 5, 4 }, { 3, 2, 5 }, { 10, 5, 2 }, { 11, 7, 6 }},
235 | {{ 7, 2, 3 }, { 7, 6, 2 }, { 5, 4, 9 }},
236 | {{ 9, 5, 4 }, { 0, 8, 6 }, { 0, 6, 2 }, { 6, 8, 7 }},
237 | {{ 3, 6, 2 }, { 3, 7, 6 }, { 1, 5, 0 }, { 5, 4, 0 }},
238 | {{ 6, 2, 8 }, { 6, 8, 7 }, { 2, 1, 8 }, { 4, 8, 5 }, { 1, 5, 8 }},
239 | {{ 9, 5, 4 }, { 10, 1, 6 }, { 1, 7, 6 }, { 1, 3, 7 }},
240 | {{ 1, 6, 10 }, { 1, 7, 6 }, { 1, 0, 7 }, { 8, 7, 0 }, { 9, 5, 4 }},
241 | {{ 4, 0, 10 }, { 4, 10, 5 }, { 0, 3, 10 }, { 6, 10, 7 }, { 3, 7, 10 }},
242 | {{ 7, 6, 10 }, { 7, 10, 8 }, { 5, 4, 10 }, { 4, 8, 10 }},
243 | {{ 6, 9, 5 }, { 6, 11, 9 }, { 11, 8, 9 }},
244 | {{ 3, 6, 11 }, { 0, 6, 3 }, { 0, 5, 6 }, { 0, 9, 5 }},
245 | {{ 0, 11, 8 }, { 0, 5, 11 }, { 0, 1, 5 }, { 5, 6, 11 }},
246 | {{ 6, 11, 3 }, { 6, 3, 5 }, { 5, 3, 1 }},
247 | {{ 1, 2, 10 }, { 9, 5, 11 }, { 9, 11, 8 }, { 11, 5, 6 }},
248 | {{ 0, 11, 3 }, { 0, 6, 11 }, { 0, 9, 6 }, { 5, 6, 9 }, { 1, 2, 10 }},
249 | {{ 11, 8, 5 }, { 11, 5, 6 }, { 8, 0, 5 }, { 10, 5, 2 }, { 0, 2, 5 }},
250 | {{ 6, 11, 3 }, { 6, 3, 5 }, { 2, 10, 3 }, { 10, 5, 3 }},
251 | {{ 5, 8, 9 }, { 5, 2, 8 }, { 5, 6, 2 }, { 3, 8, 2 }},
252 | {{ 9, 5, 6 }, { 9, 6, 0 }, { 0, 6, 2 }},
253 | {{ 1, 5, 8 }, { 1, 8, 0 }, { 5, 6, 8 }, { 3, 8, 2 }, { 6, 2, 8 }},
254 | {{ 1, 5, 6 }, { 2, 1, 6 }},
255 | {{ 1, 3, 6 }, { 1, 6, 10 }, { 3, 8, 6 }, { 5, 6, 9 }, { 8, 9, 6 }},
256 | {{ 10, 1, 0 }, { 10, 0, 6 }, { 9, 5, 0 }, { 5, 6, 0 }},
257 | {{ 0, 3, 8 }, { 5, 6, 10 }},
258 | {{ 10, 5, 6 }},
259 | {{ 11, 5, 10 }, { 7, 5, 11 }},
260 | {{ 11, 5, 10 }, { 11, 7, 5 }, { 8, 3, 0 }},
261 | {{ 5, 11, 7 }, { 5, 10, 11 }, { 1, 9, 0 }},
262 | {{ 10, 7, 5 }, { 10, 11, 7 }, { 9, 8, 1 }, { 8, 3, 1 }},
263 | {{ 11, 1, 2 }, { 11, 7, 1 }, { 7, 5, 1 }},
264 | {{ 0, 8, 3 }, { 1, 2, 7 }, { 1, 7, 5 }, { 7, 2, 11 }},
265 | {{ 9, 7, 5 }, { 9, 2, 7 }, { 9, 0, 2 }, { 2, 11, 7 }},
266 | {{ 7, 5, 2 }, { 7, 2, 11 }, { 5, 9, 2 }, { 3, 2, 8 }, { 9, 8, 2 }},
267 | {{ 2, 5, 10 }, { 2, 3, 5 }, { 3, 7, 5 }},
268 | {{ 8, 2, 0 }, { 8, 5, 2 }, { 8, 7, 5 }, { 10, 2, 5 }},
269 | {{ 9, 0, 1 }, { 5, 10, 3 }, { 5, 3, 7 }, { 3, 10, 2 }},
270 | {{ 9, 8, 2 }, { 9, 2, 1 }, { 8, 7, 2 }, { 10, 2, 5 }, { 7, 5, 2 }},
271 | {{ 1, 3, 5 }, { 3, 7, 5 }},
272 | {{ 0, 8, 7 }, { 0, 7, 1 }, { 1, 7, 5 }},
273 | {{ 9, 0, 3 }, { 9, 3, 5 }, { 5, 3, 7 }},
274 | {{ 9, 8, 7 }, { 5, 9, 7 }},
275 | {{ 5, 8, 4 }, { 5, 10, 8 }, { 10, 11, 8 }},
276 | {{ 5, 0, 4 }, { 5, 11, 0 }, { 5, 10, 11 }, { 11, 3, 0 }},
277 | {{ 0, 1, 9 }, { 8, 4, 10 }, { 8, 10, 11 }, { 10, 4, 5 }},
278 | {{ 10, 11, 4 }, { 10, 4, 5 }, { 11, 3, 4 }, { 9, 4, 1 }, { 3, 1, 4 }},
279 | {{ 2, 5, 1 }, { 2, 8, 5 }, { 2, 11, 8 }, { 4, 5, 8 }},
280 | {{ 0, 4, 11 }, { 0, 11, 3 }, { 4, 5, 11 }, { 2, 11, 1 }, { 5, 1, 11 }},
281 | {{ 0, 2, 5 }, { 0, 5, 9 }, { 2, 11, 5 }, { 4, 5, 8 }, { 11, 8, 5 }},
282 | {{ 9, 4, 5 }, { 2, 11, 3 }},
283 | {{ 2, 5, 10 }, { 3, 5, 2 }, { 3, 4, 5 }, { 3, 8, 4 }},
284 | {{ 5, 10, 2 }, { 5, 2, 4 }, { 4, 2, 0 }},
285 | {{ 3, 10, 2 }, { 3, 5, 10 }, { 3, 8, 5 }, { 4, 5, 8 }, { 0, 1, 9 }},
286 | {{ 5, 10, 2 }, { 5, 2, 4 }, { 1, 9, 2 }, { 9, 4, 2 }},
287 | {{ 8, 4, 5 }, { 8, 5, 3 }, { 3, 5, 1 }},
288 | {{ 0, 4, 5 }, { 1, 0, 5 }},
289 | {{ 8, 4, 5 }, { 8, 5, 3 }, { 9, 0, 5 }, { 0, 3, 5 }},
290 | {{ 9, 4, 5 }},
291 | {{ 4, 11, 7 }, { 4, 9, 11 }, { 9, 10, 11 }},
292 | {{ 0, 8, 3 }, { 4, 9, 7 }, { 9, 11, 7 }, { 9, 10, 11 }},
293 | {{ 1, 10, 11 }, { 1, 11, 4 }, { 1, 4, 0 }, { 7, 4, 11 }},
294 | {{ 3, 1, 4 }, { 3, 4, 8 }, { 1, 10, 4 }, { 7, 4, 11 }, { 10, 11, 4 }},
295 | {{ 4, 11, 7 }, { 9, 11, 4 }, { 9, 2, 11 }, { 9, 1, 2 }},
296 | {{ 9, 7, 4 }, { 9, 11, 7 }, { 9, 1, 11 }, { 2, 11, 1 }, { 0, 8, 3 }},
297 | {{ 11, 7, 4 }, { 11, 4, 2 }, { 2, 4, 0 }},
298 | {{ 11, 7, 4 }, { 11, 4, 2 }, { 8, 3, 4 }, { 3, 2, 4 }},
299 | {{ 2, 9, 10 }, { 2, 7, 9 }, { 2, 3, 7 }, { 7, 4, 9 }},
300 | {{ 9, 10, 7 }, { 9, 7, 4 }, { 10, 2, 7 }, { 8, 7, 0 }, { 2, 0, 7 }},
301 | {{ 3, 7, 10 }, { 3, 10, 2 }, { 7, 4, 10 }, { 1, 10, 0 }, { 4, 0, 10 }},
302 | {{ 1, 10, 2 }, { 8, 7, 4 }},
303 | {{ 4, 9, 1 }, { 4, 1, 7 }, { 7, 1, 3 }},
304 | {{ 4, 9, 1 }, { 4, 1, 7 }, { 0, 8, 1 }, { 8, 7, 1 }},
305 | {{ 4, 0, 3 }, { 7, 4, 3 }},
306 | {{ 4, 8, 7 }},
307 | {{ 9, 10, 8 }, { 10, 11, 8 }},
308 | {{ 3, 0, 9 }, { 3, 9, 11 }, { 11, 9, 10 }},
309 | {{ 0, 1, 10 }, { 0, 10, 8 }, { 8, 10, 11 }},
310 | {{ 3, 1, 10 }, { 11, 3, 10 }},
311 | {{ 1, 2, 11 }, { 1, 11, 9 }, { 9, 11, 8 }},
312 | {{ 3, 0, 9 }, { 3, 9, 11 }, { 1, 2, 9 }, { 2, 11, 9 }},
313 | {{ 0, 2, 11 }, { 8, 0, 11 }},
314 | {{ 3, 2, 11 }},
315 | {{ 2, 3, 8 }, { 2, 8, 10 }, { 10, 8, 9 }},
316 | {{ 9, 10, 2 }, { 0, 9, 2 }},
317 | {{ 2, 3, 8 }, { 2, 8, 10 }, { 0, 1, 8 }, { 1, 10, 8 }},
318 | {{ 1, 10, 2 }},
319 | {{ 1, 3, 8 }, { 9, 1, 8 }},
320 | {{ 0, 9, 1 }},
321 | {{ 0, 3, 8 }},
322 | {}
323 | };
324 | }
325 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/mc/MarchingCubesMeshGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.mc;
38 |
39 | import com.jme3.math.Vector3f;
40 | import com.jme3.scene.Mesh;
41 | import com.jme3.scene.VertexBuffer.Type;
42 | import com.jme3.util.BufferUtils;
43 | import com.simsilica.iso.DensityVolume;
44 | import com.simsilica.iso.MeshGenerator;
45 | import java.nio.FloatBuffer;
46 | import java.nio.IntBuffer;
47 | import java.util.ArrayList;
48 | import java.util.Arrays;
49 | import java.util.List;
50 |
51 |
52 | /**
53 | * Takes a density field and generates meshes for it
54 | * using the Marching Cubes algorithm.
55 | *
56 | * @author Paul Speed
57 | */
58 | public class MarchingCubesMeshGenerator implements MeshGenerator {
59 |
60 | private int cx;
61 | private int cy;
62 | private int cz;
63 | private int[] masks;
64 | private int[] cells;
65 | private int cellIndex = 0;
66 | private int triangleCount = 0;
67 | private int vertCount = 0;
68 | private int maskIndex = 0;
69 | private boolean[] edgeHit = new boolean[12];
70 | private int[][][][] edgeVerts;
71 | private float xzScale = 1;
72 |
73 | /**
74 | * Creates a Marching Cubes based mesh generator that will
75 | * generate chunks of the specified size.
76 | */
77 | public MarchingCubesMeshGenerator( int cx, int cy, int cz ) {
78 | this(cx, cy, cz, 1);
79 | }
80 |
81 | /**
82 | * Creates a Marching Cubes based mesh generator that will
83 | * generate chunks of the specified size with an extra x, z
84 | * scale applied to the resulting mesh. In other words,
85 | * even though the source data may be sampled in 64x64 cell
86 | * chunks, with an xzScale of 2 the generated geometry will be
87 | * 128 x 128.
88 | */
89 | public MarchingCubesMeshGenerator( int cx, int cy, int cz, float xzScale ) {
90 | cx++;
91 | cy++;
92 | cz++;
93 | this.cx = cx;
94 | this.cy = cy;
95 | this.cz = cz;
96 | this.masks = new int[cx * cy * cz];
97 | this.cells = new int[cx * cy * cz];
98 | this.edgeVerts = new int[cx+1][cy+1][cz+1][3];
99 | this.xzScale = xzScale;
100 | }
101 |
102 | public Vector3f getRequiredVolumeSize() {
103 | // When the creator passed in a size of "cells", we actually
104 | // sample corners and so neded +1
105 | // However, we also sample an extra border on all sides which
106 | // is another +2... +3 in all. But the +1 is already incorporated
107 | // into our size fields.
108 | return new Vector3f(cx + 2, cy + 2, cz + 2);
109 | }
110 |
111 | public Vector3f getGenerationSize() {
112 | int x = cx - 1;
113 | int y = cy - 1;
114 | int z = cz - 1;
115 | return new Vector3f(x * xzScale, y, z * xzScale);
116 | }
117 |
118 | public void setXzScale( float s ) {
119 | this.xzScale = s;
120 | }
121 |
122 | public float getXzScale() {
123 | return xzScale;
124 | }
125 |
126 | private int solid( float value ) {
127 | return value > 0 ? 1 : 0;
128 | }
129 |
130 | private Vector3f getEdgePoint( int x, int y, int z, int edge, DensityVolume volume ) {
131 |
132 | int x1 = x + MarchingCubesConstants.edgeStarts[edge][0] + 1;
133 | int y1 = y + MarchingCubesConstants.edgeStarts[edge][1] + 1;
134 | int z1 = z + MarchingCubesConstants.edgeStarts[edge][2] + 1;
135 | float d1 = volume.getDensity(x1, y1, z1);
136 |
137 | int x2 = x + MarchingCubesConstants.edgeEnds[edge][0] + 1;
138 | int y2 = y + MarchingCubesConstants.edgeEnds[edge][1] + 1;
139 | int z2 = z + MarchingCubesConstants.edgeEnds[edge][2] + 1;
140 | float d2 = volume.getDensity(x2, y2, z2);
141 |
142 | // If d1 is -0.2 and d2 is 0.6 then the
143 | // point should be 0.25 from edge start.
144 | float part = Math.abs(d1) / Math.abs(d2 - d1);
145 | float vx = x1 + (x2-x1) * part;
146 | float vy = y1 + (y2-y1) * part;
147 | float vz = z1 + (z2-z1) * part;
148 | Vector3f vert = new Vector3f(vx, vy, vz);
149 | return vert;
150 | }
151 |
152 | /**
153 | * Builds a mesh from the specified volume. The resulting mesh
154 | * will be extracted from 0 to size in all directions but requires
155 | * the volume to support queries -1 to size + 2 because it will
156 | * will internally build a border of cells.
157 | */
158 | public Mesh buildMesh( DensityVolume volume ) {
159 |
160 | List verts = new ArrayList();
161 | List normals = new ArrayList();
162 | cellIndex = 0;
163 | triangleCount = 0;
164 | vertCount = 0;
165 | maskIndex = 0;
166 |
167 | // Build up the edge indexes so we can share edges
168 | for( int x = 0; x < cx; x++ ) {
169 | for( int y = 0; y < cy; y++ ) {
170 | for( int z = 0; z < cz; z++ ) {
171 | int bits = 0;
172 | int sx = x + 1;
173 | int sy = y + 1;
174 | int sz = z + 1;
175 |
176 | bits |= solid(volume.getDensity(sx , sy , sz ));
177 | bits |= solid(volume.getDensity(sx , sy+1, sz )) << 1;
178 | bits |= solid(volume.getDensity(sx+1, sy+1, sz )) << 2;
179 | bits |= solid(volume.getDensity(sx+1, sy , sz )) << 3;
180 | bits |= solid(volume.getDensity(sx , sy , sz+1)) << 4;
181 | bits |= solid(volume.getDensity(sx , sy+1, sz+1)) << 5;
182 | bits |= solid(volume.getDensity(sx+1, sy+1, sz+1)) << 6;
183 | bits |= solid(volume.getDensity(sx+1, sy , sz+1)) << 7;
184 |
185 | if( MarchingCubesConstants.triEdges[bits].length > 0 ) {
186 | // We _do_ want to process some of the edges but
187 | // we _don't_ want to process the actual cell if
188 | // it is the outside border
189 | if( x < cx - 1 && y < cy - 1 && z < cz - 1 ) {
190 | cells[cellIndex++] = maskIndex;
191 | }
192 | int[][] triangles = MarchingCubesConstants.triEdges[bits];
193 | triangleCount += triangles.length;
194 | Arrays.fill(edgeHit, false);
195 |
196 | for( int t = 0; t < triangles.length; t++ ) {
197 | int[] triEdges = triangles[t];
198 |
199 | for( int i = 0; i < 3; i++ ) {
200 | edgeHit[triEdges[i]] = true;
201 | }
202 | }
203 |
204 | // The density field is theoretically cx * cy * cz which
205 | // means that we only need to generate cells for cx - 1, cy -1, cz -1
206 | // We generate extra cells to make sure we have the edges we need...
207 | // but these cells are technically outside of the field and
208 | // we will need to skip them later. Also, I guess we can avoid
209 | // generating some extra vertexes that would stick out.
210 | if( edgeHit[0] && y < cy - 1 ) {
211 | Vector3f vert = getEdgePoint(x, y, z, 0, volume);
212 | edgeVerts[x][y][z][0] = verts.size();
213 | verts.add(vert);
214 | normals.add(volume.getFieldDirection(vert.x, vert.y, vert.z, null));
215 | vert.x--;
216 | vert.y--;
217 | vert.z--;
218 | }
219 | if( edgeHit[3] && x < cx - 1 ) {
220 | Vector3f vert = getEdgePoint(x, y, z, 3, volume);
221 | edgeVerts[x][y][z][1] = verts.size();
222 | verts.add(vert);
223 | normals.add(volume.getFieldDirection(vert.x, vert.y, vert.z, null));
224 | vert.x--;
225 | vert.y--;
226 | vert.z--;
227 | }
228 | if( edgeHit[8] && z < cz - 1 ) {
229 | Vector3f vert = getEdgePoint(x, y, z, 8, volume);
230 | edgeVerts[x][y][z][2] = verts.size();
231 | verts.add(vert);
232 | normals.add(volume.getFieldDirection(vert.x, vert.y, vert.z, null));
233 | vert.x--;
234 | vert.y--;
235 | vert.z--;
236 | }
237 | }
238 | masks[maskIndex++] = bits;
239 | }
240 | }
241 | }
242 |
243 | int cellCount = cellIndex;
244 | if( cellCount == 0 )
245 | return null;
246 |
247 | if( xzScale != 1 ) {
248 | for( int i = 0; i < verts.size(); i++ ) {
249 | Vector3f v = verts.get(i);
250 | Vector3f n = normals.get(i);
251 | v.x *= xzScale;
252 | v.z *= xzScale;
253 | n.y *= xzScale;
254 | n.normalizeLocal();
255 | }
256 | }
257 |
258 | int[] triIndexes = new int[triangleCount * 3];
259 | int triIndexIndex = 0;
260 |
261 | // Now let's just visit the non-empty cells and spin out the
262 | // shared triangles' indexes.
263 | int cycz = cy * cz;
264 | for( int c = 0; c < cellCount; c++ ) {
265 |
266 | int index = cells[c];
267 | int mask = masks[index];
268 | int x = index / (cycz);
269 | int y = (index % (cycz)) / cz;
270 | int z = index % cz;
271 |
272 | int[][] triangles = MarchingCubesConstants.triEdges[mask];
273 | if( triangles.length == 0 ) {
274 | throw new RuntimeException("Algorithm inconsistency detected.");
275 | //System.out.println( "****** How did this happen? ******" );
276 | //continue;
277 | }
278 |
279 | for( int t = 0; t < triangles.length; t++ ) {
280 |
281 | int[] triEdges = triangles[t];
282 |
283 | for( int i = 0; i < 3; i++ ) {
284 | int vertIndex;
285 | switch(triEdges[i]) {
286 | case 0:
287 | vertIndex = edgeVerts[x][y][z][0];
288 | break;
289 | case 1:
290 | vertIndex = edgeVerts[x][y+1][z][1];
291 | break;
292 | case 2:
293 | vertIndex = edgeVerts[x+1][y][z][0];
294 | break;
295 | case 3:
296 | vertIndex = edgeVerts[x][y][z][1];
297 | break;
298 | case 4:
299 | vertIndex = edgeVerts[x][y][z+1][0];
300 | break;
301 | case 5:
302 | vertIndex = edgeVerts[x][y+1][z+1][1];
303 | break;
304 | case 6:
305 | vertIndex = edgeVerts[x+1][y][z+1][0];
306 | break;
307 | case 7:
308 | vertIndex = edgeVerts[x][y][z+1][1];
309 | break;
310 | case 8:
311 | vertIndex = edgeVerts[x][y][z][2];
312 | break;
313 | case 9:
314 | vertIndex = edgeVerts[x][y+1][z][2];
315 | break;
316 | case 10:
317 | vertIndex = edgeVerts[x+1][y+1][z][2];
318 | break;
319 | case 11:
320 | vertIndex = edgeVerts[x+1][y][z][2];
321 | break;
322 | default:
323 | throw new RuntimeException("Unknown edge:" + triEdges[i]);
324 | }
325 |
326 | triIndexes[triIndexIndex++] = vertIndex;
327 | }
328 | }
329 | }
330 |
331 | Vector3f[] vertArray = new Vector3f[verts.size()];
332 | vertArray = verts.toArray(vertArray);
333 |
334 | Vector3f[] normArray = new Vector3f[normals.size()];
335 | normArray = normals.toArray(normArray);
336 |
337 | Mesh mesh = new Mesh();
338 | FloatBuffer pb = BufferUtils.createFloatBuffer(vertArray);
339 | mesh.setBuffer(Type.Position, 3, pb);
340 | FloatBuffer nb = BufferUtils.createFloatBuffer(normArray);
341 | mesh.setBuffer(Type.Normal, 3, nb);
342 | IntBuffer ib = BufferUtils.createIntBuffer(triIndexes);
343 | mesh.setBuffer(Type.Index, 3, ib);
344 |
345 | mesh.updateBound();
346 |
347 | return mesh;
348 | }
349 | }
350 |
351 |
352 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/plot/BatchInstance.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.plot;
38 |
39 | import com.jme3.math.Quaternion;
40 | import com.jme3.math.Vector3f;
41 |
42 |
43 | /**
44 | * Holds the information about a single object's
45 | * transform. The batcher will use these to create the
46 | * batch from the template mesh.
47 | *
48 | * @author Paul Speed
49 | */
50 | public class BatchInstance {
51 | public Vector3f position;
52 | public Quaternion rotation;
53 | public float scale;
54 |
55 | public BatchInstance() {
56 | }
57 |
58 | public BatchInstance( Vector3f pos, Quaternion rot, float scale ) {
59 | this.position = pos;
60 | this.rotation = rot;
61 | this.scale = scale;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/plot/InstanceTemplate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.plot;
38 |
39 | import com.jme3.bounding.BoundingBox;
40 | import com.jme3.math.Matrix4f;
41 | import com.jme3.math.Quaternion;
42 | import com.jme3.math.Vector3f;
43 | import com.jme3.scene.Geometry;
44 | import com.jme3.scene.Mesh;
45 | import com.jme3.scene.VertexBuffer;
46 | import com.jme3.scene.VertexBuffer.Format;
47 | import com.jme3.scene.VertexBuffer.Type;
48 | import com.jme3.scene.VertexBuffer.Usage;
49 | import com.simsilica.iso.util.MatrixUtils;
50 | import java.nio.FloatBuffer;
51 | import java.util.List;
52 |
53 |
54 | /**
55 | * Wraps a Geometry to provide a template for
56 | * instance-batching. This could have been combined with
57 | * BatchTemplate but I'm trying to isolated the JME 3.x specific
58 | * dependencies from the JME 3.0 dependencies.
59 | *
60 | * @author Paul Speed
61 | */
62 | public class InstanceTemplate {
63 | private Geometry sourceGeom;
64 | private Mesh source;
65 | private VertexBuffer[] templates;
66 | private boolean intIndex;
67 |
68 | public InstanceTemplate( Geometry sourceGeom, boolean intIndex ) {
69 | this.sourceGeom = sourceGeom;
70 | this.intIndex = intIndex;
71 | this.source = sourceGeom.getMesh();
72 | }
73 |
74 | public Geometry createInstances( List instances ) {
75 | if( instances.isEmpty() ) {
76 | return null;
77 | }
78 |
79 | Vector3f offset = sourceGeom.getWorldTranslation();
80 |
81 | // For instances, we just clone the original mesh and add
82 | // in the transform instance data
83 | Mesh mesh = source.clone();
84 |
85 | Vector3f min = new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
86 | Vector3f max = new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
87 | Matrix4f[] transforms = new Matrix4f[instances.size()];
88 | for( int i = 0; i < instances.size(); i++ ) {
89 | BatchInstance instance = instances.get(i);
90 |
91 | Vector3f p1 = instance.position;
92 | Quaternion rot = instance.rotation;
93 | float scale = instance.scale;
94 |
95 | // The offset needs to be projected
96 | Vector3f localOffset = rot.mult(offset);
97 | localOffset.multLocal(scale);
98 |
99 | p1 = p1.add(localOffset);
100 |
101 | min.minLocal(p1);
102 | max.maxLocal(p1);
103 |
104 |
105 | Matrix4f transform = new Matrix4f();
106 | transform.setRotationQuaternion(rot);
107 | transform.setTranslation(p1);
108 | transform.setScale(scale, scale, scale);
109 |
110 | transforms[i] = transform;
111 | }
112 |
113 | // Note: this doesn't calculate it correctly right now
114 | // so we'll do it manually and fudge it a little.
115 | //mesh.updateBound();
116 | min.subtractLocal(3, 1, 3);
117 | max.addLocal(3, 8, 3);
118 | BoundingBox bounds = new BoundingBox(min, max);
119 |
120 | // Create the transform buffer
121 | FloatBuffer xb = MatrixUtils.createMatrixBuffer(transforms);
122 |
123 | VertexBuffer vb = new VertexBuffer(Type.InstanceData);
124 | vb.setInstanceSpan(1);
125 | vb.setupData(Usage.Stream, 16, Format.Float, xb);
126 |
127 | return createInstances(vb, bounds);
128 | }
129 |
130 | public Geometry createInstances( VertexBuffer transforms, BoundingBox bounds ) {
131 |
132 | // For instances, we just clone the original mesh and add
133 | // in the transform instance data
134 | Mesh mesh = source.clone();
135 | mesh.setBuffer(transforms);
136 | mesh.setBound(bounds);
137 |
138 | Geometry result = new Geometry("batch:" + sourceGeom.getName(), mesh);
139 | result.setMaterial(sourceGeom.getMaterial());
140 | result.setQueueBucket(sourceGeom.getQueueBucket());
141 | return result;
142 | }
143 |
144 |
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/tri/Triangle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.tri;
38 |
39 | import com.jme3.math.Vector2f;
40 | import com.jme3.math.Vector3f;
41 |
42 |
43 | /**
44 | *
45 | *
46 | * @author Paul Speed
47 | */
48 | public class Triangle implements Cloneable {
49 |
50 | public Vector3f[] verts = { new Vector3f(), new Vector3f(), new Vector3f() };
51 | public Vector3f[] norms = { new Vector3f(), new Vector3f(), new Vector3f() };
52 | public Vector2f[] texes = { new Vector2f(), new Vector2f(), new Vector2f() };
53 | public int[] indexes = new int[3];
54 |
55 | public Triangle() {
56 | }
57 |
58 | @Override
59 | public Triangle clone() {
60 | Triangle result = new Triangle();
61 | for( int v = 0; v < 3; v++ ) {
62 | result.verts[v].set(verts[v]);
63 | result.norms[v].set(norms[v]);
64 | result.texes[v].set(texes[v]);
65 | result.indexes[v] = indexes[v];
66 | }
67 | return result;
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return "Triangle[" + verts[0] + ", " + verts[1] + ", " + verts[2] + "]";
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/tri/TriangleProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.tri;
38 |
39 | import com.jme3.scene.Mesh;
40 |
41 |
42 | /**
43 | *
44 | *
45 | * @author Paul Speed
46 | */
47 | public interface TriangleProcessor {
48 | public void processTriangle( Mesh mesh, int index, Triangle tri );
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/tri/TriangleUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.tri;
38 |
39 | import com.jme3.math.Vector2f;
40 | import com.jme3.math.Vector3f;
41 | import com.jme3.scene.Geometry;
42 | import com.jme3.scene.Mesh;
43 | import com.jme3.scene.Node;
44 | import com.jme3.scene.Spatial;
45 | import com.jme3.scene.VertexBuffer;
46 | import com.jme3.scene.VertexBuffer.Type;
47 | import com.jme3.scene.mesh.IndexBuffer;
48 | import java.nio.FloatBuffer;
49 | import org.slf4j.Logger;
50 | import org.slf4j.LoggerFactory;
51 |
52 |
53 | /**
54 | *
55 | *
56 | * @author Paul Speed
57 | */
58 | public class TriangleUtils {
59 |
60 | static Logger log = LoggerFactory.getLogger(TriangleUtils.class);
61 |
62 | public static int processTriangles( Mesh mesh, TriangleProcessor proc ) {
63 | if( log.isTraceEnabled() ) {
64 | log.trace("processTriangles(" + mesh + ", " + proc + ")");
65 | log.trace(" verts:" + mesh.getVertexCount() + " mode:" + mesh.getMode());
66 | }
67 | if( mesh.getVertexCount() == 0 ) {
68 | return 0;
69 | }
70 | switch( mesh.getMode() ) {
71 | case LineLoop:
72 | case Lines:
73 | case LineStrip:
74 | case Points:
75 | return 0; // no triangles in those
76 | case Hybrid:
77 | case TriangleFan:
78 | case TriangleStrip:
79 | throw new UnsupportedOperationException("Mesh type not yet supported:" + mesh.getMode());
80 | case Triangles:
81 | if( mesh.getIndexBuffer() != null ) {
82 | return doIndexedTriangles(mesh, proc);
83 | } else {
84 | return doTriangles(mesh, proc);
85 | }
86 | default:
87 | return 0;
88 | }
89 | }
90 |
91 | public static int processTriangles( Spatial s, TriangleProcessor proc ) {
92 | if( log.isTraceEnabled() ) {
93 | log.trace("processTriangles(Spatial:" + s + ", proc:" + proc + ")");
94 | }
95 | int count = 0;
96 | if( s instanceof Node ) {
97 | for( Spatial child : ((Node)s).getChildren() ) {
98 | count += processTriangles(child, proc);
99 | }
100 | } else if( s instanceof Geometry ) {
101 | count += processTriangles(((Geometry)s).getMesh(), proc);
102 | } else {
103 | throw new UnsupportedOperationException("Unsupported spatial type:" + s);
104 | }
105 | return count;
106 | }
107 |
108 | protected static int doTriangles( Mesh mesh, TriangleProcessor proc ) {
109 | throw new UnsupportedOperationException("Non-indexed triangles not yet supported.");
110 | }
111 |
112 | protected static int doIndexedTriangles( Mesh mesh, TriangleProcessor proc ) {
113 | Triangle tri = new Triangle();
114 |
115 | VertexBuffer vbPos = mesh.getBuffer(Type.Position);
116 | int posSize = vbPos.getNumComponents();
117 | VertexBuffer vbNorms = mesh.getBuffer(Type.Normal);
118 | int normSize = 0;
119 | VertexBuffer vbTexes = mesh.getBuffer(Type.TexCoord);
120 | int texesSize = 0;
121 |
122 | FloatBuffer pos = ((FloatBuffer)vbPos.getData()).duplicate();
123 | FloatBuffer norms = null;
124 | if( vbNorms != null ) {
125 | norms = ((FloatBuffer)vbNorms.getData()).duplicate();
126 | normSize = vbNorms.getNumComponents();
127 | }
128 | FloatBuffer texes = null;
129 | if( vbTexes != null ) {
130 | texes = ((FloatBuffer)vbTexes.getData()).duplicate();
131 | texesSize = vbTexes.getNumComponents();
132 | }
133 |
134 | IndexBuffer ib = mesh.getIndexBuffer();
135 | int size = ib.size();
136 | int triangleIndex = 0;
137 | for( int i = 0; i < size; ) {
138 | for( int v = 0; v < 3; v++ ) {
139 | int index = ib.get(i++);
140 | tri.indexes[v] = index;
141 |
142 | pos.position(index * posSize);
143 | Vector3f vert = tri.verts[v];
144 | vert.x = pos.get();
145 | vert.y = pos.get();
146 | vert.z = pos.get();
147 | if( norms != null ) {
148 | norms.position(index * normSize);
149 | Vector3f norm = tri.norms[v];
150 | norm.x = norms.get();
151 | norm.y = norms.get();
152 | norm.z = norms.get();
153 | }
154 | if( texes != null ) {
155 | texes.position(index * texesSize);
156 | Vector2f tex = tri.texes[v];
157 | tex.x = texes.get();
158 | tex.y = texes.get();
159 | }
160 | }
161 | proc.processTriangle(mesh, triangleIndex++, tri);
162 | }
163 | return triangleIndex;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/util/BilinearArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.util;
38 |
39 |
40 | import com.jme3.texture.Image;
41 | import com.jme3.texture.Image.Format;
42 | import com.jme3.texture.Texture;
43 | import java.nio.ByteBuffer;
44 | import org.slf4j.Logger;
45 | import org.slf4j.LoggerFactory;
46 |
47 |
48 | /**
49 | * Array data that can be sampled with bilinear interpolation
50 | * similar to the way textures are sampled. This is an 'int'
51 | * array but the 4 bytes in each int are interpolated separately
52 | * as if they represent a four component color.
53 | *
54 | * @author Paul Speed
55 | */
56 | public class BilinearArray {
57 |
58 | static Logger log = LoggerFactory.getLogger(BilinearArray.class);
59 |
60 | private int width;
61 | private int height;
62 | private int[] array;
63 |
64 | public BilinearArray( int width, int height ) {
65 | this.width = width;
66 | this.height = height;
67 | this.array = new int[width * height];
68 | }
69 |
70 | public static BilinearArray fromTexture( Texture texture ) {
71 | return fromImage(texture.getImage());
72 | }
73 |
74 | public static BilinearArray fromImage( Image image ) {
75 | BilinearArray result = new BilinearArray(image.getWidth(), image.getHeight());
76 |
77 | ByteBuffer data = image.getData(0);
78 | data.rewind();
79 |
80 | //System.out.println( "Format:" + image.getFormat() + " bpp:" + image.getFormat().getBitsPerPixel() );
81 | Format format = image.getFormat();
82 | int span = image.getFormat().getBitsPerPixel() / 8;
83 | int size = result.array.length;
84 |
85 | for( int i = 0; i < size; i++ ) {
86 | byte b1 = data.get();
87 | byte b2 = 0;
88 | byte b3 = 0;
89 | byte b4 = 0;
90 | if( span > 1 ) {
91 | b2 = data.get();
92 | }
93 | if( span > 2 ) {
94 | b3 = data.get();
95 | }
96 | if( span > 3 ) {
97 | b4 = data.get();
98 | }
99 | if( span > 4 ) {
100 | for( int skip = 4; skip < span; skip++ ) {
101 | data.get();
102 | }
103 | }
104 |
105 | int value = 0;
106 | switch( format ) {
107 | case BGR8:
108 | value |= (b3 & 0xff) << 24;
109 | value |= (b2 & 0xff) << 16;
110 | value |= (b1 & 0xff) << 8;
111 | break;
112 | case ABGR8:
113 | value |= (b4 & 0xff) << 24;
114 | value |= (b3 & 0xff) << 16;
115 | value |= (b2 & 0xff) << 8;
116 | value |= (b1 & 0xff);
117 | break;
118 | default :
119 | // Default to rgb or rgba
120 | value |= (b1 & 0xff) << 24;
121 | value |= (b2 & 0xff) << 16;
122 | value |= (b3 & 0xff) << 8;
123 | value |= (b4 & 0xff);
124 | break;
125 | }
126 | result.array[i] = value;
127 | }
128 |
129 | return result;
130 | }
131 |
132 | private int index( int x, int y ) {
133 | return y * width + x;
134 | }
135 |
136 | private int wrappedIndex( int x, int y ) {
137 | x = x % width;
138 | y = y % height;
139 |
140 | if( x < 0 ) {
141 | x = width + x;
142 | }
143 | if( y < 0 ) {
144 | y = height + y;
145 | }
146 | int result = y * width + x;
147 | if( result >= array.length ) {
148 | throw new RuntimeException( "Bad clipping:" + x + ", " + y + " width:" + width + " height:" + height );
149 | }
150 | return result;
151 | }
152 |
153 | public int get( int x, int y ) {
154 | return array[wrappedIndex(x,y)];
155 | }
156 |
157 | public void set( int x, int y, int value ) {
158 | array[wrappedIndex(x,y)] = value;
159 | }
160 |
161 | public byte[] getHomogenous( double u, double v, byte[] target ) {
162 | return get(u * width, v * height, target);
163 | }
164 |
165 | public byte[] get( double x, double y, byte[] target ) {
166 | if( target == null ) {
167 | target = new byte[4];
168 | }
169 |
170 | int ll = get((int)Math.floor(x), (int)Math.floor(y));
171 | int lr = get((int)Math.ceil(x), (int)Math.floor(y));
172 | int ul = get((int)Math.floor(x), (int)Math.ceil(y));
173 | int ur = get((int)Math.ceil(x), (int)Math.ceil(y));
174 |
175 | if( log.isTraceEnabled() ) {
176 | log.trace("ll:%08X lr:%08X ul:%08X ur:%08X\n", ll, lr, ul, ur);
177 | }
178 | double xPart = x - Math.floor(x);
179 |
180 | int l1 = interpolate(ll & 0xff, lr & 0xff, xPart);
181 | int l2 = interpolate((ll >> 8 ) & 0xff, (lr >> 8 ) & 0xff, xPart);
182 | int l3 = interpolate((ll >> 16) & 0xff, (lr >> 16) & 0xff, xPart);
183 | int l4 = interpolate((ll >> 24) & 0xff, (lr >> 24) & 0xff, xPart);
184 |
185 | int u1 = interpolate(ul & 0xff, ur & 0xff, xPart);
186 | int u2 = interpolate((ul >> 8 ) & 0xff, (ur >> 8 ) & 0xff, xPart);
187 | int u3 = interpolate((ul >> 16) & 0xff, (ur >> 16) & 0xff, xPart);
188 | int u4 = interpolate((ul >> 24) & 0xff, (ur >> 24) & 0xff, xPart);
189 |
190 | double yPart = y - Math.floor(y);
191 |
192 | if( log.isTraceEnabled() ) {
193 | log.trace("lower: %02X%02X%02X%02X upper: %02X%02X%02X%02X\n", l4, l3, l2, l1, u4, u3, u2, u1 );
194 | }
195 |
196 | target[3] = (byte)interpolate(l1, u1, yPart);
197 | target[2] = (byte)interpolate(l2, u2, yPart);
198 | target[1] = (byte)interpolate(l3, u3, yPart);
199 | target[0] = (byte)interpolate(l4, u4, yPart);
200 |
201 | return target;
202 | }
203 |
204 | private int interpolate( int b1, int b2, double f ) {
205 | int result = b1 + (int)Math.round((b2 - b1) * f);
206 | return result;
207 | }
208 |
209 | public static String toString( byte[] array ) {
210 | return String.format("0x%02X%02X%02X%02X", array[0], array[1], array[2], array[3]);
211 | }
212 |
213 | public static void main( String... args ) {
214 |
215 | BilinearArray test = new BilinearArray(10, 10);
216 | test.set(0, 0, 0x01010404);
217 | test.set(1, 0, 0x08080404);
218 | test.set(0, 1, 0x02020202);
219 | test.set(1, 1, 0x08080808);
220 |
221 | System.out.println( "0,0=" + test.get(0,0) );
222 | System.out.println( "1,1=" + test.get(1,1) );
223 | System.out.println( "0.5,0.5=" + toString(test.get(0.5,0.5, null)) );
224 | System.out.println( "0.25,0.5=" + toString(test.get(0.25,0.5, null)) );
225 | System.out.println( "0.25,0.25=" + toString(test.get(0.25,0.25, null)) );
226 | System.out.println( "10,10=" + toString(test.get(10,10, null)) );
227 | System.out.println( "9.5,9.5=" + toString(test.get(9.5,9.5, null)) );
228 | System.out.println( "9.25,9.25=" + toString(test.get(9.25,9.25, null)) );
229 | }
230 |
231 | @Override
232 | public String toString() {
233 | return "BilinearArray[" + width + ", " + height + "]";
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/util/MatrixUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.util;
38 |
39 | import com.jme3.math.Matrix3f;
40 | import com.jme3.math.Matrix4f;
41 | import com.jme3.math.Quaternion;
42 | import com.jme3.util.BufferUtils;
43 | import java.nio.FloatBuffer;
44 |
45 |
46 | /**
47 | *
48 | *
49 | * @author Paul Speed
50 | */
51 | public class MatrixUtils {
52 |
53 | public static FloatBuffer createMatrixBuffer( int count ) {
54 | return BufferUtils.createFloatBuffer(count * 16);
55 | }
56 |
57 | public static FloatBuffer createMatrixBuffer( Matrix4f[] mats ) {
58 | FloatBuffer result = createMatrixBuffer(mats.length);
59 |
60 | Matrix3f rotMat = new Matrix3f();
61 | Quaternion rot = new Quaternion();
62 |
63 | for( Matrix4f mat : mats ) {
64 | mat.toRotationMatrix(rotMat);
65 | rot.fromRotationMatrix(rotMat);
66 |
67 | result.put(mat.m00);
68 | result.put(mat.m10);
69 | result.put(mat.m20);
70 | result.put(rot.getX());
71 | result.put(mat.m01);
72 | result.put(mat.m11);
73 | result.put(mat.m21);
74 | result.put(rot.getY());
75 | result.put(mat.m02);
76 | result.put(mat.m12);
77 | result.put(mat.m22);
78 | result.put(rot.getZ());
79 | result.put(mat.m03);
80 | result.put(mat.m13);
81 | result.put(mat.m23);
82 | result.put(rot.getW());
83 | }
84 |
85 | result.flip();
86 | return result;
87 | }
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/util/MeshCompareUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.util;
38 |
39 | import com.jme3.scene.Mesh;
40 | import com.jme3.scene.VertexBuffer;
41 | import com.jme3.scene.VertexBuffer.Type;
42 | import java.nio.FloatBuffer;
43 | import java.nio.IntBuffer;
44 | import java.nio.ShortBuffer;
45 | import org.slf4j.Logger;
46 | import org.slf4j.LoggerFactory;
47 |
48 |
49 | /**
50 | * Utility methods for comparing meshes and mesh parts.
51 | *
52 | * @author Paul Speed
53 | */
54 | public class MeshCompareUtil {
55 |
56 | static Logger log = LoggerFactory.getLogger(MeshCompareUtil.class);
57 |
58 | public static boolean compare( Mesh mesh1, Mesh mesh2 ) {
59 | VertexBuffer[] source = mesh1.getBufferList().getArray();
60 | for( int i = 0; i < source.length; i++ ) {
61 | VertexBuffer comp = mesh2.getBuffer(source[i].getBufferType());
62 | if( comp == null ) {
63 | log.info("Second mesh has no type:" + source[i].getBufferType());
64 | return false;
65 | }
66 | if( !compare(source[i], comp) ) {
67 | return false;
68 | }
69 | }
70 | return true;
71 | }
72 |
73 | public static boolean compare( VertexBuffer vb1, VertexBuffer vb2 ) {
74 | if( vb1.getBufferType() != vb2.getBufferType() ) {
75 | log.info("Buffer types differ 1:" + vb1.getBufferType() + " 2:" + vb2.getBufferType());
76 | return false;
77 | }
78 | if( vb1.getFormat() != vb2.getFormat() ) {
79 | log.info("Buffer formats differ for type:" + vb1.getBufferType()
80 | + " 1:" + vb1.getFormat() + " 2:" + vb2.getFormat());
81 | return false;
82 | }
83 | if( vb1.getNumComponents() != vb2.getNumComponents() ) {
84 | log.info("Buffer components differ for type:" + vb1.getBufferType()
85 | + " 1:" + vb1.getNumComponents() + " 2:" + vb2.getNumComponents());
86 | return false;
87 | }
88 | switch( vb1.getFormat() ) {
89 | case Float:
90 | if( !compare(vb1.getBufferType(), (FloatBuffer)vb1.getData(), (FloatBuffer)vb2.getData()) ) {
91 | return false;
92 | }
93 | break;
94 | case UnsignedShort:
95 | case Short:
96 | if( !compare(vb1.getBufferType(), (ShortBuffer)vb1.getData(), (ShortBuffer)vb2.getData()) ) {
97 | return false;
98 | }
99 | break;
100 | case UnsignedInt:
101 | case Int:
102 | if( !compare(vb1.getBufferType(), (IntBuffer)vb1.getData(), (IntBuffer)vb2.getData()) ) {
103 | return false;
104 | }
105 | break;
106 | default:
107 | throw new UnsupportedOperationException("Unhandled format" + vb1.getFormat());
108 | }
109 | return true;
110 | }
111 |
112 | public static boolean compare( Type type, FloatBuffer b1, FloatBuffer b2 ) {
113 | b1.rewind();
114 | b2.rewind();
115 | for( int i = 0; i < b1.limit(); i++ ) {
116 | float v1 = b1.get();
117 | float v2 = b2.get();
118 | if( v1 != v2 ) {
119 | log.info("Type:" + type + " differs at pos:" + i + " 1:" + v1 + " 2:" + v2);
120 | return false;
121 | }
122 | }
123 | return true;
124 | }
125 |
126 | public static boolean compare( Type type, ShortBuffer b1, ShortBuffer b2 ) {
127 | b1.rewind();
128 | b2.rewind();
129 | for( int i = 0; i < b1.limit(); i++ ) {
130 | short v1 = b1.get();
131 | short v2 = b2.get();
132 | if( v1 != v2 ) {
133 | log.info("Type:" + type + " differs at pos:" + i + " 1:" + v1 + " 2:" + v2);
134 | return false;
135 | }
136 | }
137 | return true;
138 | }
139 |
140 | public static boolean compare( Type type, IntBuffer b1, IntBuffer b2 ) {
141 | b1.rewind();
142 | b2.rewind();
143 | for( int i = 0; i < b1.limit(); i++ ) {
144 | int v1 = b1.get();
145 | int v2 = b2.get();
146 | if( v1 != v2 ) {
147 | log.info("Type:" + type + " differs at pos:" + i + " 1:" + v1 + " 2:" + v2);
148 | return false;
149 | }
150 | }
151 | return true;
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/volume/ArrayDensityVolume.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.volume;
38 |
39 | import com.jme3.math.Vector3f;
40 | import com.simsilica.iso.DensityVolume;
41 | import java.util.Arrays;
42 |
43 |
44 | /**
45 | * A DensityVolume implementation backed by a fixed size
46 | * array of values. These may be set directly or extracted
47 | * from an existing DensityField as required. Intercell
48 | * sampling is done using trilinear interpolation.
49 | *
50 | * @author Paul Speed
51 | */
52 | public class ArrayDensityVolume implements DensityVolume {
53 |
54 | private int cx, cy, cz, cLayer;
55 | private float[] array;
56 |
57 | public ArrayDensityVolume( int width, int height, int depth ) {
58 | this.array = new float[width * height * depth];
59 | this.cx = width;
60 | this.cy = height;
61 | this.cz = depth;
62 | this.cLayer = cx * cy;
63 | }
64 |
65 | public static ArrayDensityVolume create( float[][][] source,
66 | int width, int height, int depth ) {
67 | ArrayDensityVolume result = new ArrayDensityVolume(width, height, depth);
68 | int index = 0;
69 | float[] target = result.array;
70 | for( int z = 0; z < depth; z++ ) {
71 | for( int y = 0; y < height; y++ ) {
72 | for( int x = 0; x < width; x++ ) {
73 | target[index++] = source[x][y][z];
74 | }
75 | }
76 | }
77 | return result;
78 | }
79 |
80 | public static ArrayDensityVolume extractVolume( DensityVolume source,
81 | int xBase, int yBase, int zBase,
82 | int width, int height, int depth ) {
83 | ArrayDensityVolume result = new ArrayDensityVolume(width, height, depth);
84 | int index = 0;
85 | float[] target = result.array;
86 | for( int z = 0; z < depth; z++ ) {
87 | for( int y = 0; y < height; y++ ) {
88 | for( int x = 0; x < width; x++ ) {
89 | target[index++] = source.getDensity(xBase+x, yBase+y, zBase+z);
90 | }
91 | }
92 | }
93 | return result;
94 | }
95 |
96 | public void extract( DensityVolume source, int xBase, int yBase, int zBase ) {
97 | int index = 0;
98 | for( int z = 0; z < cz; z++ ) {
99 | for( int y = 0; y < cy; y++ ) {
100 | for( int x = 0; x < cx; x++ ) {
101 | array[index++] = source.getDensity(xBase+x, yBase+y, zBase+z);
102 | }
103 | }
104 | }
105 | }
106 |
107 | public void clear() {
108 | Arrays.fill(array, -1);
109 | }
110 |
111 | private int index( int x, int y, int z ) {
112 | /*if( x < 0 || y < 0 || z < 0 || x >= cx || y >= cy || z >= cz ) {
113 | throw new IndexOutOfBoundsException( "(" + x + ", " + y + ", " + z + ") in size:" + cx + ", " + cy + ", " + cz );
114 | }*/
115 | return z * cLayer + cx * y + x;
116 | }
117 |
118 | public void setDensity( int x, int y, int z, float d ) {
119 | array[index(x, y, z)] = d;
120 | }
121 |
122 | public float getDensity( int x, int y, int z ) {
123 | return array[index(x, y, z)];
124 | }
125 |
126 | private double trilinear( float x, float y, float z ) {
127 | int xBase = (int)Math.floor(x);
128 | int yBase = (int)Math.floor(y);
129 | int zBase = (int)Math.floor(z);
130 | int xTop = (int)Math.ceil(x);
131 | int yTop = (int)Math.ceil(y);
132 | int zTop = (int)Math.ceil(z);
133 |
134 | double c000 = array[index(xBase, yBase, zBase)];
135 | double c100 = array[index(xTop, yBase, zBase)];
136 | double c101 = array[index(xTop, yBase, zTop)];
137 | double c001 = array[index(xBase, yBase, zTop)];
138 | double c010 = array[index(xBase, yTop, zBase)];
139 | double c110 = array[index(xTop, yTop, zBase)];
140 | double c111 = array[index(xTop, yTop, zTop)];
141 | double c011 = array[index(xBase, yTop, zTop)];
142 |
143 | double xPart = x - xBase;
144 | double cx00 = c000 + (c100 - c000) * xPart;
145 | double cx01 = c001 + (c101 - c001) * xPart;
146 |
147 | double cx10 = c010 + (c110 - c010) * xPart;
148 | double cx11 = c011 + (c111 - c011) * xPart;
149 |
150 | double yPart = y - yBase;
151 | double cxy0 = cx00 + (cx10 - cx00) * yPart;
152 | double cxy1 = cx01 + (cx11 - cx01) * yPart;
153 |
154 | double zPart = z - zBase;
155 | double c = cxy0 + (cxy1 - cxy0) * zPart;
156 |
157 | return c;
158 | }
159 |
160 |
161 | public float getDensity( float x, float y, float z ) {
162 | return (float)trilinear(x, y, z);
163 | }
164 |
165 | public Vector3f getFieldDirection( float x, float y, float z, Vector3f target ) {
166 |
167 | float d = 1f;
168 |
169 | double nx = trilinear(x + d, y, z)
170 | - trilinear(x - d, y, z);
171 | double ny = trilinear(x, y + d, z)
172 | - trilinear(x, y - d, z);
173 | double nz = trilinear(x, y, z + d)
174 | - trilinear(x, y, z - d);
175 |
176 | if( target == null ) {
177 | target = new Vector3f((float)-nx, (float)-ny, (float)-nz).normalizeLocal();
178 | } else {
179 | target.set((float)-nx, (float)-ny, (float)-nz);
180 | target.normalizeLocal();
181 | }
182 |
183 | return target;
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/volume/CachingDensityVolume.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.volume;
38 |
39 | import com.google.common.cache.CacheBuilder;
40 | import com.google.common.cache.CacheLoader;
41 | import com.google.common.cache.LoadingCache;
42 | import com.jme3.math.Vector3f;
43 | import com.simsilica.iso.DensityVolume;
44 | import com.simsilica.pager.Grid;
45 | import java.util.concurrent.ExecutionException;
46 |
47 |
48 | /**
49 | * Presents a continuous array-based view of 'chunks' that
50 | * are extracted from a continuous source field.
51 | *
52 | * @author Paul Speed
53 | */
54 | public class CachingDensityVolume implements DensityVolume {
55 |
56 | private DensityVolume source;
57 | private int xzSize;
58 | private int ySize;
59 | private int superSample;
60 | private Grid grid;
61 | private LoadingCache cache;
62 |
63 | public CachingDensityVolume( int cacheSize, DensityVolume source, int xzSize, int ySize, int xzSuperSample ) {
64 | this.source = source;
65 | this.superSample = xzSuperSample;
66 | this.xzSize = xzSize / xzSuperSample;
67 | this.ySize = ySize;
68 | this.grid = new Grid(xzSize, ySize, xzSize);
69 |
70 | this.cache = CacheBuilder.newBuilder().maximumSize(cacheSize).build(new ChunkLoader());
71 | }
72 |
73 | public CachingDensityVolume( int cacheSize, DensityVolume source, int xzSize, int ySize ) {
74 | this(cacheSize, source, xzSize, ySize, 1);
75 | }
76 |
77 | private Chunk getChunk( int x, int y, int z ) {
78 | int xCell = grid.toCellX(x);
79 | int yCell = grid.toCellY(y);
80 | int zCell = grid.toCellZ(z);
81 | try {
82 | return cache.get(new ChunkId(xCell, yCell, zCell));
83 | } catch( ExecutionException ex ) {
84 | throw new RuntimeException("Error creating chunk", ex);
85 | }
86 | }
87 |
88 | private Chunk getChunk( float x, float y, float z ) {
89 | int xCell = grid.toCellX(x);
90 | int yCell = grid.toCellY(y);
91 | int zCell = grid.toCellZ(z);
92 | try {
93 | return cache.get(new ChunkId(xCell, yCell, zCell));
94 | } catch( ExecutionException ex ) {
95 | throw new RuntimeException("Error creating chunk", ex);
96 | }
97 | }
98 |
99 | @Override
100 | public final float getDensity( int x, int y, int z ) {
101 | Chunk chunk = getChunk(x, y, z);
102 | return chunk.getDensity(x, y, z);
103 | }
104 |
105 | @Override
106 | public final float getDensity( float x, float y, float z ) {
107 | Chunk chunk = getChunk(x, y, z);
108 | return chunk.getDensity(x, y, z);
109 | }
110 |
111 | @Override
112 | public final Vector3f getFieldDirection( float x, float y, float z, Vector3f target ) {
113 | Chunk chunk = getChunk(x, y, z);
114 | return chunk.getFieldDirection(x, y, z, target);
115 | }
116 |
117 | private class ChunkId {
118 | int xChunk;
119 | int yChunk;
120 | int zChunk;
121 |
122 | public ChunkId( int x, int y, int z ) {
123 | this.xChunk = x;
124 | this.yChunk = y;
125 | this.zChunk = z;
126 | }
127 |
128 | @Override
129 | public final int hashCode() {
130 | int hash = 37;
131 | hash += 37 * hash + xChunk;
132 | hash += 37 * hash + yChunk;
133 | hash += 37 * hash + zChunk;
134 | return hash;
135 | }
136 |
137 | @Override
138 | public final boolean equals( Object o ) {
139 | if( o == null || o.getClass() != getClass() )
140 | return false;
141 | if( o == this )
142 | return true;
143 | ChunkId other = (ChunkId)o;
144 | if( other.xChunk != xChunk )
145 | return false;
146 | if( other.yChunk != yChunk )
147 | return false;
148 | if( other.zChunk != zChunk )
149 | return false;
150 | return true;
151 | }
152 |
153 | @Override
154 | public String toString() {
155 | return "ChunkId[" + xChunk + ", " + yChunk + ", " + zChunk + "]";
156 | }
157 | }
158 |
159 | private class Chunk implements DensityVolume {
160 | ChunkId id;
161 | DensityVolume volume;
162 | int xBase;
163 | int yBase;
164 | int zBase;
165 |
166 | public Chunk( ChunkId id, int xBase, int yBase, int zBase, DensityVolume volume ) {
167 | this.id = id;
168 | this.volume = volume;
169 | this.xBase = xBase;
170 | this.yBase = yBase;
171 | this.zBase = zBase;
172 | }
173 |
174 | @Override
175 | public final float getDensity( int x, int y, int z ) {
176 | return volume.getDensity(x - xBase, y - yBase, z - zBase);
177 | }
178 |
179 | @Override
180 | public final float getDensity( float x, float y, float z ) {
181 | return volume.getDensity(x - xBase, y - yBase, z - zBase);
182 | }
183 |
184 | @Override
185 | public final Vector3f getFieldDirection( float x, float y, float z, Vector3f target ) {
186 | return volume.getFieldDirection(x - xBase, y - yBase, z - zBase, target);
187 | }
188 | }
189 |
190 | public static void main( String... args ) {
191 | // Testing something
192 |
193 | DensityVolume source = new DensityVolume() {
194 | @Override
195 | public float getDensity( int x, int y, int z ) {
196 | return x;
197 | }
198 |
199 | @Override
200 | public float getDensity( float x, float y, float z ) {
201 | return x;
202 | }
203 |
204 | @Override
205 | public Vector3f getFieldDirection( float x, float y, float z, Vector3f target ) {
206 | return null;
207 | }
208 | };
209 |
210 | int xBase = 100;
211 | int superSample = 2;
212 | int xzSize = 16;
213 | int ySize = 32;
214 |
215 | ResamplingVolume resampled = new ResamplingVolume(new Vector3f(superSample, 1, superSample),
216 | new Vector3f(xBase, 0, 0),
217 | source);
218 |
219 | // Since we've moved prescaled origin then our xBase, yBase, etc. are already
220 | // moved for us
221 | DensityVolume result = ArrayDensityVolume.extractVolume(resampled, -2, -2, -2,
222 | xzSize + 4, ySize + 4, xzSize + 4);
223 |
224 | for( int x = 0; x < 16; x++ ) {
225 | System.out.println( "intermediate:" + result.getDensity(x, 0, 0) );
226 | }
227 |
228 | // Now unscale it... we don't have to unmove it because
229 | // the chunk access is already translating it as if it were an array
230 | // based at 0, 0... but we'll offset for the border we created.
231 | result = new ResamplingVolume(new Vector3f(1f/superSample, 1, 1f/superSample),
232 | new Vector3f(2, 2, 2),
233 | result);
234 |
235 | for( int x = 100; x < 132; x++ ) {
236 | System.out.println( "Original:" + source.getDensity(x, 0, 0)
237 | + " Resampled:" + result.getDensity(x-xBase, 0, 0) );
238 | }
239 | }
240 |
241 | private class ChunkLoader extends CacheLoader {
242 |
243 | @Override
244 | public Chunk load( ChunkId id ) throws Exception {
245 |
246 | System.out.println( "Loading chunk:" + id );
247 | int xBase = (int)grid.toWorldX(id.xChunk);
248 | int yBase = (int)grid.toWorldY(id.yChunk);
249 | int zBase = (int)grid.toWorldZ(id.zChunk);
250 |
251 | DensityVolume result;
252 | if( superSample != 1 ) {
253 | // If we are super-sampling then we extract less data but
254 | // treat it like more data. It also means we are extracting
255 | // from a different place, though.
256 | // For example, if we have a cell size of 16 x 16 but we
257 | // are super-sampling *2 then we are really building an array of
258 | // 8 x 8 by skipping every other value. But that means when
259 | // x = 3 in the 'regular world' that it's really 1.5 in the
260 | // super-sampled world.
261 | // Now, we can unscale it when returning and now we can skip
262 | // resolution.
263 | // xzSize has already had supersampling factored in.
264 | ResamplingVolume resampled = new ResamplingVolume(new Vector3f(superSample, 1, superSample),
265 | new Vector3f(xBase, yBase, zBase),
266 | source);
267 | // So we've setup sampling with xBase, yBase, zBase as 0,0,0 in our
268 | // source, and scaled by superSample otherwise
269 |
270 |
271 | // Since we've moved prescaled origin then our xBase, yBase, etc. are already
272 | // moved for us
273 | result = ArrayDensityVolume.extractVolume(resampled, -2, -2, -2,
274 | xzSize + 4, ySize + 4, xzSize + 4);
275 | // The array now represents:
276 | // xBase - 2 * superSample to that plus (xzSize + 4) * superSample
277 |
278 | // Now unscale it... we don't have to unmove it because
279 | // the chunk access is already translating it as if it were an array
280 | // based at 0, 0... but we'll offset for the border we created.
281 | result = new ResamplingVolume(new Vector3f(1f/superSample, 1, 1f/superSample),
282 | new Vector3f(2, 2, 2),
283 | result);
284 | // So, the above indexes 0 as 2, 2, 2 in the array... which represented
285 | // a skipped version of our regular world so we un-sample to index into
286 | // it properly.
287 | } else {
288 | // Make the chunk 2 elements bigger all the way
289 | // around so that the field direction is likely to work
290 | // ArrayDensityVolume samples coordinate + 1... which means
291 | // that 8.5 + 1 = 9.5 which means that we'd need element 10
292 | // also... not just element 9
293 | xBase-=2;
294 | yBase-=2;
295 | zBase-=2;
296 |
297 | result = ArrayDensityVolume.extractVolume(source, xBase, yBase, zBase,
298 | xzSize + 4, ySize + 4, xzSize + 4);
299 | }
300 |
301 | return new Chunk(id, xBase, yBase, zBase, result);
302 | }
303 | }
304 | }
305 |
306 |
307 |
--------------------------------------------------------------------------------
/src/main/java/com/simsilica/iso/volume/ResamplingVolume.java:
--------------------------------------------------------------------------------
1 | /*
2 | * $Id$
3 | *
4 | * Copyright (c) 2014, Simsilica, LLC
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions
9 | * are met:
10 | *
11 | * 1. Redistributions of source code must retain the above copyright
12 | * notice, this list of conditions and the following disclaimer.
13 | *
14 | * 2. Redistributions in binary form must reproduce the above copyright
15 | * notice, this list of conditions and the following disclaimer in
16 | * the documentation and/or other materials provided with the
17 | * distribution.
18 | *
19 | * 3. Neither the name of the copyright holder nor the names of its
20 | * contributors may be used to endorse or promote products derived
21 | * from this software without specific prior written permission.
22 | *
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 | * OF THE POSSIBILITY OF SUCH DAMAGE.
35 | */
36 |
37 | package com.simsilica.iso.volume;
38 |
39 | import com.jme3.math.Vector3f;
40 | import com.simsilica.iso.DensityVolume;
41 |
42 |
43 | /**
44 | * Presents a resampled view of a delegate volume where the
45 | * x, y, and z space may be rescaled.
46 | *
47 | * @author Paul Speed
48 | */
49 | public class ResamplingVolume implements DensityVolume {
50 |
51 | private Vector3f offset;
52 | private Vector3f scale;
53 | private DensityVolume delegate;
54 |
55 | public ResamplingVolume( Vector3f scale, DensityVolume delegate ) {
56 | this(scale, Vector3f.ZERO, delegate);
57 | }
58 |
59 | public ResamplingVolume( Vector3f scale, Vector3f preScaleOffset, DensityVolume delegate ) {
60 | this.scale = scale.clone();
61 | this.offset = preScaleOffset.clone();
62 | this.delegate = delegate;
63 | }
64 |
65 | public float getDensity( int x, int y, int z ) {
66 | return getDensity((float)x, (float)y, (float)z);
67 | }
68 |
69 | public float getDensity( float x, float y, float z ) {
70 | x *= scale.x;
71 | y *= scale.y;
72 | z *= scale.z;
73 | x += offset.x;
74 | y += offset.y;
75 | z += offset.z;
76 | return delegate.getDensity(x, y, z);
77 | }
78 |
79 | public Vector3f getFieldDirection( float x, float y, float z, Vector3f target ) {
80 | float xt = x * scale.x;
81 | float yt = y * scale.y;
82 | float zt = z * scale.z;
83 | xt += offset.x;
84 | yt += offset.y;
85 | zt += offset.z;
86 | Vector3f dir = delegate.getFieldDirection(xt, yt, zt, target);
87 | return dir;
88 | }
89 |
90 | @Override
91 | public String toString() {
92 | return "ResamplingVolume[" + scale + ", " + offset + ", " + delegate + "]";
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/license.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Simsilica, LLC
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions
7 | * are met:
8 | *
9 | * 1. Redistributions of source code must retain the above copyright
10 | * notice, this list of conditions and the following disclaimer.
11 | *
12 | * 2. Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in
14 | * the documentation and/or other materials provided with the
15 | * distribution.
16 | *
17 | * 3. Neither the name of the copyright holder nor the names of its
18 | * contributors may be used to endorse or promote products derived
19 | * from this software without specific prior written permission.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
32 | * OF THE POSSIBILITY OF SUCH DAMAGE.
33 | */
34 |
35 |
--------------------------------------------------------------------------------