implemented fragment shader parallax occlusion mapping & add some assets to test it

This commit is contained in:
2023-08-21 02:56:51 +10:00
parent 3020ea8a08
commit 73b58eb3e0
12 changed files with 156 additions and 39 deletions

View File

@ -3,6 +3,9 @@ package gay.pizza.CavesOfJolk
import com.badlogic.gdx.graphics.g3d.Attributes import com.badlogic.gdx.graphics.g3d.Attributes
import com.badlogic.gdx.graphics.g3d.Renderable import com.badlogic.gdx.graphics.g3d.Renderable
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute 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 import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader
class CustomDefaultShader(renderable: Renderable, config: Config): class CustomDefaultShader(renderable: Renderable, config: Config):
@ -18,6 +21,13 @@ class CustomDefaultShader(renderable: Renderable, config: Config):
renderable.environment.let { attribs.set(it) } renderable.environment.let { attribs.set(it) }
renderable.material.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)) if (attribs.has(ColorAttribute.Fog))
{ {
prefix += "#define fog${ prefix += "#define fog${
@ -50,6 +60,41 @@ class CustomDefaultShader(renderable: Renderable, config: Config):
val fogNear = Uniform("u_fogNear") val fogNear = Uniform("u_fogNear")
val fogFar = Uniform("u_fogFar") val fogFar = Uniform("u_fogFar")
val fogDensity = Uniform("u_fogDensity") 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_fogFar = register(Inputs.fogFar)
private val u_fogDensity = register(Inputs.fogDensity) 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?) override fun bindLights(renderable: Renderable?, attributes: Attributes?)
{ {
if (attributes == null) if (attributes == null)

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g3d.Renderable import com.badlogic.gdx.graphics.g3d.Renderable
import com.badlogic.gdx.graphics.g3d.Shader import com.badlogic.gdx.graphics.g3d.Shader
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute 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.shaders.DefaultShader
import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider
@ -29,6 +30,11 @@ class CustomDefaultShaderProvider(config: DefaultShader.Config): DefaultShaderPr
CustomFloatAttribute.FogDensity CustomFloatAttribute.FogDensity
if ((renderableMask and ColorAttribute.Fog == ColorAttribute.Fog) && (renderableMask and fogMask != 0L)) if ((renderableMask and ColorAttribute.Fog == ColorAttribute.Fog) && (renderableMask and fogMask != 0L))
return CustomDefaultShader(renderable, config) return CustomDefaultShader(renderable, config)
val bumpMask = CustomFloatAttribute.BumpHeight or TextureAttribute.Bump
if (renderableMask and bumpMask == bumpMask)
return CustomDefaultShader(renderable, config)
return super.createShader(renderable) return super.createShader(renderable)
} }
} }

View File

@ -17,5 +17,9 @@ class CustomFloatAttribute private constructor(type: Long, value: Float): FloatA
const val FogDensityAlias = "fogDensity" const val FogDensityAlias = "fogDensity"
val FogDensity = register(FogDensityAlias) val FogDensity = register(FogDensityAlias)
fun createFogDensity(value: Float) = CustomFloatAttribute(FogDensity, value) fun createFogDensity(value: Float) = CustomFloatAttribute(FogDensity, value)
const val BumpHeightAlias = "bumpHeight"
val BumpHeight = register(BumpHeightAlias)
fun createBumpHeight(value: Float) = CustomFloatAttribute(BumpHeight, value)
} }
} }

View File

@ -22,10 +22,10 @@ import ktx.math.times
class Game: ApplicationAdapter() class Game: ApplicationAdapter()
{ {
private lateinit var texJolk: Texture
private lateinit var fntComic: BitmapFont private lateinit var fntComic: BitmapFont
private lateinit var cube: Model private lateinit var cube: Model
private lateinit var floor: Model private lateinit var floor: Model
private lateinit var toybox: Model
private lateinit var spriteBatch: SpriteBatch private lateinit var spriteBatch: SpriteBatch
private lateinit var modelBatch: ModelBatch private lateinit var modelBatch: ModelBatch
@ -41,23 +41,17 @@ class Game: ApplicationAdapter()
private lateinit var suzanneInstance: ModelInstance private lateinit var suzanneInstance: ModelInstance
private lateinit var rockBatch: ModelCache private lateinit var rockBatch: ModelCache
private lateinit var knux: ModelInstance 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() ModelBuilder().apply {
val size = 2.0f val attribs =
val material = Material( VertexAttributes.Usage.Position or
ColorAttribute.createDiffuse(XnaColor.White), VertexAttributes.Usage.TextureCoordinates or
TextureAttribute(TextureAttribute.Diffuse, VertexAttributes.Usage.Normal
TextureDescriptor(texture, return createBox(size, size, size, material, attribs.toLong())
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())
} }
private fun makeFloor(size: Float): Model private fun makeFloor(size: Float): Model
@ -103,8 +97,9 @@ class Game: ApplicationAdapter()
shininess = 65.0f shininess = 65.0f
textures = Array() textures = Array()
textures.add( textures.add(
modelTexture(ModelTexture.USAGE_DIFFUSE, "cobblestone.png"), modelTexture(ModelTexture.USAGE_DIFFUSE, "cobblestone.png"),
modelTexture(ModelTexture.USAGE_NORMAL, "cobblestone_normal.png"), modelTexture(ModelTexture.USAGE_NORMAL, "cobblestone_normal.png"),
modelTexture(ModelTexture.USAGE_BUMP, "cobblestone_bump.png"),
modelTexture(ModelTexture.USAGE_SPECULAR, "cobblestone_specular.png")) modelTexture(ModelTexture.USAGE_SPECULAR, "cobblestone_specular.png"))
}) })
nodes.add(ModelNode().apply { nodes.add(ModelNode().apply {
@ -115,7 +110,9 @@ class Game: ApplicationAdapter()
materialId = "floormat" materialId = "floormat"
}) })
}) })
}, AssetTextureProvider(assetManager)) }, AssetTextureProvider(assetManager)).apply {
materials[0].set(CustomFloatAttribute.createBumpHeight(0.0075f))
}
} }
override fun create() override fun create()
@ -123,11 +120,20 @@ class Game: ApplicationAdapter()
Resources.instance.loadAssets() Resources.instance.loadAssets()
assetManager.finishLoading() assetManager.finishLoading()
texJolk = assetManager.get("jolkmeup.jpg")
fntComic = assetManager.get("Comic Sans MS.ttf") fntComic = assetManager.get("Comic Sans MS.ttf")
cube = makeCube(texJolk) cube = makeCube(2.0f, Material(
var joeMany = 56.0f 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) floor = makeFloor(joeMany)
spriteBatch = SpriteBatch() spriteBatch = SpriteBatch()
@ -190,6 +196,7 @@ class Game: ApplicationAdapter()
suzanneInstance.transform = Matrix4().translate(3.0f, 1.0f, -3.5f) suzanneInstance.transform = Matrix4().translate(3.0f, 1.0f, -3.5f)
knux = ModelInstance(assetManager.get("knux.g3db", Model::class.java)) knux = ModelInstance(assetManager.get("knux.g3db", Model::class.java))
toyboxInstance = ModelInstance(toybox)
} }
override fun resize(width: Int, height: Int) override fun resize(width: Int, height: Int)
@ -247,12 +254,19 @@ class Game: ApplicationAdapter()
knux.transform.rotate(Quaternion().slerp(rand.nextQuaternion(), deltaTime)) knux.transform.rotate(Quaternion().slerp(rand.nextQuaternion(), deltaTime))
knux.transform.translate(knux.transform * Util.forward * 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.begin(colin.camera)
modelBatch.render(floorInstance, env) modelBatch.render(floorInstance, env)
modelBatch.render(rockBatch, env) modelBatch.render(rockBatch, env)
modelBatch.render(cubeInstance, env) modelBatch.render(cubeInstance, env)
modelBatch.render(suzanneInstance, env) modelBatch.render(suzanneInstance, env)
modelBatch.render(knux, env) modelBatch.render(knux, env)
modelBatch.render(toyboxInstance, env)
modelBatch.end() modelBatch.end()
spriteBatch.begin() spriteBatch.begin()

View File

@ -31,18 +31,25 @@ class Resources private constructor()
assetManager.setLoader(BitmapFont::class.java, ".ttf", FreetypeFontLoader(resolver)) assetManager.setLoader(BitmapFont::class.java, ".ttf", FreetypeFontLoader(resolver))
} }
val linearMipped = TextureLoader.TextureParameter().apply { val linearMipped = TextureLoader.TextureParameter().apply {
minFilter = Texture.TextureFilter.MipMapLinearLinear minFilter = Texture.TextureFilter.MipMapLinearLinear
magFilter = Texture.TextureFilter.Linear magFilter = Texture.TextureFilter.Linear
wrapU = Texture.TextureWrap.Repeat wrapU = Texture.TextureWrap.Repeat
wrapV = Texture.TextureWrap.Repeat wrapV = Texture.TextureWrap.Repeat
genMipMaps = true 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() fun loadAssets()
{ {
assetManager.load("colin.png", Texture::class.java) 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.loadFont("Comic Sans MS.ttf", 20)
assetManager.load("suzanne.g3db", Model::class.java) assetManager.load("suzanne.g3db", Model::class.java)
assetManager.load("nut.wav", Sound::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("cobblestone_specular.png", Texture::class.java, linearMipped)
assetManager.load("rock.g3db", Model::class.java) assetManager.load("rock.g3db", Model::class.java)
assetManager.load("knux.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)
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

View File

@ -13,7 +13,7 @@ precision mediump float;
varying vec3 v_normal; varying vec3 v_normal;
#endif // normalFlag #endif // normalFlag
#if defined(tangentFlag) && defined(binormalFlag) #if (defined(tangentFlag) && defined(binormalFlag)) || (defined(bumpHeightFlag) && defined(bumpTextureFlag))
varying mat3 v_tbn; varying mat3 v_tbn;
#endif // tangentFlag && bitangentFlag #endif // tangentFlag && bitangentFlag
@ -28,6 +28,10 @@ varying vec4 v_color;
varying MEDP vec2 v_diffuseUV; varying MEDP vec2 v_diffuseUV;
uniform sampler2D u_diffuseTexture; uniform sampler2D u_diffuseTexture;
#endif // diffuseTextureFlag #endif // diffuseTextureFlag
#ifdef bumpTextureFlag
varying MEDP vec2 v_bumpUV;
uniform sampler2D u_bumpTexture;
#endif // bumpTextureFlag
#ifdef normalTextureFlag #ifdef normalTextureFlag
varying MEDP vec2 v_normalUV; varying MEDP vec2 v_normalUV;
uniform sampler2D u_normalTexture; uniform sampler2D u_normalTexture;
@ -60,6 +64,10 @@ uniform float u_shininess;
const float u_shininess = 20.0; const float u_shininess = 20.0;
#endif // shininessFlag #endif // shininessFlag
#ifdef bumpHeightFlag
uniform float u_bumpHeight;
#endif // bumpHeightFlag
#if numDirectionalLights > 0 #if numDirectionalLights > 0
struct DirectionalLight 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() 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) #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) #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) #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) #elif defined(diffuseTextureFlag)
vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV); vec4 diffuse = texture2D(u_diffuseTexture, v_diffuseUV + uvOffset);
#elif defined(diffuseColorFlag) && defined(colorFlag) #elif defined(diffuseColorFlag) && defined(colorFlag)
vec4 diffuse = u_diffuseColor * v_color; vec4 diffuse = u_diffuseColor * v_color;
#elif defined(diffuseColorFlag) #elif defined(diffuseColorFlag)
@ -136,7 +160,7 @@ void main()
#ifdef lightingFlag #ifdef lightingFlag
#if defined(normalFlag) && defined(tangentFlag) && defined(binormalFlag) && defined(normalTextureFlag) #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); normal = normalize(v_tbn * normal);
#elif defined(normalFlag) #elif defined(normalFlag)
vec3 normal = normalize(v_normal); vec3 normal = normalize(v_normal);
@ -149,7 +173,6 @@ void main()
#endif // ambientFlag #endif // ambientFlag
#ifdef specularFlag #ifdef specularFlag
vec3 eyeVec = normalize(u_cameraPosition.xyz - v_worldPosition.xyz);
vec3 specAccum = vec3(0.0); vec3 specAccum = vec3(0.0);
#endif // specularFlag #endif // specularFlag
@ -201,7 +224,7 @@ void main()
vec3 fragment; vec3 fragment;
#ifdef specularFlag #ifdef specularFlag
#ifdef specularTextureFlag #ifdef specularTextureFlag
vec3 specularColorTex = texture2D(u_specularTexture, v_specularUV).rgb; vec3 specularColorTex = texture2D(u_specularTexture, v_specularUV + uvOffset).rgb;
specularColorTex = linearEncode(specularColorTex); specularColorTex = linearEncode(specularColorTex);
specAccum *= specularColorTex; specAccum *= specularColorTex;
#endif // specularTextureFlag #endif // specularTextureFlag

View File

@ -7,7 +7,7 @@ uniform mat3 u_normalMatrix;
varying vec3 v_normal; varying vec3 v_normal;
#endif // normalFlag #endif // normalFlag
#if defined(tangentFlag) && defined(binormalFlag) #if (defined(tangentFlag) && defined(binormalFlag)) || (defined(bumpHeightFlag) && defined(bumpTextureFlag))
attribute vec3 a_tangent; attribute vec3 a_tangent;
attribute vec3 a_binormal; attribute vec3 a_binormal;
varying mat3 v_tbn; varying mat3 v_tbn;
@ -35,6 +35,11 @@ uniform vec4 u_diffuseUVTransform;
varying vec2 v_diffuseUV; varying vec2 v_diffuseUV;
#endif // diffuseTextureFlag #endif // diffuseTextureFlag
#ifdef bumpTextureFlag
uniform vec4 u_bumpUVTransform;
varying vec2 v_bumpUV;
#endif // bumpTextureFlag
#ifdef normalTextureFlag #ifdef normalTextureFlag
uniform vec4 u_normalUVTransform; uniform vec4 u_normalUVTransform;
varying vec2 v_normalUV; varying vec2 v_normalUV;
@ -104,6 +109,10 @@ void main()
v_diffuseUV = u_diffuseUVTransform.xy + a_texCoord0 * u_diffuseUVTransform.zw; v_diffuseUV = u_diffuseUVTransform.xy + a_texCoord0 * u_diffuseUVTransform.zw;
#endif // diffuseTextureFlag #endif // diffuseTextureFlag
#ifdef bumpTextureFlag
v_bumpUV = u_bumpUVTransform.xy + a_texCoord0 * u_bumpUVTransform.zw;
#endif // bumpTextureFlag
#ifdef normalTextureFlag #ifdef normalTextureFlag
v_normalUV = u_normalUVTransform.xy + a_texCoord0 * u_normalUVTransform.zw; v_normalUV = u_normalUVTransform.xy + a_texCoord0 * u_normalUVTransform.zw;
#endif // normalTextureFlag #endif // normalTextureFlag

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB