Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for skinned Mesh #4968

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.terasology.engine.core.subsystem.headless.assets.HeadlessMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessShader;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessSkeletalMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessTexture;
import org.terasology.engine.entitySystem.entity.internal.EngineEntityManager;
import org.terasology.engine.entitySystem.prefab.Prefab;
Expand All @@ -48,6 +49,7 @@
import org.terasology.engine.rendering.assets.font.FontImpl;
import org.terasology.engine.rendering.assets.material.Material;
import org.terasology.engine.rendering.assets.mesh.Mesh;
import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.engine.rendering.assets.shader.Shader;
import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.engine.rendering.assets.texture.PNGTextureFormat;
Expand Down Expand Up @@ -230,6 +232,8 @@ protected AssetManager setupAssetManager() {
HeadlessMesh::new, "mesh");
assetTypeManager.createAssetType(SkeletalMesh.class,
HeadlessSkeletalMesh::new, "skeletalMesh");
assetTypeManager.createAssetType(SkinnedMesh.class,
HeadlessSkinnedMesh::new, "skeletalMesh");
assetTypeManager.createAssetType(MeshAnimation.class,
MeshAnimationImpl::new, "animations");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.terasology.engine.core.subsystem.headless.assets.HeadlessMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessShader;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessSkeletalMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh;
import org.terasology.engine.core.subsystem.headless.assets.HeadlessTexture;
import org.terasology.engine.core.subsystem.headless.device.HeadlessDisplayDevice;
import org.terasology.engine.core.subsystem.headless.renderer.HeadlessCanvasRenderer;
Expand All @@ -23,6 +24,7 @@
import org.terasology.engine.rendering.assets.font.FontImpl;
import org.terasology.engine.rendering.assets.material.Material;
import org.terasology.engine.rendering.assets.mesh.Mesh;
import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.engine.rendering.assets.shader.Shader;
import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.engine.rendering.assets.texture.PNGTextureFormat;
Expand Down Expand Up @@ -55,6 +57,7 @@ public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager)
assetTypeManager.createAssetType(Material.class, HeadlessMaterial::new, "materials");
assetTypeManager.createAssetType(Mesh.class, HeadlessMesh::new, "mesh");
assetTypeManager.createAssetType(SkeletalMesh.class, HeadlessSkeletalMesh::new, "skeletalMesh");
assetTypeManager.createAssetType(SkinnedMesh.class, HeadlessSkinnedMesh::new, "skeletalMesh");
assetTypeManager.createAssetType(MeshAnimation.class, MeshAnimationImpl::new, "animations");
assetTypeManager.createAssetType(Atlas.class, Atlas::new, "atlas");
assetTypeManager.createAssetType(Subtexture.class, Subtexture::new);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0
package org.terasology.engine.core.subsystem.headless.assets;

import com.google.common.collect.Maps;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.engine.rendering.assets.mesh.SkinnedMeshData;
import org.terasology.engine.rendering.assets.mesh.resource.VertexAttributeBinding;
import org.terasology.engine.rendering.assets.mesh.resource.VertexByteAttributeBinding;
import org.terasology.engine.rendering.assets.skeletalmesh.Bone;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.joml.geom.AABBf;
import org.terasology.joml.geom.AABBfc;

import java.util.List;
import java.util.Map;

public class HeadlessSkinnedMesh extends SkinnedMesh {

private List<Bone> bones;
private Map<String, Bone> boneLookup = Maps.newHashMap();
private VertexAttributeBinding<Vector3fc, Vector3f> positions;
private VertexByteAttributeBinding boneIndex0;
private VertexByteAttributeBinding boneIndex1;
private VertexByteAttributeBinding boneIndex2;
private VertexByteAttributeBinding boneIndex3;
private AABBf bounds;

public HeadlessSkinnedMesh(ResourceUrn urn, AssetType<?, SkinnedMeshData> assetType, SkinnedMeshData skinnedMesh) {
super(urn, assetType);
reload(skinnedMesh);
}

@Override
protected void doReload(SkinnedMeshData data) {
this.boneLookup.clear();
this.positions = data.positions();
this.boneIndex0 = data.boneIndex0();
this.boneIndex1 = data.boneIndex0();
this.boneIndex2 = data.boneIndex0();
this.boneIndex3 = data.boneIndex0();
this.bones.forEach(b -> {

Check warning on line 45 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

NP_UNWRITTEN_FIELD

NORMAL: Read of unwritten field bones in org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.doReload(SkinnedMeshData)
Raw output
<p> The program is dereferencing a field that does not seem to ever have a non-null value written to it. Unless the field is initialized via some mechanism not seen by the analysis, dereferencing this value will generate a null pointer exception. </p>

Check warning on line 45 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

UWF_UNWRITTEN_FIELD

LOW: Unwritten field: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.bones
Raw output
<p> This field is never written.&nbsp; All reads of it will return the default value. Check for errors (should it have been initialized?), or remove it if it is useless.</p>
boneLookup.put(b.getName(), b);
});
getBound(bounds);

Check warning on line 48 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

UWF_UNWRITTEN_FIELD

LOW: Unwritten field: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.bounds
Raw output
<p> This field is never written.&nbsp; All reads of it will return the default value. Check for errors (should it have been initialized?), or remove it if it is useless.</p>
}

@Override
public AABBfc getAABB() {
return bounds;

Check warning on line 53 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.getAABB() may expose internal representation by returning HeadlessSkinnedMesh.bounds
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public VertexAttributeBinding<Vector3fc, Vector3f> vertices() {
return positions;

Check warning on line 58 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.vertices() may expose internal representation by returning HeadlessSkinnedMesh.positions
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public int elementCount() {
return this.positions.elements();
}

@Override
public VertexByteAttributeBinding boneIndex0() {
return boneIndex0;

Check warning on line 68 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.boneIndex0() may expose internal representation by returning HeadlessSkinnedMesh.boneIndex0
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public VertexByteAttributeBinding boneIndex1() {
return boneIndex1;

Check warning on line 73 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.boneIndex1() may expose internal representation by returning HeadlessSkinnedMesh.boneIndex1
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public VertexByteAttributeBinding boneIndex2() {
return boneIndex2;

Check warning on line 78 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.boneIndex2() may expose internal representation by returning HeadlessSkinnedMesh.boneIndex2
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public VertexByteAttributeBinding boneIndex3() {
return boneIndex3;

Check warning on line 83 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.boneIndex3() may expose internal representation by returning HeadlessSkinnedMesh.boneIndex3
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public List<Bone> bones() {
return bones;

Check warning on line 88 in engine/src/main/java/org/terasology/engine/core/subsystem/headless/assets/HeadlessSkinnedMesh.java

View check run for this annotation

Terasology Jenkins.io / SpotBugs

EI_EXPOSE_REP

LOW: org.terasology.engine.core.subsystem.headless.assets.HeadlessSkinnedMesh.bones() may expose internal representation by returning HeadlessSkinnedMesh.bones
Raw output
<p> Returning a reference to a mutable object value stored in one of the object's fields exposes the internal representation of the object.&nbsp; If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.</p>
}

@Override
public Bone getBone(String boneName) {
return boneLookup.get(boneName);
}

@Override
public void render() {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.terasology.engine.rendering.assets.font.FontImpl;
import org.terasology.engine.rendering.assets.material.Material;
import org.terasology.engine.rendering.assets.mesh.Mesh;
import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.engine.rendering.assets.shader.Shader;
import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.engine.rendering.assets.texture.PNGTextureFormat;
Expand All @@ -28,6 +29,7 @@
import org.terasology.engine.rendering.opengl.GLSLShader;
import org.terasology.engine.rendering.opengl.OpenGLMesh;
import org.terasology.engine.rendering.opengl.OpenGLSkeletalMesh;
import org.terasology.engine.rendering.opengl.OpenGLSkinnedMesh;
import org.terasology.engine.rendering.opengl.OpenGLTexture;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.module.ModuleAssetScanner;
Expand Down Expand Up @@ -90,6 +92,10 @@ public void registerCoreAssetTypes(ModuleAwareAssetTypeManager assetTypeManager)
(urn, assetType, data) ->
OpenGLSkeletalMesh.create(urn, assetType, data, this),
"skeletalMesh");
assetTypeManager.createAssetType(SkinnedMesh.class,
(urn, assetType, data) ->
OpenGLSkinnedMesh.create(urn, assetType, data, this),
"skeletalMesh");
assetTypeManager.createAssetType(MeshAnimation.class, MeshAnimationImpl::new,
"animations", "skeletalMesh");
assetTypeManager.createAssetType(Atlas.class, Atlas::new, "atlas");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

package org.terasology.engine.rendering.assets.animation;

import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.gestalt.assets.Asset;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.joml.geom.AABBf;

public abstract class MeshAnimation extends Asset<MeshAnimationData> {
Expand All @@ -15,7 +15,7 @@ protected MeshAnimation(ResourceUrn urn, AssetType<?, MeshAnimationData> assetTy
super(urn, assetType);
}

public abstract boolean isValidAnimationFor(SkeletalMesh mesh);
public abstract boolean isValidAnimationFor(SkinnedMesh mesh);

public abstract int getBoneCount();

Expand All @@ -28,4 +28,8 @@ protected MeshAnimation(ResourceUrn urn, AssetType<?, MeshAnimationData> assetTy
public abstract float getTimePerFrame();

public abstract AABBf getAabb();

public float getDuration() {
return getTimePerFrame() * (getFrameCount() - 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
package org.terasology.engine.rendering.assets.animation;

import org.terasology.engine.rendering.assets.mesh.SkinnedMesh;
import org.terasology.gestalt.assets.Asset;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.engine.rendering.assets.skeletalmesh.Bone;
import org.terasology.engine.rendering.assets.skeletalmesh.SkeletalMesh;
import org.terasology.joml.geom.AABBf;

import java.util.Optional;
Expand All @@ -21,7 +21,7 @@ public MeshAnimationImpl(ResourceUrn urn, AssetType<?, MeshAnimationData> assetT
}

@Override
public boolean isValidAnimationFor(SkeletalMesh mesh) {
public boolean isValidAnimationFor(SkinnedMesh mesh) {
for (int i = 0; i < data.getBoneNames().size(); ++i) {
Bone bone = mesh.getBone(data.getBoneNames().get(i));
boolean hasParent = data.getBoneParent().get(i) != MeshAnimationData.NO_PARENT;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.engine.rendering.assets.mesh;

import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.terasology.engine.rendering.assets.mesh.resource.VertexAttributeBinding;
import org.terasology.engine.rendering.assets.mesh.resource.VertexByteAttributeBinding;
import org.terasology.engine.rendering.assets.skeletalmesh.Bone;
import org.terasology.gestalt.assets.Asset;
import org.terasology.gestalt.assets.AssetType;
import org.terasology.gestalt.assets.DisposableResource;
import org.terasology.gestalt.assets.ResourceUrn;
import org.terasology.joml.geom.AABBf;
import org.terasology.joml.geom.AABBfc;

import java.util.List;

public abstract class SkinnedMesh extends Asset<SkinnedMeshData> {

protected SkinnedMesh(ResourceUrn urn, AssetType<?, SkinnedMeshData> assetType) {
super(urn, assetType);
}

protected SkinnedMesh(ResourceUrn urn, AssetType<?, SkinnedMeshData> assetType, DisposableResource resource) {
super(urn, assetType, resource);
}

public abstract AABBfc getAABB();

protected AABBf getBound(AABBf dest) {
VertexAttributeBinding<Vector3fc, Vector3f> vertices = this.vertices();
if (elementCount() == 0) {
dest.set(Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY,
Float.NEGATIVE_INFINITY,
Float.NEGATIVE_INFINITY,
Float.NEGATIVE_INFINITY);
return dest;
}
Vector3f pos = new Vector3f();
for (int x = 0; x < elementCount(); x++) {
dest.union(vertices.get(x, pos));
}
return dest;
}

public abstract VertexAttributeBinding<Vector3fc, Vector3f> vertices();
public abstract int elementCount();

public abstract VertexByteAttributeBinding boneIndex0();
public abstract VertexByteAttributeBinding boneIndex1();
public abstract VertexByteAttributeBinding boneIndex2();
public abstract VertexByteAttributeBinding boneIndex3();
public abstract List<Bone> bones();
public abstract Bone getBone(String name);
public abstract void render();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.engine.rendering.assets.mesh;

import org.joml.Vector4f;
import org.joml.Vector4fc;
import org.terasology.engine.rendering.assets.mesh.resource.AllocationType;
import org.terasology.engine.rendering.assets.mesh.resource.DrawingMode;
import org.terasology.engine.rendering.assets.mesh.resource.VertexAttributeBinding;
import org.terasology.engine.rendering.assets.mesh.resource.VertexByteAttributeBinding;
import org.terasology.engine.rendering.assets.skeletalmesh.Bone;

import java.util.List;

public abstract class SkinnedMeshData extends MeshData {

public SkinnedMeshData() {
this(DrawingMode.TRIANGLES, AllocationType.STATIC);
}

public SkinnedMeshData(DrawingMode mode, AllocationType allocationType) {
super(mode, allocationType);
}

public abstract VertexByteAttributeBinding boneIndex0();
public abstract VertexByteAttributeBinding boneIndex1();
public abstract VertexByteAttributeBinding boneIndex2();
public abstract VertexByteAttributeBinding boneIndex3();
public abstract VertexAttributeBinding<Vector4fc, Vector4f> weight();
public abstract List<Bone> bones();

}
Loading