Transform vertex normals as well as positions when generating quads (#5242)

This commit is contained in:
Ben Staddon 2019-04-11 17:59:16 +01:00 committed by tterrag
parent f68fdcf703
commit 441a9c9024
10 changed files with 199 additions and 141 deletions

View File

@ -478,6 +478,7 @@ public class ForgeHooksClient
case GENERIC:
glEnableVertexAttribArray(attr.getIndex());
glVertexAttribPointer(attr.getIndex(), count, constant, false, stride, buffer);
break;
default:
LOGGER.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
}
@ -508,6 +509,7 @@ public class ForgeHooksClient
break;
case GENERIC:
glDisableVertexAttribArray(attr.getIndex());
break;
default:
LOGGER.fatal("Unimplemented vanilla attribute upload: {}", attrType.getDisplayName());
}

View File

@ -34,6 +34,8 @@ import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
@ -399,53 +401,49 @@ public final class ItemLayerModel implements IUnbakedModel
float x3, float y3, float z3, float u3, float v3)
{
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
builder.setQuadTint(tint);
builder.setQuadOrientation(side);
builder.setTexture(sprite);
putVertex(builder, format, transform, side, x0, y0, z0, u0, v0);
putVertex(builder, format, transform, side, x1, y1, z1, u1, v1);
putVertex(builder, format, transform, side, x2, y2, z2, u2, v2);
putVertex(builder, format, transform, side, x3, y3, z3, u3, v3);
boolean hasTransform = transform.isPresent() && !transform.get().isIdentity();
IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transform.get()) : builder;
putVertex(consumer, format, side, x0, y0, z0, u0, v0);
putVertex(consumer, format, side, x1, y1, z1, u1, v1);
putVertex(consumer, format, side, x2, y2, z2, u2, v2);
putVertex(consumer, format, side, x3, y3, z3, u3, v3);
return builder.build();
}
private static void putVertex(UnpackedBakedQuad.Builder builder, VertexFormat format, Optional<TRSRTransformation> transform, EnumFacing side, float x, float y, float z, float u, float v)
private static void putVertex(IVertexConsumer consumer, VertexFormat format, EnumFacing side, float x, float y, float z, float u, float v)
{
Vector4f vec = new Vector4f();
boolean hasTransform = transform.isPresent() && !transform.get().isIdentity();
for(int e = 0; e < format.getElementCount(); e++)
{
switch(format.getElement(e).getUsage())
{
case POSITION:
if(hasTransform)
{
vec.x = x;
vec.y = y;
vec.z = z;
vec.w = 1;
transform.get().getMatrixVec().transform(vec);
builder.put(e, vec.x, vec.y, vec.z, vec.w);
}
else
{
builder.put(e, x, y, z, 1);
}
consumer.put(e, x, y, z, 1f);
break;
case COLOR:
builder.put(e, 1f, 1f, 1f, 1f);
consumer.put(e, 1f, 1f, 1f, 1f);
break;
case UV: if(format.getElement(e).getIndex() == 0)
{
builder.put(e, u, v, 0f, 1f);
break;
}
case NORMAL:
builder.put(e, (float)side.getXOffset(), (float)side.getYOffset(), (float)side.getZOffset(), 0f);
float offX = (float) side.getXOffset();
float offY = (float) side.getYOffset();
float offZ = (float) side.getZOffset();
consumer.put(e, offX, offY, offZ, 0f);
break;
case UV:
if(format.getElement(e).getIndex() == 0)
{
consumer.put(e, u, v, 0f, 1f);
break;
}
// else fallthrough to default
default:
builder.put(e);
consumer.put(e);
break;
}
}

View File

@ -25,11 +25,11 @@ import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.model.TRSRTransformation;
import javax.vecmath.Vector4f;
import java.util.List;
public final class ItemTextureQuadConverter
@ -240,65 +240,59 @@ public final class ItemTextureQuadConverter
builder.setQuadOrientation(side);
builder.setTexture(sprite);
// only apply the transform if it's not identity
boolean hasTransform = !transform.isIdentity();
IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transform) : builder;
if (side == EnumFacing.SOUTH)
{
putVertex(builder, format, transform, side, x1, y1, z, u1, v2, color);
putVertex(builder, format, transform, side, x2, y1, z, u2, v2, color);
putVertex(builder, format, transform, side, x2, y2, z, u2, v1, color);
putVertex(builder, format, transform, side, x1, y2, z, u1, v1, color);
putVertex(consumer, format, side, x1, y1, z, u1, v2, color);
putVertex(consumer, format, side, x2, y1, z, u2, v2, color);
putVertex(consumer, format, side, x2, y2, z, u2, v1, color);
putVertex(consumer, format, side, x1, y2, z, u1, v1, color);
}
else
{
putVertex(builder, format, transform, side, x1, y1, z, u1, v2, color);
putVertex(builder, format, transform, side, x1, y2, z, u1, v1, color);
putVertex(builder, format, transform, side, x2, y2, z, u2, v1, color);
putVertex(builder, format, transform, side, x2, y1, z, u2, v2, color);
putVertex(consumer, format, side, x1, y1, z, u1, v2, color);
putVertex(consumer, format, side, x1, y2, z, u1, v1, color);
putVertex(consumer, format, side, x2, y2, z, u2, v1, color);
putVertex(consumer, format, side, x2, y1, z, u2, v2, color);
}
return builder.build();
}
private static void putVertex(UnpackedBakedQuad.Builder builder, VertexFormat format, TRSRTransformation transform, EnumFacing side,
private static void putVertex(IVertexConsumer consumer, VertexFormat format, EnumFacing side,
float x, float y, float z, float u, float v, int color)
{
Vector4f vec = new Vector4f();
for (int e = 0; e < format.getElementCount(); e++)
{
switch (format.getElement(e).getUsage())
{
case POSITION:
if (transform.isIdentity())
{
builder.put(e, x, y, z, 1);
}
// only apply the transform if it's not identity
else
{
vec.x = x;
vec.y = y;
vec.z = z;
vec.w = 1;
transform.getMatrixVec().transform(vec);
builder.put(e, vec.x, vec.y, vec.z, vec.w);
}
consumer.put(e, x, y, z, 1f);
break;
case COLOR:
float r = ((color >> 16) & 0xFF) / 255f; // red
float g = ((color >> 8) & 0xFF) / 255f; // green
float b = ((color >> 0) & 0xFF) / 255f; // blue
float g = ((color >> 8) & 0xFF) / 255f; // green
float b = ((color >> 0) & 0xFF) / 255f; // blue
float a = ((color >> 24) & 0xFF) / 255f; // alpha
builder.put(e, r, g, b, a);
consumer.put(e, r, g, b, a);
break;
case NORMAL:
float offX = (float) side.getXOffset();
float offY = (float) side.getYOffset();
float offZ = (float) side.getZOffset();
consumer.put(e, offX, offY, offZ, 0f);
break;
case UV:
if (format.getElement(e).getIndex() == 0)
{
builder.put(e, u, v, 0f, 1f);
consumer.put(e, u, v, 0f, 1f);
break;
}
case NORMAL:
builder.put(e, (float) side.getXOffset(), (float) side.getYOffset(), (float) side.getZOffset(), 0f);
break;
// else fallthrough to default
default:
builder.put(e);
consumer.put(e);
break;
}
}

View File

@ -30,7 +30,6 @@ import java.util.Set;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.model.BakedQuad;
@ -44,6 +43,8 @@ import net.minecraft.resources.IResourceManager;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.common.model.IModelState;
@ -399,15 +400,19 @@ public final class ModelFluid implements IUnbakedModel
private BakedQuad buildQuad(EnumFacing side, TextureAtlasSprite texture, boolean flip, boolean offset, VertexParameter x, VertexParameter y, VertexParameter z, VertexParameter u, VertexParameter v)
{
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
builder.setQuadOrientation(side);
builder.setTexture(texture);
builder.setQuadTint(0);
boolean hasTransform = transformation.isPresent() && !transformation.get().isIdentity();
IVertexConsumer consumer = hasTransform ? new TRSRTransformer(builder, transformation.get()) : builder;
for (int i = 0; i < 4; i++)
{
int vertex = flip ? 3 - i : i;
putVertex(
builder, side, offset,
consumer, side, offset,
x.get(vertex), y.get(vertex), z.get(vertex),
texture.getInterpolatedU(u.get(vertex)),
texture.getInterpolatedV(v.get(vertex))
@ -417,7 +422,7 @@ public final class ModelFluid implements IUnbakedModel
return builder.build();
}
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing side, boolean offset, float x, float y, float z, float u, float v)
private void putVertex(IVertexConsumer consumer, EnumFacing side, boolean offset, float x, float y, float z, float u, float v)
{
for(int e = 0; e < format.getElementCount(); e++)
{
@ -427,32 +432,30 @@ public final class ModelFluid implements IUnbakedModel
float dx = offset ? side.getDirectionVec().getX() * eps : 0f;
float dy = offset ? side.getDirectionVec().getY() * eps : 0f;
float dz = offset ? side.getDirectionVec().getZ() * eps : 0f;
float[] data = { x - dx, y - dy, z - dz, 1f };
if(transformation.isPresent() && !transformation.get().isIdentity())
{
Vector4f vec = new Vector4f(data);
transformation.get().getMatrixVec().transform(vec);
vec.get(data);
}
builder.put(e, data);
consumer.put(e, x - dx, y - dy, z - dz, 1f);
break;
case COLOR:
builder.put(e,
((color >> 16) & 0xFF) / 255f,
((color >> 8) & 0xFF) / 255f,
(color & 0xFF) / 255f,
((color >> 24) & 0xFF) / 255f);
float r = ((color >> 16) & 0xFF) / 255f;
float g = ((color >> 8) & 0xFF) / 255f;
float b = ( color & 0xFF) / 255f;
float a = ((color >> 24) & 0xFF) / 255f;
consumer.put(e, r, g, b, a);
break;
case UV: if(format.getElement(e).getIndex() == 0)
{
builder.put(e, u, v, 0f, 1f);
break;
}
case NORMAL:
builder.put(e, (float)side.getXOffset(), (float)side.getYOffset(), (float)side.getZOffset(), 0f);
float offX = (float) side.getXOffset();
float offY = (float) side.getYOffset();
float offZ = (float) side.getZOffset();
consumer.put(e, offX, offY, offZ, 0f);
break;
case UV:
if(format.getElement(e).getIndex() == 0)
{
consumer.put(e, u, v, 0f, 1f);
break;
}
// else fallthrough to default
default:
builder.put(e);
consumer.put(e);
break;
}
}

View File

@ -19,12 +19,12 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.common.model.TRSRTransformation;
import com.google.common.collect.ImmutableList;
@ -41,7 +41,7 @@ import net.minecraft.util.ResourceLocation;
public abstract class SimpleModelFontRenderer extends FontRenderer {
private float r, g, b, a;
private final Matrix4f matrix;
private final TRSRTransformation transform;
private ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
private final VertexFormat format;
private final Vector3f normal = new Vector3f(0, 0, 1);
@ -52,16 +52,10 @@ public abstract class SimpleModelFontRenderer extends FontRenderer {
public SimpleModelFontRenderer(GameSettings settings, ResourceLocation font, TextureManager manager, boolean isUnicode, Matrix4f matrix, VertexFormat format)
{
super(manager, null);
// super(settings, font, manager, isUnicode);
this.matrix = new Matrix4f(matrix);
Matrix3f nm = new Matrix3f();
this.matrix.getRotationScale(nm);
nm.invert();
nm.transpose();
super(manager, null);
this.transform = new TRSRTransformation(matrix);
this.format = format;
nm.transform(normal);
normal.normalize();
transform.transformNormal(normal);
orientation = EnumFacing.getFacingFromVector(normal.x, normal.y, normal.z);
}
@ -79,21 +73,15 @@ public abstract class SimpleModelFontRenderer extends FontRenderer {
private void addVertex(UnpackedBakedQuad.Builder quadBuilder, float x, float y, float u, float v)
{
vec.x = x;
vec.y = y;
vec.z = 0;
vec.w = 1;
matrix.transform(vec);
for(int e = 0; e < format.getElementCount(); e++)
{
switch(format.getElement(e).getUsage())
{
case POSITION:
vec.set(x, y, 0f, 1f);
transform.transformPosition(vec);
quadBuilder.put(e, vec.x, vec.y, vec.z, vec.w);
break;
case UV:
quadBuilder.put(e, sprite.getInterpolatedU(u * 16), sprite.getInterpolatedV(v * 16), 0, 1);
break;
case COLOR:
quadBuilder.put(e, r, g, b, a);
break;
@ -101,6 +89,13 @@ public abstract class SimpleModelFontRenderer extends FontRenderer {
//quadBuilder.put(e, normal.x, normal.y, normal.z, 1);
quadBuilder.put(e, 0, 0, 1, 1);
break;
case UV:
if(format.getElement(e).getIndex() == 0)
{
quadBuilder.put(e, sprite.getInterpolatedU(u * 16), sprite.getInterpolatedV(v * 16), 0, 1);
break;
}
// else fallthrough to default
default:
quadBuilder.put(e);
break;

View File

@ -37,7 +37,6 @@ import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector2f;
@ -45,6 +44,7 @@ import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.common.model.TRSRTransformation;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
@ -681,25 +681,21 @@ public class B3DModel
else t.setIdentity();
}
TRSRTransformation trsr = new TRSRTransformation(t);
// pos
Vector4f pos = new Vector4f(this.pos), newPos = new Vector4f();
Vector4f pos = new Vector4f(this.pos);
pos.w = 1;
t.transform(pos, newPos);
Vector3f rPos = new Vector3f(newPos.x / newPos.w, newPos.y / newPos.w, newPos.z / newPos.w);
trsr.transformPosition(pos);
Vector3f rPos = new Vector3f(pos.x / pos.w, pos.y / pos.w, pos.z / pos.w);
// normal
Vector3f rNormal = null;
if(this.normal != null)
{
Matrix3f tm = new Matrix3f();
t.getRotationScale(tm);
tm.invert();
tm.transpose();
Vector3f normal = new Vector3f(this.normal);
rNormal = new Vector3f();
tm.transform(normal, rNormal);
rNormal.normalize();
rNormal = new Vector3f(this.normal);
trsr.transformNormal(rNormal);
}
// texCoords TODO

View File

@ -857,8 +857,6 @@ public class OBJModel implements IUnbakedModel
public Face bake(TRSRTransformation transform)
{
Matrix4f m = transform.getMatrixVec();
Matrix3f mn = null;
Vertex[] vertices = new Vertex[verts.length];
// Normal[] normals = norms != null ? new Normal[norms.length] : null;
// TextureCoordinate[] textureCoords = texCoords != null ? new TextureCoordinate[texCoords.length] : null;
@ -869,24 +867,16 @@ public class OBJModel implements IUnbakedModel
// Normal n = norms != null ? norms[i] : null;
// TextureCoordinate t = texCoords != null ? texCoords[i] : null;
Vector4f pos = new Vector4f(v.getPos()), newPos = new Vector4f();
Vector4f pos = new Vector4f(v.getPos());
pos.w = 1;
m.transform(pos, newPos);
vertices[i] = new Vertex(newPos, v.getMaterial());
transform.transformPosition(pos);
vertices[i] = new Vertex(pos, v.getMaterial());
if (v.hasNormal())
{
if(mn == null)
{
mn = new Matrix3f();
m.getRotationScale(mn);
mn.invert();
mn.transpose();
}
Vector3f normal = new Vector3f(v.getNormal().getData()), newNormal = new Vector3f();
mn.transform(normal, newNormal);
newNormal.normalize();
vertices[i].setNormal(new Normal(newNormal));
Vector3f normal = new Vector3f(v.getNormal().getData());
transform.transformNormal(normal);
vertices[i].setNormal(new Normal(normal));
}
if (v.hasTextureCoordinate()) vertices[i].setTextureCoordinate(v.getTextureCoordinate());

View File

@ -0,0 +1,55 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client.model.pipeline;
import net.minecraftforge.common.model.TRSRTransformation;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
public class TRSRTransformer extends VertexTransformer
{
private final TRSRTransformation transform;
public TRSRTransformer(IVertexConsumer parent, TRSRTransformation transform)
{
super(parent);
this.transform = transform;
}
@Override
public void put(int element, float... data)
{
switch (getVertexFormat().getElement(element).getUsage())
{
case POSITION:
Vector4f pos = new Vector4f(data);
transform.transformPosition(pos);
pos.get(data);
break;
case NORMAL:
Vector3f normal = new Vector3f(data);
transform.transformNormal(normal);
normal.get(data);
break;
}
super.put(element, data);
}
}

View File

@ -216,19 +216,19 @@ public class VertexLighterFlat extends QuadGatheringTransformer
pos[2] += blockInfo.getBlockPos().getZ();*/
parent.put(e, position[v]);
break;
case NORMAL: if(normalIndex != -1)
{
case NORMAL:
parent.put(e, normal[v]);
break;
}
case COLOR:
parent.put(e, color[v]);
break;
case UV: if(element.getIndex() == 1)
{
parent.put(e, lightmap[v]);
break;
}
case UV:
if(element.getIndex() == 1)
{
parent.put(e, lightmap[v]);
break;
}
// else fallthrough to default
default:
parent.put(e, quadData[e][v]);
}

View File

@ -72,6 +72,8 @@ public final class TRSRTransformation implements IModelState, ITransformation
private Vector3f scale;
private Quat4f rightRot;
private Matrix3f normalTransform;
public TRSRTransformation(@Nullable Matrix4f matrix)
{
if(matrix == null)
@ -625,6 +627,29 @@ public final class TRSRTransformation implements IModelState, ITransformation
return vertexIndex;
}
public void transformPosition(Vector4f position)
{
matrix.transform(position);
}
public void transformNormal(Vector3f normal)
{
checkNormalTransform();
normalTransform.transform(normal);
normal.normalize();
}
private void checkNormalTransform()
{
if (normalTransform == null)
{
normalTransform = new Matrix3f();
matrix.getRotationScale(normalTransform);
normalTransform.invert();
normalTransform.transpose();
}
}
@Override
public String toString()
{