diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Camera3D.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Camera3D.kt index 8ed8c8e..3f99eab 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Camera3D.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Camera3D.kt @@ -75,6 +75,7 @@ class Transform3D { private val _rotation = Quaternion() private val _scale = Scale3D(1, 1, 1) private fun updateTRS() { + transformDirty = false matrix.getTRS(_translation, rotation, _scale) transformDirty = false } @@ -93,8 +94,8 @@ class Transform3D { } fun setMatrix(mat: Matrix3D) { - this.matrix.copyFrom(mat) transformDirty = true + this.matrix.copyFrom(mat) } @PublishedApi diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Shaders3D.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Shaders3D.kt index 30da6bb..8becfd6 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Shaders3D.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Shaders3D.kt @@ -11,6 +11,7 @@ object Shaders3D { operator fun Operand.get(index: Operand) = Program.ArrayAccess(this, index) val u_Shiness = Uniform("u_shiness", VarType.Float1) + val u_AmbientColor = Uniform("u_ambientColor", VarType.Float4) val u_ProjMat = Uniform("u_ProjMat", VarType.Mat4) val u_ViewMat = Uniform("u_ViewMat", VarType.Mat4) val u_BindMat = Uniform("u_BindMat", VarType.Mat4) @@ -47,10 +48,9 @@ object Shaders3D { ) class LightAttributes(val id: Int) { - val sourcePos = Uniform("light${id}_pos", VarType.Float3) - val diffuse = Uniform("light${id}_diffuse", VarType.Float4) - val specular = Uniform("light${id}_specular", VarType.Float4) - val ambient = Uniform("light${id}_ambient", VarType.Float4) + val u_sourcePos = Uniform("light${id}_pos", VarType.Float3) + val u_color = Uniform("light${id}_color", VarType.Float4) + val u_attenuation = Uniform("light${id}_attenuation", VarType.Float3) } val lights = (0 until 4).map { LightAttributes(it) } @@ -63,13 +63,33 @@ object Shaders3D { val E = createTemp(VarType.Float3) val R = createTemp(VarType.Float3) - SET(L, normalize(light.sourcePos["xyz"] - v)) + val attenuation = createTemp(VarType.Float1) + val dist = createTemp(VarType.Float1) + val NdotL = createTemp(VarType.Float1) + val lightDir = createTemp(VarType.Float3) + + SET(L, normalize(light.u_sourcePos["xyz"] - v)) SET(E, normalize(-v)) // we are in Eye Coordinates, so EyePos is (0,0,0) SET(R, normalize(-reflect(L, N))) - SET(out["rgb"], out["rgb"] + light.ambient["rgb"]) - SET(out["rgb"], out["rgb"] + clamp(light.diffuse * max(dot(N, L), 0f.lit), 0f.lit, 1f.lit)["rgb"]) - SET(out["rgb"], out["rgb"] + clamp(light.specular * pow(max(dot(R, E), 0f.lit), 0.3f.lit * u_Shiness), 0f.lit, 1f.lit)["rgb"]) + val constantAttenuation = light.u_attenuation.x + val linearAttenuation = light.u_attenuation.y + val quadraticAttenuation = light.u_attenuation.z + SET(lightDir, light.u_sourcePos["xyz"] - v_Pos) + SET(dist, length(lightDir)) + //SET(dist, length(vec3(4f.lit, 1f.lit, 6f.lit) - vec3(0f.lit, 0f.lit, 0f.lit))) + + SET(attenuation, 1f.lit / (constantAttenuation + linearAttenuation * dist + quadraticAttenuation * dist * dist)) + //SET(attenuation, 1f.lit / (1f.lit + 0f.lit * dist + 0.00111109f.lit * dist * dist)) + //SET(attenuation, 0.9.lit) + SET(NdotL, max(dot(normalize(N), normalize(lightDir)), 0f.lit)) + + IF(NdotL ge 0f.lit) { + SET(out["rgb"], out["rgb"] + (light.u_color["rgb"] * NdotL + u_AmbientColor["rgb"]) * attenuation) + } + //SET(out["rgb"], out["rgb"] * attenuation) + //SET(out["rgb"], out["rgb"] + clamp(light.diffuse * max(dot(N, L), 0f.lit), 0f.lit, 1f.lit)["rgb"]) + //SET(out["rgb"], out["rgb"] + clamp(light.specular * pow(max(dot(R, E), 0f.lit), 0.3f.lit * u_Shiness), 0f.lit, 1f.lit)["rgb"]) } @ThreadLocal @@ -96,20 +116,30 @@ object Shaders3D { val skinMatrix = createTemp(VarType.Mat4) + val localPos = createTemp(VarType.Float4) + val localNorm = createTemp(VarType.Float4) + + SET(localPos, vec4(1f.lit)) + SET(localNorm, vec4(0f.lit)) + if (nweights == 0) { SET(skinMatrix, mat4Identity()) + SET(localPos, vec4(a_pos, 1f.lit)) + SET(localNorm, vec4(a_norm, 0f.lit)) } else { for (wIndex in 0 until nweights) { IF(getBoneIndex(wIndex) ge 0.lit) { - SET(skinMatrix, skinMatrix + (getBone(wIndex) * getWeight(wIndex))) + SET(skinMatrix, getBone(wIndex)) + SET(localPos, localPos + skinMatrix * vec4(a_pos, 1f.lit) * getWeight(wIndex)) + SET(localNorm, localNorm + skinMatrix * vec4(a_norm, 0f.lit) * getWeight(wIndex)) } } } SET(modelViewMat, u_ModMat * u_ViewMat) SET(normalMat, u_NormMat) - SET(v_Pos, vec3(modelViewMat * u_BindMat * skinMatrix * vec4(a_pos, 1f.lit))) - SET(v_Norm, vec3(normalMat * u_BindMat * skinMatrix * vec4(a_norm, 1f.lit))) + SET(v_Pos, vec3(modelViewMat * u_BindMat * localPos)) + SET(v_Norm, vec3(normalMat * u_BindMat * localNorm)) if (hasTexture) { SET(v_TexCoords, a_tex["xy"]) } diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Stage3D.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Stage3D.kt index 9233ee7..a74b8d1 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Stage3D.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/Stage3D.kt @@ -5,6 +5,7 @@ import com.soywiz.kds.iterators.* import com.soywiz.kmem.* import com.soywiz.korag.* import com.soywiz.korag.shader.* +import com.soywiz.korge.experimental.s3d.model.internal.* import com.soywiz.korge.render.* import com.soywiz.korge.view.* import com.soywiz.korim.bitmap.* @@ -19,32 +20,25 @@ class Views3D { fun Container3D.light(callback: Light3D.() -> Unit = {}) = Light3D().apply(callback).addTo(this) -class Light3D : View3D() { - var diffuseColor = Colors.WHITE - var specularColor = Colors.WHITE - var ambientColor = Colors.WHITE - var diffusePower = 1.0 - var specularPower = 0.2 - var ambientPower = 0.1 - var power = 1.0 - internal val tempArray1 = FloatArray(4) - internal val tempArray2 = FloatArray(4) - internal val tempArray3 = FloatArray(4) +open class Light3D( + var color: RGBA = Colors.WHITE, + var constantAttenuation: Double = 1.0, + var linearAttenuation: Double = 0.0, + var quadraticAttenuation: Double = 0.00111109 +) : View3D() { + internal val tempVec1 = Vector3D() + internal val tempVec2 = Vector3D() - //val diffuseColorPremult get() = diffuseColor.withAd(power).premultiplied - //val specularColorPremult get() = specularColor.withAd(power).premultiplied - //val ambientColorPremult get() = ambientColor.withAd(power).premultiplied - - fun diffuseColor(color: RGBA): Light3D = this.apply { this.diffuseColor = color } - fun specularColor(color: RGBA): Light3D = this.apply { this.specularColor = color } - fun ambientColor(color: RGBA): Light3D = this.apply { this.ambientColor = color } - - fun colors(ambient: RGBA, diffuse: RGBA = ambient, specular: RGBA = diffuse) = this.diffuseColor(diffuse).specularColor(specular).ambientColor(ambient) - fun power(globalPower: Double = 1.0, diffusePower: Double = 1.0, specularPower: Double = 0.2, ambientPower: Double = 0.1) = apply { - this.power = globalPower - this.diffusePower = diffusePower - this.specularPower = specularPower - this.ambientPower = ambientPower + fun setTo( + color: RGBA = Colors.WHITE, + constantAttenuation: Double = 1.0, + linearAttenuation: Double = 0.0, + quadraticAttenuation: Double = 0.00111109 + ) = this.apply { + this.color = color + this.constantAttenuation = constantAttenuation + this.linearAttenuation = linearAttenuation + this.quadraticAttenuation = quadraticAttenuation } override fun render(ctx: RenderContext3D) { @@ -53,7 +47,10 @@ class Light3D : View3D() { class Stage3D(val views: Views3D) : Container3D() { lateinit var view: Stage3DView - var camera = Camera3D.Perspective().apply { + //var ambientColor: RGBA = Colors.WHITE + var ambientColor: RGBA = Colors.BLACK // No ambient light + var ambientPower: Double = 0.3 + var camera: Camera3D = Camera3D.Perspective().apply { positionLookingAt(0, 1, -10, 0, 0, 0) } } @@ -72,6 +69,7 @@ class Stage3DView(val stage3D: Stage3D) : View() { ctx3D.rctx = ctx ctx3D.projMat.copyFrom(stage3D.camera.getProjMatrix(ctx.ag.backWidth.toDouble(), ctx.ag.backHeight.toDouble())) ctx3D.cameraMat.copyFrom(stage3D.camera.localTransform.matrix) + ctx3D.ambientColor.setToColorPremultiplied(stage3D.ambientColor).scale(stage3D.ambientPower) ctx3D.cameraMatInv.invert(stage3D.camera.localTransform.matrix) ctx3D.projCameraMat.multiply(ctx3D.projMat, ctx3D.cameraMatInv) ctx3D.lights.clear() @@ -84,6 +82,8 @@ class Stage3DView(val stage3D: Stage3D) : View() { } } + + fun View3D?.foreachDescendant(handler: (View3D) -> Unit) { if (this != null) { handler(this) @@ -108,9 +108,11 @@ class RenderContext3D() { val cameraMat: Matrix3D = Matrix3D() val cameraMatInv: Matrix3D = Matrix3D() val dynamicVertexBufferPool = Pool { ag.createVertexBuffer() } + val ambientColor: Vector3D = Vector3D() } abstract class View3D { + var id: String? = null var name: String? = null val localTransform = Transform3D() @@ -140,6 +142,18 @@ abstract class View3D { open class Container3D : View3D() { val children = arrayListOf() + fun removeChild(child: View3D) { + children.remove(child) + } + + fun addChild(child: View3D) { + child.removeFromParent() + children += child + child.parent = this + } + + operator fun plusAssign(child: View3D) = addChild(child) + override fun render(ctx: RenderContext3D) { children.fastForEach { it.render(ctx) @@ -147,12 +161,23 @@ open class Container3D : View3D() { } } +fun View3D.removeFromParent() { + parent?.removeChild(this) + parent = null +} + inline fun View3D?.findByType() = sequence { for (it in descendants()) { if (it is T) yield(it) } } +inline fun View3D?.findByTypeWithName(name: String) = sequence { + for (it in descendants()) { + if (it is T && it.name == name) yield(it) + } +} + fun View3D?.descendants(): Sequence = sequence { val view = this@descendants ?: return@sequence yield(view) @@ -198,9 +223,7 @@ inline fun T.positionLookingAt(px: Number, py: Number, pz: Number, } fun T.addTo(container: Container3D) = this.apply { - this.parent?.children?.remove(this) - container.children += this - this.parent = container + container.addChild(this) } data class Bone3D( @@ -214,6 +237,15 @@ data class Skeleton3D(val bindShapeMatrix: Matrix3D, val bones: List) { } class Mesh3D constructor(val data: FloatArray, val layout: VertexLayout, val program: Program?, val drawType: AG.DrawType, val maxWeights: Int = 0) { + val fbuffer by lazy { + FBuffer.alloc(data.size * 4).apply { + setAlignedArrayFloat32(0, this@Mesh3D.data, 0, this@Mesh3D.data.size) + } + //FBuffer.wrap(MemBufferAlloc(data.size * 4)).apply { + // arraycopy(this@Mesh3D.data, 0, this@apply.mem, 0, this@Mesh3D.data.size) // Bug in kmem-js? + //} + } + var skeleton: Skeleton3D? = null var texture: Bitmap? = null @@ -309,7 +341,9 @@ open class ViewWithMesh3D(var mesh: Mesh3D) : View3D() { val ag = ctx.ag ctx.dynamicVertexBufferPool.alloc { vertexBuffer -> - vertexBuffer.upload(mesh.data) + //vertexBuffer.upload(mesh.data) + vertexBuffer.upload(mesh.fbuffer) + //tempMat2.invert() //tempMat3.multiply(ctx.cameraMatInv, this.localTransform.matrix) //tempMat3.multiply(ctx.cameraMatInv, Matrix3D().invert(this.localTransform.matrix)) @@ -356,35 +390,15 @@ open class ViewWithMesh3D(var mesh: Mesh3D) : View3D() { this[u_BindMat] = ctx.bindMat4.identity() } + this[u_AmbientColor] = ctx.ambientColor + ctx.lights.fastForEachWithIndex { index, light: Light3D -> - this[lights[index].sourcePos] = light.localTransform.translation.data - val diffuse = light.diffuseColor - val specular = light.specularColor - val ambient = light.ambientColor - - //println(light.diffuseColor.withAd(1.0)) - //println(diffuse) - //println(specular) - //println(ambient) - - this[lights[index].diffuse] = light.tempArray1.apply { - val scale = (light.power * light.diffusePower).toFloat() - this[0] = (diffuse.rf * scale) - this[1] = (diffuse.gf * scale) - this[2] = (diffuse.bf * scale) - } - this[lights[index].specular] = light.tempArray2.apply { - val scale = (light.power * light.specularPower).toFloat() - this[0] = (specular.rf * scale) - this[1] = (specular.gf * scale) - this[2] = (specular.bf * scale) - } - this[lights[index].ambient] = light.tempArray3.apply { - val scale = (light.power * light.ambientPower).toFloat() - this[0] = (ambient.rf * scale) - this[1] = (ambient.gf * scale) - this[2] = (ambient.bf * scale) - } + val lightColor = light.color + this[lights[index].u_sourcePos] = light.localTransform.translation + //println("light.localTransform.translation:${light.localTransform.translation}") + this[lights[index].u_color] = light.tempVec1.setTo(lightColor.rf, lightColor.gf, lightColor.bf, 1f) + //println(light.tempVec1.setTo(lightColor.rf, lightColor.gf, lightColor.bf, 1f)) + this[lights[index].u_attenuation] = light.tempVec2.setTo(light.constantAttenuation, light.linearAttenuation, light.quadraticAttenuation) } }, renderState = rs diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Collada.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Collada.kt index 7e08f62..b0898e1 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Collada.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Collada.kt @@ -6,6 +6,7 @@ import com.soywiz.korag.* import com.soywiz.korag.shader.* import com.soywiz.korge.experimental.s3d.* import com.soywiz.korge.experimental.s3d.model.internal.* +import com.soywiz.korim.color.* import com.soywiz.korio.file.* import com.soywiz.korio.serialization.xml.* import com.soywiz.korio.util.* @@ -52,9 +53,9 @@ class ColladaParser { for (skin in skins) { library.skins[skin.controllerId] = skin } + generateGeometries(geometries, skins) parseVisualScenes(xml) parseScene(xml) - generateGeometries(geometries, skins) } fun Library3D.generateGeometries(geometries: List, skins: List) { @@ -216,8 +217,9 @@ class ColladaParser { //println(combinedData.toString()) - geometryDefs[geom.id] = Library3D.RawGeometryDef( + geometryDefs[geom.id] = Library3D.GeometryDef( Mesh3D( + //combinedData.toFloatArray().toFBuffer(), combinedData.toFloatArray(), VertexLayout(buildList { add(Shaders3D.a_pos) @@ -247,6 +249,13 @@ class ColladaParser { fun Library3D.parseScene(xml: Xml) { val scene = xml["scene"] + for (instance_visual_scene in scene["instance_visual_scene"]) { + val id = instance_visual_scene.str("url").trim('#') + val scene = scenes[id] + if (scene != null) { + mainScene.children += scene + } + } } fun parseControllers(xml: Xml): List { @@ -322,9 +331,27 @@ class ColladaParser { fun Library3D.parseLights(xml: Xml) { for (light in xml["library_lights"]["light"]) { - val id = light.getString("id") - val name = light.getString("name") + var lightDef: Library3D.LightDef? = null + val id = light.str("id") + val name = light.str("name") log { "Light id=$id, name=$name" } + for (technique in light["technique_common"].allNodeChildren) { + when (technique.nameLC) { + "point" -> { + val color = technique["color"].firstOrNull()?.text?.reader()?.readVector3D() ?: Vector3D(1, 1, 1) + val constant_attenuation = technique["constant_attenuation"].firstOrNull()?.text?.toDoubleOrNull() ?: 1.0 + val linear_attenuation = technique["linear_attenuation"].firstOrNull()?.text?.toDoubleOrNull() ?: 0.0 + val quadratic_attenuation = technique["quadratic_attenuation"].firstOrNull()?.text?.toDoubleOrNull() ?: 0.00111109 + lightDef = Library3D.PointLightDef(RGBA.float(color.x, color.y, color.z, 1f), constant_attenuation, linear_attenuation, quadratic_attenuation) + } + else -> { + println("WARNING: Unsupported light.technique_common.${technique.nameLC}") + } + } + } + if (lightDef != null) { + lightDefs[id] = lightDef + } } } @@ -419,35 +446,109 @@ class ColladaParser { fun Library3D.parseVisualScenes(xml: Xml) { for (vscene in xml["library_visual_scenes"]["visual_scene"]) { - val id = vscene.getString("id") - val name = vscene.getString("name") - log { "VisualScene id=$id, name=$name" } + val scene = Library3D.Scene3D() + scene.id = vscene.str("id") + scene.name = vscene.str("name") for (node in vscene["node"]) { - val id = node.getString("id") - val name = node.getString("name") - var transform = Matrix3D() - node.allNodeChildren.fastForEach { v -> - when (v.nameLC) { - "matrix" -> { - val sid = v.getString("sid") - val matrix = v.text.reader().readMatrix3D() - when (sid) { - "transform" -> { - transform = matrix - } - else -> { - log { " Unhandled matrix sid=$sid" } - } - } - } - else -> { - log { " Unhandled ${v.nameLC}" } - } + val instance = parseVisualSceneNode(node) + scene.children += instance + } + scenes[scene.id] = scene + } + } + + fun Library3D.parseVisualSceneNode(node: Xml): Library3D.Instance3D { + val instance = Library3D.Instance3D() + var location: Vector3D? = null + var scale: Vector3D? = null + var rotationX: Vector3D? = null + var rotationY: Vector3D? = null + var rotationZ: Vector3D? = null + + instance.id = node.str("id") + instance.name = node.str("name") + instance.type = node.str("type") + + for (child in node.allNodeChildren) { + when (child.nameLC) { + "matrix" -> { + val sid = child.str("sid") + when (sid) { + "transform" -> instance.transform.copyFrom(child.text.reader().readMatrix3D()) + else -> println("WARNING: Unsupported node.matrix.sid=$sid") } } - log { " Node id=$id, name=$name, transform=$transform" } + "translate" -> { + val sid = child.str("sid") + when (sid) { + "location" -> location = child.text.reader().readVector3D() + else -> println("WARNING: Unsupported node.translate.sid=$sid") + } + } + "rotate" -> { + val sid = child.str("sid") + when (sid) { + "rotationX" -> rotationX = child.text.reader().readVector3D() + "rotationY" -> rotationY = child.text.reader().readVector3D() + "rotationZ" -> rotationZ = child.text.reader().readVector3D() + else -> println("WARNING: Unsupported node.rotate.sid=$sid") + } + } + "scale" -> { + val sid = child.str("sid") + when (sid) { + "scale" -> scale = child.text.reader().readVector3D() + else -> println("WARNING: Unsupported node.scale.sid=$sid") + } + } + "instance_camera" -> { + val cameraId = child.str("url").trim('#') + instance.def = cameraDefs[cameraId] + } + "instance_light" -> { + val lightId = child.str("url").trim('#') + instance.def = lightDefs[lightId] + } + "instance_geometry" -> { + val geometryId = child.str("url").trim('#') + val geometryName = child.str("name") + instance.def = geometryDefs[geometryId] + } + "node" -> { + val childInstance = parseVisualSceneNode(child) + instance.children.add(childInstance) + } + "extra" -> { + } + else -> { + println("WARNING: Unsupported node.${child.nameLC}") + } } } + if (location != null || scale != null || rotationX != null || rotationY != null || rotationZ != null) { + val trns = location ?: Vector3D(0, 0, 0, 1) + val scl = scale ?: Vector3D(1, 1, 1) + val rotX = rotationX ?: Vector3D(1, 0, 0, 0) + val rotY = rotationY ?: Vector3D(0, 1, 0, 0) + val rotZ = rotationZ ?: Vector3D(0, 0, 1, 0) + rotationVectorToEulerRotation(rotX) + + instance.transform.setTRS( + trns, + Quaternion().setTo(combine(rotationVectorToEulerRotation(rotX), rotationVectorToEulerRotation(rotY), rotationVectorToEulerRotation(rotZ))), + scl + ) + } + return instance + } + + private fun combine(a: EulerRotation, b: EulerRotation, c: EulerRotation, out: EulerRotation = EulerRotation()): EulerRotation { + return out.setTo(a.x + b.x + c.x, a.y + b.y + c.y, a.z + b.z + c.z) + } + + private fun rotationVectorToEulerRotation(vec: Vector3D, out: EulerRotation = EulerRotation()): EulerRotation { + val degrees = vec.w.degrees + return out.setTo(degrees * vec.x, degrees * vec.y, degrees * vec.z) } val sourceArrayParams = FastStringMap() @@ -537,3 +638,5 @@ class ColladaParser { @Deprecated("", ReplaceWith("log { str }", "com.soywiz.korge.experimental.s3d.model.ColladaParser.log")) inline fun log(str: String) = log { str } } + +private val Iterable.allNodeChildren: Iterable get() = this.flatMap(Xml::allNodeChildren) diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Library3D.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Library3D.kt index 73bb81f..939a43b 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Library3D.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/Library3D.kt @@ -2,31 +2,101 @@ package com.soywiz.korge.experimental.s3d.model import com.soywiz.kds.* import com.soywiz.korge.experimental.s3d.* +import com.soywiz.korim.color.* import com.soywiz.korma.geom.* data class Library3D( val cameraDefs: FastStringMap = FastStringMap(), + val lightDefs: FastStringMap = FastStringMap(), + val materialDefs: FastStringMap = FastStringMap(), val geometryDefs: FastStringMap = FastStringMap(), val skins: FastStringMap = FastStringMap() ) { val library = this - open class CameraDef + val mainScene = Scene3D().apply { + id = "MainScene" + name = "MainScene" + } + var scenes = FastStringMap() + + open class Instance3D { + val transform = Matrix3D() + var def: Def? = null + val children = arrayListOf() + var id: String = "" + var name: String = "" + var type: String = "" + } + + open class Scene3D : Instance3D() { + } + + open class Def + + open class ObjectDef : Def() + + open class MaterialDef : Def() + + open class LightDef : ObjectDef() + + open class CameraDef : ObjectDef() data class PerspectiveCameraDef(val xfov: Angle, val zmin: Double, val zmax: Double) : CameraDef() - open class GeometryDef - //data class RawGeometryDef(val data: FloatArray, val hasPos: Boolean, val hasNormal: Boolean, val hasUV: Boolean) : GeometryDef() - data class RawGeometryDef( + data class GeometryDef( val mesh: Mesh3D, val skin: SkinDef? = null - ) : GeometryDef() + ) : ObjectDef() - data class BoneDef(val name: String, val pose: Matrix3D) { + data class BoneDef(val name: String, val pose: Matrix3D) : Def() { fun toBone() = Bone3D(name, pose.clone()) } data class SkinDef( val bindShapeMatrix: Matrix3D, val bones: List - ) + ) : Def() + + + class PointLightDef( + val color: RGBA, + val constantAttenuation: Double, + val linearAttenuation: Double, + val quadraticAttenuation: Double + ) : LightDef() +} + +fun Library3D.Instance3D.instantiate(): View3D { + val def = this.def + val view: View3D = when (def) { + null -> { + Container3D().also { container -> + for (child in children) { + container.addChild(child.instantiate()) + } + } + } + is Library3D.GeometryDef -> { + ViewWithMesh3D(def.mesh) + } + is Library3D.PerspectiveCameraDef -> { + Camera3D.Perspective(def.xfov, def.zmin, def.zmax) + } + is Library3D.PointLightDef -> { + Light3D(def.color, def.constantAttenuation, def.linearAttenuation, def.quadraticAttenuation) + } + else -> TODO("def=$def") + } + view.id = this.id + view.name = this.name + //view.localTransform.setMatrix(this.transform.clone().transpose()) + view.localTransform.setMatrix(this.transform) + if (def is Library3D.PointLightDef) { + println(view.localTransform.matrix) + println(view.localTransform.translation) + println(view.localTransform.rotation) + println(view.localTransform.scale) + println("def: $def") + } + return view } diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/RGBAExt.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/RGBAExt.kt new file mode 100644 index 0000000..6042232 --- /dev/null +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/RGBAExt.kt @@ -0,0 +1,18 @@ +package com.soywiz.korge.experimental.s3d.model.internal + +import com.soywiz.korim.color.* +import com.soywiz.korma.geom.* + +internal fun Vector3D.setToColorPremultiplied(col: RGBA): Vector3D = this.apply { col.toPremultipliedVector3D(this) } +internal fun Vector3D.setToColor(col: RGBA): Vector3D = this.apply { col.toPremultipliedVector3D(this) } + +internal fun RGBA.toPremultipliedVector3D(out: Vector3D = Vector3D()): Vector3D = out.setTo( + rf * af, gf * af, bf * af, 1f +) + +internal fun RGBA.toVector3D(out: Vector3D = Vector3D()): Vector3D = out.setTo( + rf, gf, bf, af +) + +fun Vector3D.scale(scale: Float) = this.setTo(this.x * scale, this.y * scale, this.z * scale, this.w * scale) +inline fun Vector3D.scale(scale: Number) = scale(scale.toFloat()) diff --git a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/StrReaderExt.kt b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/StrReaderExt.kt index bbb1f0c..604bafb 100644 --- a/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/StrReaderExt.kt +++ b/sample-raw-3d/src/commonMain/kotlin/com.soywiz.korge.experimental.s3d/model/internal/StrReaderExt.kt @@ -41,10 +41,18 @@ internal fun StrReader.readInts(list: com.soywiz.kds.IntArrayList = com.soywiz.k return list } +internal fun StrReader.readVector3D(): com.soywiz.korma.geom.Vector3D { + val f = readFloats(com.soywiz.kds.FloatArrayList()) + return when { + f.size == 4 -> com.soywiz.korma.geom.Vector3D(f[0], f[1], f[2], f[3]) + else -> com.soywiz.korma.geom.Vector3D(f[0], f[1], f[2]) + } +} + internal fun StrReader.readMatrix3D(): com.soywiz.korma.geom.Matrix3D { val f = readFloats(com.soywiz.kds.FloatArrayList()) if (f.size == 16) { - return com.soywiz.korma.geom.Matrix3D().setColumns( // This is correct + return com.soywiz.korma.geom.Matrix3D().setRows( f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10], f[11], diff --git a/sample-raw-3d/src/commonMain/kotlin/main.kt b/sample-raw-3d/src/commonMain/kotlin/main.kt index c23ecfe..e2fe2ae 100644 --- a/sample-raw-3d/src/commonMain/kotlin/main.kt +++ b/sample-raw-3d/src/commonMain/kotlin/main.kt @@ -5,7 +5,6 @@ import com.soywiz.korge.experimental.s3d.* import com.soywiz.korge.experimental.s3d.model.* import com.soywiz.korge.tween.* import com.soywiz.korge.view.* -import com.soywiz.korim.bitmap.* import com.soywiz.korim.color.* import com.soywiz.korim.format.* import com.soywiz.korio.* @@ -16,7 +15,8 @@ import com.soywiz.korma.interpolation.* import kotlin.jvm.* //suspend fun main(args: Array) = Demo3.main(args) -suspend fun main(args: Array) = Demo3.main() +//suspend fun main(args: Array) = Demo3.main() +suspend fun main(args: Array) = Demo1.main() object Demo1 { @JvmStatic @@ -70,8 +70,8 @@ object Demo2 { //delay(10.seconds) //println("delay") scene3D { - val light1 = light().position(0, 10, +10).diffuseColor(Colors.RED) - val light2 = light().position(10, 0, +10).diffuseColor(Colors.BLUE) + val light1 = light().position(0, 10, +10).setTo(Colors.RED) + val light2 = light().position(10, 0, +10).setTo(Colors.BLUE) launchImmediately { while (true) { @@ -87,7 +87,7 @@ object Demo2 { val library = resourcesVfs["monkey-smooth.dae"].readColladaLibrary() //val library = resourcesVfs["plane.dae"].readColladaLibrary() //val cubeGeom = library.geometryDefs["Cube-mesh"]!! as Library3D.RawGeometryDef - val cubeGeom = library.geometryDefs.values.first() as Library3D.RawGeometryDef + val cubeGeom = library.geometryDefs.values.first() as Library3D.GeometryDef val cube = mesh(cubeGeom.mesh).rotation(-90.degrees, 0.degrees, 0.degrees) println(library) /* @@ -128,7 +128,7 @@ object Demo3 { //delay(10.seconds) //println("delay") scene3D { - val light1 = light().position(0, 1, 1).colors(Colors.WHITE, Colors.WHITE, Colors.WHITE).power(1.0) + //val light1 = light().position(0, 1, 1).colors(Colors.WHITE, Colors.WHITE, Colors.WHITE).power(1.0) /* val light1 = light().position(0, 10, +10).colors(Colors.RED, Colors.RED, Colors.RED) val light2 = light().position(10, 0, +10).colors(Colors.BLUE, Colors.BLUE, Colors.BLUE) @@ -145,25 +145,36 @@ object Demo3 { //val library = resourcesVfs["scene.dae"].readColladaLibrary() //val library = resourcesVfs["cilinder.dae"].readColladaLibrary() + //val library = resourcesVfs["box_textured.dae"].readColladaLibrary() //val library = resourcesVfs["monkey.dae"].readColladaLibrary() - //val library = resourcesVfs["monkey-smooth.dae"].readColladaLibrary() + val library = resourcesVfs["monkey-smooth.dae"].readColladaLibrary() //val library = resourcesVfs["shape2.dae"].readColladaLibrary() - val library = resourcesVfs["skinning.dae"].readColladaLibrary() + //val library = resourcesVfs["skinning.dae"].readColladaLibrary() //val library = resourcesVfs["Fallera.dae"].readColladaLibrary() + //val library = resourcesVfs["model.dae"].readColladaLibrary() //val library = resourcesVfs["skinning_sample.dae"].readColladaLibrary() //val library = resourcesVfs["box_textured.dae"].readColladaLibrary() //val library = resourcesVfs["shape1.dae"].readColladaLibrary() //val library = resourcesVfs["plane.dae"].readColladaLibrary() //val cubeGeom = library.geometryDefs["Cube-mesh"]!! as Library3D.RawGeometryDef - val cubeGeom = library.geometryDefs.values.first() as Library3D.RawGeometryDef - val tex = resourcesVfs["korge.png"].readBitmapOptimized() + //val cubeGeom = library.geometryDefs.values.first() as Library3D.GeometryDef + //val tex = resourcesVfs["korge.png"].readBitmapOptimized() //val tex = resourcesVfs["Fallera.jpg"].readBitmapOptimized() + //val tex = resourcesVfs["diffuse.png"].readBitmapOptimized() //val cube = mesh(cubeGeom.mesh) - //val cube = mesh(cubeGeom.mesh).scale(0.02, 0.02, 0.02).rotation(z = 90.degrees) + //val cube = mesh(cubeGeom.mesh).scale(0.02, 0.02, 0.02).rotation(z = 90.degrees) // @TODO: Kotlin.JS BUG //val cube = mesh(cubeGeom.mesh).scale(0.02, 0.02, 0.02).rotation(0.degrees, 0.degrees, 90.degrees) //val cube = mesh(cubeGeom.mesh).rotation(y = 90.degrees) // @TODO: Kotlin.JS BUG - val cube = mesh(cubeGeom.mesh) - cube.mesh.texture = tex + //val cube = mesh(cubeGeom.mesh) + //cube.mesh.texture = tex + + val mainSceneView = library.mainScene.instantiate() + //ambientColor = Colors.RED + //ambientColor = Colors.WHITE + //ambientColor = Colors.WHITE + camera = mainSceneView.findByType().first() + this += mainSceneView + //this += box() //val cube = mesh(cubeGeom.mesh).scale(0.02, 0.02, 0.02) //val cube = mesh(cubeGeom.mesh).rotation(-90.degrees, 0.degrees, 0.degrees) @@ -174,6 +185,7 @@ object Demo3 { } */ + /* var tick = 0 addUpdatable { val angle = (tick / 1.0).degrees @@ -184,6 +196,7 @@ object Demo3 { ) tick++ } + */ } } } diff --git a/sample-raw-3d/src/commonMain/resources/box_textured.blend b/sample-raw-3d/src/commonMain/resources/box_textured.blend new file mode 100644 index 0000000..6040c23 Binary files /dev/null and b/sample-raw-3d/src/commonMain/resources/box_textured.blend differ diff --git a/sample-raw-3d/src/commonMain/resources/box_textured.dae b/sample-raw-3d/src/commonMain/resources/box_textured.dae new file mode 100644 index 0000000..0402423 --- /dev/null +++ b/sample-raw-3d/src/commonMain/resources/box_textured.dae @@ -0,0 +1,294 @@ + + + + + Blender User + Blender 2.79.0 commit date:2018-03-22, commit time:14:10, hash:f4dc9f9 + + 2019-03-10T23:38:20 + 2019-03-10T23:38:20 + + Z_UP + + + + + + + 49.13434 + 1.777778 + 0.1 + 100 + + + + + + 0 + 0 + 0 + + + + + + + + + 1 1 1 + 1 + 0 + 0.00111109 + + + + + 0 + 0 + 8192 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 1 + 29.99998 + 75 + 0.15 + 1 + 0 + 1 + 2 + 1.000799 + 30.002 + 1 + 3 + 0.04999995 + 2880 + 3 + 1 + 0 + 0 + 2 + 1 + 1 + 1 + 0 + 1 + 0.1 + 0.1 + 1 + 0.000999987 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 2 + 1 + 1 + 1 + 1 + 0 + + + + + + + 1 1 1 + 1 + 0 + 0.00111109 + + + + + 0 + 0 + 8192 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + 1 + 29.99998 + 75 + 0.15 + 1 + 0 + 1 + 2 + 1.000799 + 30.002 + 1 + 3 + 0.04999995 + 2880 + 3 + 1 + 0 + 0 + 2 + 1 + 1 + 1 + 0 + 1 + 0.1 + 0.1 + 1 + 0.000999987 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 2 + 1 + 1 + 1 + 1 + 0 + + + + + + + crate.png + + + + + + + + crate_png + + + + + crate_png-surface + + + + + + 0 0 0 1 + + + 0 0 0 1 + + + + + + 0.5 0.5 0.5 1 + + + 50 + + + 1 + + + + + + + + + + + + + + + + 1 1 -1 1 -1 -1 -1 -0.9999998 -1 -0.9999997 1 -1 1 0.9999995 1 0.9999994 -1.000001 1 -1 -0.9999997 1 -1 1 1 + + + + + + + + + + 0 0 -1 0 0 1 1 0 -2.38419e-7 0 -1 -4.76837e-7 -1 2.38419e-7 -1.49012e-7 2.68221e-7 1 2.38419e-7 0 0 -1 0 0 1 1 -5.96046e-7 3.27825e-7 -4.76837e-7 -1 0 -1 2.38419e-7 -1.19209e-7 2.08616e-7 1 0 + + + + + + + + + + 0 0 1 1 0 1 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 0 0 1 0 1 1 1 0 1 1 0 1 + + + + + + + + + + + + + + +

0 0 0 2 0 1 3 0 2 7 1 3 5 1 4 4 1 5 4 2 6 1 2 7 0 2 8 5 3 9 2 3 10 1 3 11 2 4 12 7 4 13 3 4 14 0 5 15 7 5 16 4 5 17 0 6 18 1 6 19 2 6 20 7 7 21 6 7 22 5 7 23 4 8 24 5 8 25 1 8 26 5 9 27 6 9 28 2 9 29 2 10 30 6 10 31 7 10 32 0 11 33 3 11 34 7 11 35

+
+
+
+
+ + + + + -0.2908646 -0.7711008 0.5663932 4.076245 0.9551712 -0.1998834 0.2183912 -4.424634 -0.05518906 0.6045247 0.7946723 5.903862 0 0 0 1 + + + + 0.6859207 -0.3240135 0.6515582 7.481132 0.7276763 0.3054208 -0.6141704 -6.50764 0 0.8953956 0.4452714 5.343665 0 0 0 1 + + + + -0.2908646 -0.7711008 0.5663932 4.076245 0.9551712 -0.1998834 0.2183912 1.005454 -0.05518906 0.6045247 0.7946723 5.903862 0 0 0 1 + + + + 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/sample-raw-3d/src/commonMain/resources/crate.png b/sample-raw-3d/src/commonMain/resources/crate.png new file mode 100644 index 0000000..80f7199 Binary files /dev/null and b/sample-raw-3d/src/commonMain/resources/crate.png differ