diff --git a/src/main/kotlin/CustomDefaultShader.kt b/src/main/kotlin/CustomDefaultShader.kt index eda4cad..a230296 100644 --- a/src/main/kotlin/CustomDefaultShader.kt +++ b/src/main/kotlin/CustomDefaultShader.kt @@ -3,6 +3,9 @@ package gay.pizza.CavesOfJolk import com.badlogic.gdx.graphics.g3d.Attributes import com.badlogic.gdx.graphics.g3d.Renderable import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute +import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute +import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute +import com.badlogic.gdx.graphics.g3d.shaders.BaseShader import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader class CustomDefaultShader(renderable: Renderable, config: Config): @@ -18,6 +21,13 @@ class CustomDefaultShader(renderable: Renderable, config: Config): renderable.environment.let { attribs.set(it) } renderable.material.let { attribs.set(it) } + if (attribs.has(CustomFloatAttribute.BumpHeight) && attribs.has(TextureAttribute.Bump)) + { + prefix += "#define " + CustomFloatAttribute.BumpHeightAlias + "Flag\n" + prefix += "#define " + TextureAttribute.BumpAlias + "Flag\n" + prefix += "#define " + TextureAttribute.BumpAlias + "Coord texCoord0\n" + } + if (attribs.has(ColorAttribute.Fog)) { prefix += "#define fog${ @@ -50,6 +60,41 @@ class CustomDefaultShader(renderable: Renderable, config: Config): val fogNear = Uniform("u_fogNear") val fogFar = Uniform("u_fogFar") val fogDensity = Uniform("u_fogDensity") + + val bumpHeight = Uniform("u_bumpHeight") + + val bumpTexture = Uniform("u_bumpTexture") + val bumpUVTransform = Uniform("u_bumpUVTransform") + } + + object Setters + { + val bumpHeight = object: LocalSetter() + { + override fun set(shader: BaseShader, inputId: Int, renderable: Renderable, combAttribs: Attributes) + { + val attr = combAttribs.get(CustomFloatAttribute.BumpHeight) as FloatAttribute + shader.set(inputId, attr.value) + } + } + + val bumpTexture = object: LocalSetter() + { + override fun set(shader: BaseShader, inputId: Int, renderable: Renderable, combAttribs: Attributes) + { + val texAttr = combAttribs.get(TextureAttribute.Bump) as TextureAttribute + val unit = shader.context.textureBinder.bind(texAttr.textureDescription) + shader.set(inputId, unit) + } + } + var bumpUVTransform = object: LocalSetter() + { + override fun set(shader: BaseShader, inputId: Int, renderable: Renderable, combAttribs: Attributes) + { + val ta = combAttribs.get(TextureAttribute.Normal) as TextureAttribute + shader.set(inputId, ta.offsetU, ta.offsetV, ta.scaleU, ta.scaleV) + } + } } } @@ -57,6 +102,10 @@ class CustomDefaultShader(renderable: Renderable, config: Config): private val u_fogFar = register(Inputs.fogFar) private val u_fogDensity = register(Inputs.fogDensity) + private val u_bumpHeight = register(Inputs.bumpHeight, Setters.bumpHeight) + private val u_bumpTexture = register(Inputs.bumpTexture, Setters.bumpTexture) + private val u_bumpUVTransform = register(Inputs.bumpUVTransform, Setters.bumpUVTransform) + override fun bindLights(renderable: Renderable?, attributes: Attributes?) { if (attributes == null) diff --git a/src/main/kotlin/CustomDefaultShaderProvider.kt b/src/main/kotlin/CustomDefaultShaderProvider.kt index f8323cb..a2d3e85 100644 --- a/src/main/kotlin/CustomDefaultShaderProvider.kt +++ b/src/main/kotlin/CustomDefaultShaderProvider.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.g3d.Renderable import com.badlogic.gdx.graphics.g3d.Shader import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute +import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider @@ -29,6 +30,11 @@ class CustomDefaultShaderProvider(config: DefaultShader.Config): DefaultShaderPr CustomFloatAttribute.FogDensity if ((renderableMask and ColorAttribute.Fog == ColorAttribute.Fog) && (renderableMask and fogMask != 0L)) return CustomDefaultShader(renderable, config) + + val bumpMask = CustomFloatAttribute.BumpHeight or TextureAttribute.Bump + if (renderableMask and bumpMask == bumpMask) + return CustomDefaultShader(renderable, config) + return super.createShader(renderable) } } diff --git a/src/main/kotlin/CustomFloatAttribute.kt b/src/main/kotlin/CustomFloatAttribute.kt index 2171dfd..0746ac0 100644 --- a/src/main/kotlin/CustomFloatAttribute.kt +++ b/src/main/kotlin/CustomFloatAttribute.kt @@ -17,5 +17,9 @@ class CustomFloatAttribute private constructor(type: Long, value: Float): FloatA const val FogDensityAlias = "fogDensity" val FogDensity = register(FogDensityAlias) fun createFogDensity(value: Float) = CustomFloatAttribute(FogDensity, value) + + const val BumpHeightAlias = "bumpHeight" + val BumpHeight = register(BumpHeightAlias) + fun createBumpHeight(value: Float) = CustomFloatAttribute(BumpHeight, value) } } diff --git a/src/main/kotlin/Game.kt b/src/main/kotlin/Game.kt index e405051..bab5db7 100644 --- a/src/main/kotlin/Game.kt +++ b/src/main/kotlin/Game.kt @@ -22,10 +22,10 @@ import ktx.math.times class Game: ApplicationAdapter() { - private lateinit var texJolk: Texture private lateinit var fntComic: BitmapFont private lateinit var cube: Model private lateinit var floor: Model + private lateinit var toybox: Model private lateinit var spriteBatch: SpriteBatch private lateinit var modelBatch: ModelBatch @@ -41,23 +41,17 @@ class Game: ApplicationAdapter() private lateinit var suzanneInstance: ModelInstance private lateinit var rockBatch: ModelCache private lateinit var knux: ModelInstance + private lateinit var toyboxInstance: ModelInstance - private fun makeCube(texture: Texture): Model + private fun makeCube(size: Float, material: Material): Model { - val modelBuilder = ModelBuilder() - val size = 2.0f - val material = Material( - ColorAttribute.createDiffuse(XnaColor.White), - TextureAttribute(TextureAttribute.Diffuse, - TextureDescriptor(texture, - Texture.TextureFilter.Linear, - Texture.TextureFilter.Linear, - Texture.TextureWrap.ClampToEdge, - Texture.TextureWrap.ClampToEdge)), - ColorAttribute.createSpecular(XnaColor.Gray), - FloatAttribute.createShininess(20.0f)) - val attribs = VertexAttributes.Usage.Position or VertexAttributes.Usage.TextureCoordinates or VertexAttributes.Usage.Normal - return modelBuilder.createBox(size, size, size, material, attribs.toLong()) + ModelBuilder().apply { + val attribs = + VertexAttributes.Usage.Position or + VertexAttributes.Usage.TextureCoordinates or + VertexAttributes.Usage.Normal + return createBox(size, size, size, material, attribs.toLong()) + } } private fun makeFloor(size: Float): Model @@ -103,8 +97,9 @@ class Game: ApplicationAdapter() shininess = 65.0f textures = Array() textures.add( - modelTexture(ModelTexture.USAGE_DIFFUSE, "cobblestone.png"), - modelTexture(ModelTexture.USAGE_NORMAL, "cobblestone_normal.png"), + modelTexture(ModelTexture.USAGE_DIFFUSE, "cobblestone.png"), + modelTexture(ModelTexture.USAGE_NORMAL, "cobblestone_normal.png"), + modelTexture(ModelTexture.USAGE_BUMP, "cobblestone_bump.png"), modelTexture(ModelTexture.USAGE_SPECULAR, "cobblestone_specular.png")) }) nodes.add(ModelNode().apply { @@ -115,7 +110,9 @@ class Game: ApplicationAdapter() materialId = "floormat" }) }) - }, AssetTextureProvider(assetManager)) + }, AssetTextureProvider(assetManager)).apply { + materials[0].set(CustomFloatAttribute.createBumpHeight(0.0075f)) + } } override fun create() @@ -123,11 +120,20 @@ class Game: ApplicationAdapter() Resources.instance.loadAssets() assetManager.finishLoading() - texJolk = assetManager.get("jolkmeup.jpg") fntComic = assetManager.get("Comic Sans MS.ttf") - cube = makeCube(texJolk) - var joeMany = 56.0f + cube = makeCube(2.0f, Material( + ColorAttribute.createDiffuse(XnaColor.White), + TextureAttribute(TextureAttribute.Diffuse, TextureDescriptor(assetManager.get("jolkmeup.jpg"))), + ColorAttribute.createSpecular(XnaColor.Gray), + FloatAttribute.createShininess(20.0f))) + toybox = assetManager.get("toybox.g3db", Model::class.java).apply { materials[0].set( + TextureAttribute(TextureAttribute.Diffuse, TextureDescriptor(assetManager.get("toybox_albedo.png"))), + TextureAttribute(TextureAttribute.Normal, TextureDescriptor(assetManager.get("toybox_normal.png"))), + TextureAttribute(TextureAttribute.Bump, TextureDescriptor(assetManager.get("toybox_displace.png"))), + CustomFloatAttribute.createBumpHeight(0.04f), + FloatAttribute.createShininess(35.0f)) } + val joeMany = 56.0f floor = makeFloor(joeMany) spriteBatch = SpriteBatch() @@ -190,6 +196,7 @@ class Game: ApplicationAdapter() suzanneInstance.transform = Matrix4().translate(3.0f, 1.0f, -3.5f) knux = ModelInstance(assetManager.get("knux.g3db", Model::class.java)) + toyboxInstance = ModelInstance(toybox) } override fun resize(width: Int, height: Int) @@ -247,12 +254,19 @@ class Game: ApplicationAdapter() knux.transform.rotate(Quaternion().slerp(rand.nextQuaternion(), deltaTime)) knux.transform.translate(knux.transform * Util.forward * deltaTime) + toyboxInstance.transform = Matrix4( + Vector3(6.0f, 0.667f, -3.5f), + Quaternion().setEulerAnglesRad(lightTheta * 0.5f, 0.0f, 0.0f), + Util.one * 0.25f + ) + modelBatch.begin(colin.camera) modelBatch.render(floorInstance, env) modelBatch.render(rockBatch, env) modelBatch.render(cubeInstance, env) modelBatch.render(suzanneInstance, env) modelBatch.render(knux, env) + modelBatch.render(toyboxInstance, env) modelBatch.end() spriteBatch.begin() diff --git a/src/main/kotlin/Resources.kt b/src/main/kotlin/Resources.kt index d881670..799efc2 100644 --- a/src/main/kotlin/Resources.kt +++ b/src/main/kotlin/Resources.kt @@ -31,18 +31,25 @@ class Resources private constructor() assetManager.setLoader(BitmapFont::class.java, ".ttf", FreetypeFontLoader(resolver)) } - val linearMipped = TextureLoader.TextureParameter().apply { - minFilter = Texture.TextureFilter.MipMapLinearLinear - magFilter = Texture.TextureFilter.Linear - wrapU = Texture.TextureWrap.Repeat - wrapV = Texture.TextureWrap.Repeat - genMipMaps = true - } + val linearMipped = TextureLoader.TextureParameter().apply { + minFilter = Texture.TextureFilter.MipMapLinearLinear + magFilter = Texture.TextureFilter.Linear + wrapU = Texture.TextureWrap.Repeat + wrapV = Texture.TextureWrap.Repeat + genMipMaps = true + } + + val linearClamp = TextureLoader.TextureParameter().apply { + minFilter = Texture.TextureFilter.Linear + magFilter = Texture.TextureFilter.Linear + wrapU = Texture.TextureWrap.ClampToEdge + wrapV = Texture.TextureWrap.ClampToEdge + } fun loadAssets() { assetManager.load("colin.png", Texture::class.java) - assetManager.load("jolkmeup.jpg", Texture::class.java) + assetManager.load("jolkmeup.jpg", Texture::class.java, linearClamp) assetManager.loadFont("Comic Sans MS.ttf", 20) assetManager.load("suzanne.g3db", Model::class.java) assetManager.load("nut.wav", Sound::class.java) @@ -51,6 +58,11 @@ class Resources private constructor() assetManager.load("cobblestone_specular.png", Texture::class.java, linearMipped) assetManager.load("rock.g3db", Model::class.java) assetManager.load("knux.g3db", Model::class.java) + assetManager.load("toybox.g3db", Model::class.java) + assetManager.load("cobblestone_bump.png", Texture::class.java, linearMipped) + assetManager.load("toybox_albedo.png", Texture::class.java, linearMipped) + assetManager.load("toybox_normal.png", Texture::class.java, linearMipped) + assetManager.load("toybox_displace.png", Texture::class.java, linearMipped) } } diff --git a/src/main/resources/cobblestone_bump.png b/src/main/resources/cobblestone_bump.png new file mode 100644 index 0000000..17346ff Binary files /dev/null and b/src/main/resources/cobblestone_bump.png differ diff --git a/src/main/resources/lit.frag.glsl b/src/main/resources/lit.frag.glsl index d1122e2..623c30d 100644 --- a/src/main/resources/lit.frag.glsl +++ b/src/main/resources/lit.frag.glsl @@ -13,7 +13,7 @@ precision mediump float; varying vec3 v_normal; #endif // normalFlag -#if defined(tangentFlag) && defined(binormalFlag) +#if (defined(tangentFlag) && defined(binormalFlag)) || (defined(bumpHeightFlag) && defined(bumpTextureFlag)) varying mat3 v_tbn; #endif // tangentFlag && bitangentFlag @@ -28,6 +28,10 @@ varying vec4 v_color; varying MEDP vec2 v_diffuseUV; uniform sampler2D u_diffuseTexture; #endif // diffuseTextureFlag +#ifdef bumpTextureFlag +varying MEDP vec2 v_bumpUV; +uniform sampler2D u_bumpTexture; +#endif // bumpTextureFlag #ifdef normalTextureFlag varying MEDP vec2 v_normalUV; uniform sampler2D u_normalTexture; @@ -60,6 +64,10 @@ uniform float u_shininess; const float u_shininess = 20.0; #endif // shininessFlag +#ifdef bumpHeightFlag +uniform float u_bumpHeight; +#endif // bumpHeightFlag + #if numDirectionalLights > 0 struct DirectionalLight { @@ -114,14 +122,30 @@ vec3 linearDecode(vec3 v) { return vec3(pow(v.r, 1.0 / 2.2), pow(v.g, 1.0 / 2.2) void main() { +#if defined(specularFlag) || (defined(bumpHeightFlag) && defined(bumpTextureFlag)) + vec3 eyeVec = normalize(u_cameraPosition.xyz - v_worldPosition.xyz); +#endif // specularFlag || (bumpHeightFlag && bumpTextureFlag) + +#if defined(bumpHeightFlag) && defined(bumpTextureFlag) + float bumpHeight = (1.0 - texture2D(u_bumpTexture, v_bumpUV).r) * u_bumpHeight; + vec3 tbnEyeVec = normalize(mat3( + -v_tbn[0][0], v_tbn[1][0], v_tbn[2][0], + -v_tbn[0][1], v_tbn[1][1], v_tbn[2][1], + -v_tbn[0][2], v_tbn[1][2], v_tbn[2][2] + ) * -eyeVec); + vec2 uvOffset = -tbnEyeVec.xy * bumpHeight; +#else // !(bumpHeightFlag && bumpTextureFlag) + vec2 uvOffset = vec2(0.0); +#endif // bumpHeightFlag && bumpTextureFlag + #if defined(diffuseTextureFlag) && defined(diffuseColorFlag) && defined(colorFlag) - vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV) * u_diffuseColor * v_color; + vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV + uvOffset) * u_diffuseColor * v_color; #elif defined(diffuseTextureFlag) && defined(diffuseColorFlag) - vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV) * u_diffuseColor; + vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV + uvOffset) * u_diffuseColor; #elif defined(diffuseTextureFlag) && defined(colorFlag) - vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV) * v_color; + vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV + uvOffset) * v_color; #elif defined(diffuseTextureFlag) - vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV); + vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV + uvOffset); #elif defined(diffuseColorFlag) && defined(colorFlag) vec4 diffuse = u_diffuseColor * v_color; #elif defined(diffuseColorFlag) @@ -136,7 +160,7 @@ void main() #ifdef lightingFlag #if defined(normalFlag) && defined(tangentFlag) && defined(binormalFlag) && defined(normalTextureFlag) - vec3 normal = vec3(2.0 * texture2D(u_normalTexture, v_normalUV).rgb - 1.0); + vec3 normal = vec3(2.0 * texture2D(u_normalTexture, v_normalUV + uvOffset).rgb - 1.0); normal = normalize(v_tbn * normal); #elif defined(normalFlag) vec3 normal = normalize(v_normal); @@ -149,7 +173,6 @@ void main() #endif // ambientFlag #ifdef specularFlag - vec3 eyeVec = normalize(u_cameraPosition.xyz - v_worldPosition.xyz); vec3 specAccum = vec3(0.0); #endif // specularFlag @@ -201,7 +224,7 @@ void main() vec3 fragment; #ifdef specularFlag #ifdef specularTextureFlag - vec3 specularColorTex = texture2D(u_specularTexture, v_specularUV).rgb; + vec3 specularColorTex = texture2D(u_specularTexture, v_specularUV + uvOffset).rgb; specularColorTex = linearEncode(specularColorTex); specAccum *= specularColorTex; #endif // specularTextureFlag diff --git a/src/main/resources/lit.vert.glsl b/src/main/resources/lit.vert.glsl index da9e34d..1ed18e7 100644 --- a/src/main/resources/lit.vert.glsl +++ b/src/main/resources/lit.vert.glsl @@ -7,7 +7,7 @@ uniform mat3 u_normalMatrix; varying vec3 v_normal; #endif // normalFlag -#if defined(tangentFlag) && defined(binormalFlag) +#if (defined(tangentFlag) && defined(binormalFlag)) || (defined(bumpHeightFlag) && defined(bumpTextureFlag)) attribute vec3 a_tangent; attribute vec3 a_binormal; varying mat3 v_tbn; @@ -35,6 +35,11 @@ uniform vec4 u_diffuseUVTransform; varying vec2 v_diffuseUV; #endif // diffuseTextureFlag +#ifdef bumpTextureFlag +uniform vec4 u_bumpUVTransform; +varying vec2 v_bumpUV; +#endif // bumpTextureFlag + #ifdef normalTextureFlag uniform vec4 u_normalUVTransform; varying vec2 v_normalUV; @@ -104,6 +109,10 @@ void main() v_diffuseUV = u_diffuseUVTransform.xy + a_texCoord0 * u_diffuseUVTransform.zw; #endif // diffuseTextureFlag +#ifdef bumpTextureFlag + v_bumpUV = u_bumpUVTransform.xy + a_texCoord0 * u_bumpUVTransform.zw; +#endif // bumpTextureFlag + #ifdef normalTextureFlag v_normalUV = u_normalUVTransform.xy + a_texCoord0 * u_normalUVTransform.zw; #endif // normalTextureFlag diff --git a/src/main/resources/toybox.g3db b/src/main/resources/toybox.g3db new file mode 100644 index 0000000..f6f63de Binary files /dev/null and b/src/main/resources/toybox.g3db differ diff --git a/src/main/resources/toybox_albedo.png b/src/main/resources/toybox_albedo.png new file mode 100644 index 0000000..c785f41 Binary files /dev/null and b/src/main/resources/toybox_albedo.png differ diff --git a/src/main/resources/toybox_displace.png b/src/main/resources/toybox_displace.png new file mode 100644 index 0000000..e252cab Binary files /dev/null and b/src/main/resources/toybox_displace.png differ diff --git a/src/main/resources/toybox_normal.png b/src/main/resources/toybox_normal.png new file mode 100644 index 0000000..1a55f16 Binary files /dev/null and b/src/main/resources/toybox_normal.png differ