Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[1.15.2] Rendering custom obj model


Recommended Posts

I've updated to 1.15.2 and it finally started to render normally but it still has some problems:

  • When I edited it in Blender, I could hardly see any triangles and vertices, it was very smooth but in the actual game everything is way worse
  • It has some strange lightning, which I tried to disable with RenderSystem#disableLightning but it didn't do anything. Moreover, I noticed that its brightness doesn't change with the other blocks, e.g when the night come

My code:

package com.budrunbun.lavalamp.renderer;

import com.budrunbun.lavalamp.tileentity.TurretTileEntity;

import com.mojang.blaze3d.matrix.MatrixStack;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Atlases;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.model.ModelResourceLocation;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import net.minecraftforge.client.model.ModelDataManager;
import net.minecraftforge.client.model.data.IModelData;

import javax.annotation.Nonnull;

public class TurretRenderer extends TileEntityRenderer<TurretTileEntity> {
    private static final BlockModelRenderer blockRenderer = Minecraft.getInstance().getBlockRendererDispatcher().getBlockModelRenderer();
    private IBakedModel sphereQuarter;

    public TurretRenderer(TileEntityRendererDispatcher rendererDispatcherIn) {
        super(rendererDispatcherIn);
    }

    @Override
    public void render(TurretTileEntity turret, float partialTicks, @Nonnull MatrixStack matrices, @Nonnull IRenderTypeBuffer buffer, int combinedLightIn, int combinedOverlayIn) {
        BlockPos pos = turret.getPos();
        World world = turret.getWorld();

        if (sphereQuarter == null)
            sphereQuarter = Minecraft.getInstance().getModelManager().getModel(new ModelResourceLocation("lavalamp:sphere_quarter", ""));

        IModelData data = ModelDataManager.getModelData(world, pos);

        matrices.push();
        matrices.translate(0, 1, 0);
        matrices.scale(0.25F, 0.25F, 0.25F);

        //RenderSystem.disableLighting();
        blockRenderer.renderModel(
                matrices.getLast(),
                buffer.getBuffer(Atlases.getTranslucentCullBlockType()),
                turret.getBlockState(),
                sphereQuarter,
                1,
                1,
                1,
                combinedLightIn,
                combinedOverlayIn,
                data
        );
        //RenderSystem.enableLighting();

        matrices.pop();
    }
}

In-game appearance:

2021-05-20-20-10-05.png

Link to post
Share on other sites

I think that it has more to do with the inconsistent lighting rather than the roughness of the shape. And I think to deal with that there needs to be something changed within the mtl, though I don't remember what exactly. As for the incorrect location, blocks always need to be offset by 0.5 since the positions are determined by their corners and not by the center.

Link to post
Share on other sites
Posted (edited)

I didn't write anything about location but thanks anyway. As a side question: what is the ratio between ".obj" units and Minecraft units? I want my sphere to be 1x1x1 block but I don't know the scale.

Edited by BudRunBun
Link to post
Share on other sites

I figured out why it was so bright: I was passing to #renderModel 1, 1, 1 to rgb. Here comes another problem: I know how to get the light level of the current block(from 0 to 14) but I don't know how to convert it to the [0, 1] interval

Link to post
Share on other sites

I am stuck. I have looked up #getPackedLightmapCoords but I still don't know how Minecraft calculates the brightness parameter(I suspect via ambient occlusion). Since my model is rendered on top of the block, can I somehow "borrow" color from the top face of it?

Link to post
Share on other sites

Minecraft does not really have a concept of colored light. As such, if you wanted the color of a specific face, you would need to go into the baked model, grab the top quad, get the color of the quad, and apply the brightness modifier to it. At that point though it's not particularly worth it.

Link to post
Share on other sites

I have made some progress. I tried loading OBJ model myself(it works fine) and rendering it with triangles, not quads. Now ambient lighning works but diffuse doesn't: colour is changing every frame in random order, i.e the surface keeps flashing even when I stand still and look at it. I believe that problem is connected with normals but I can be wrong.2021-05-23-21-35-40.png

My code:

1) TE renderer:

package com.budrunbun.lavalamp.renderer;

import com.budrunbun.lavalamp.LavaLamp;
import com.budrunbun.lavalamp.model.OBJModel;
import com.budrunbun.lavalamp.model.OBJModelHandler;
import com.budrunbun.lavalamp.tileentity.TurretTileEntity;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import javax.annotation.Nonnull;

public class TurretRenderer extends TileEntityRenderer<TurretTileEntity> {
    private static final ResourceLocation TEXTURES = new ResourceLocation(LavaLamp.MOD_ID, "textures/block/colors/gray.png");
    private static final RenderType TURRET_RENDER_TYPE = RenderHelper.getOBJModelRenderType(TEXTURES);

    private OBJModel sphereQuarter;

    public TurretRenderer(TileEntityRendererDispatcher rendererDispatcherIn) {
        super(rendererDispatcherIn);
    }

    @Override
    public void render(TurretTileEntity turret, float partialTicks, @Nonnull MatrixStack matrices, @Nonnull IRenderTypeBuffer buffer, int light, int combinedOverlayIn) {
        BlockPos pos = turret.getPos();
        World world = turret.getWorld();

        if (sphereQuarter == null)
            sphereQuarter = OBJModelHandler.OBJModels.get(new ResourceLocation(LavaLamp.MOD_ID, "models/block/sphere_quarter.obj"));

        matrices.push();
        matrices.translate(0, 1, 0);
        matrices.scale(0.25F, 0.25F, 0.25F);

        sphereQuarter.render(
                matrices,
                buffer.getBuffer(TURRET_RENDER_TYPE),
                WorldRenderer.getCombinedLight(world, pos.up()),
                OverlayTexture.NO_OVERLAY,
                1, 1, 1, 1
        );

        matrices.pop();
    }
}

2) OBJ model:

package com.budrunbun.lavalamp.model;

import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;

import net.minecraft.client.renderer.Matrix3f;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Vector3f;
import net.minecraft.client.renderer.Vector4f;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.math.Vec3d;

import java.util.Iterator;
import java.util.Spliterator;
import java.util.Vector;
import java.util.function.Consumer;

public class OBJModel implements Iterable<OBJModel.Face> {
    private final Vector<Face> faces;

    public OBJModel(Vector<Face> faces) {
        this.faces = faces;
    }

    public void render(MatrixStack matrices, IVertexBuilder buffer, int light, int lightningOverlay, float red, float green, float blue, float alpha) {
        Matrix4f matrix4f = matrices.getLast().getMatrix();
        Matrix3f matrix3f = matrices.getLast().getNormal();

        for (Face face : this.faces) {
            Vector3f normal = face.normal;
            normal.transform(matrix3f);

            for (int i = 0; i < face.vertices.length; i++) {
                Vector4f position = new Vector4f(face.vertices[i].getX(), face.vertices[i].getY(), face.vertices[i].getZ(), 1);
                position.transform(matrix4f);

                buffer.addVertex(
                        position.getX(),
                        position.getY(),
                        position.getZ(),
                        red, green, blue, alpha,
                        face.tex[i].x, face.tex[i].y,
                        lightningOverlay,
                        light,
                        normal.getX(),
                        normal.getY(),
                        normal.getZ()
                );
            }
        }
    }

    public static class Material {
        public final String name;
        public Vec3d ambientColour = new Vec3d(0, 0, 0);
        public ResourceLocation ambientColourMap;
        public Vec3d diffuseColour = new Vec3d(1, 1, 1);
        public ResourceLocation diffuseColourMap;
        public Vec3d specularColour = new Vec3d(0, 0, 0);
        public float specularHighlight = 0;
        public ResourceLocation specularColourMap;
        public float opticalDensity = 1;
        public int illuminationModel = 2;

        public float dissolve = 1.0f;
        public float transparency = 0.0f;

        public Material(String name) {
            this.name = name;
        }
    }

    public static class Face {
        public static final Vec2f NO_TEX = new Vec2f(0, 0);

        public final Vector3f[] normals;
        public final Vec2f[] tex;
        public final Vector3f[] vertices;

        public final String materialName;
        public OBJModel.Material material;

        public final Vector3f normal;

        public Face(Vector3f[] vertex, Vec2f[] tex, Vector3f[] normal, String materialName) {
            this.vertices = vertex;
            this.tex = tex;
            this.normals = normal;
            this.materialName = materialName;

            Vector3f vec1 = new Vector3f(vertices[1].getX() - vertices[0].getX(), vertices[1].getY() - vertices[0].getY(), vertices[1].getZ() - vertices[0].getZ());
            Vector3f vec2 = new Vector3f(vertices[2].getX() - vertices[0].getX(), vertices[2].getY() - vertices[0].getY(), vertices[2].getZ() - vertices[0].getZ());

            vec1.cross(vec2);
            vec1.normalize();
            this.normal = vec1;
        }
    }

    @Override
    public Iterator<Face> iterator() {
        return this.faces.iterator();
    }

    @Override
    public void forEach(Consumer<? super Face> action) {
        this.faces.forEach(action);
    }

    @Override
    public Spliterator<Face> spliterator() {
        return this.faces.spliterator();
    }
}

3)RenderType:

    public static RenderType getOBJModelRenderType(ResourceLocation textures) {
        RenderType.State state = RenderType.State.getBuilder()
                .texture(new RenderState.TextureState(textures, false, false))
                .diffuseLighting(DIFFUSE_LIGHTING_ENABLED)
                .lightmap(LIGHTMAP_ENABLED)
                .build(true);
        return RenderType.makeType(
                "obj",
                DefaultVertexFormats.ENTITY,
                GL11.GL_TRIANGLES,
                256,
                true,
                false,
                state
        );
    }

 

Link to post
Share on other sites

The correct function, for whose, who need it, is:

    public static void normaliseVector(Vector3f vector) {
        float mu = vector.getX() * vector.getX() + vector.getY() * vector.getY() + vector.getZ() * vector.getZ();
        vector.mul((float) MathHelper.fastInvSqrt(mu));
    }

 

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.