Skip to content

Commit

Permalink
Octahedral encoded tangent vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
IMS212 committed Aug 25, 2023
1 parent 2ab6fa0 commit 75d0906
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,39 +140,17 @@ public static void replaceTangent(
root.replaceReferenceExpressions(t, "at_tangent", "iris_tangent");
tree.parseAndInjectNodes(t, ASTInjectionPoint.BEFORE_FUNCTIONS, "in vec4 iris_qTangent;", "vec4 iris_tangent;", "vec3 iris_Normal;",
"""
vec3 xAxis( vec4 qQuat )
{
float fTy = 2.0 * qQuat.y;
float fTz = 2.0 * qQuat.z;
float fTwy = fTy * qQuat.w;
float fTwz = fTz * qQuat.w;
float fTxy = fTy * qQuat.x;
float fTxz = fTz * qQuat.x;
float fTyy = fTy * qQuat.y;
float fTzz = fTz * qQuat.z;
return vec3( 1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy );
}
""", """
vec3 yAxis( vec4 qQuat )
{
float fTx = 2.0 * qQuat.x;
float fTy = 2.0 * qQuat.y;
float fTz = 2.0 * qQuat.z;
float fTwx = fTx * qQuat.w;
float fTwz = fTz * qQuat.w;
float fTxx = fTx * qQuat.x;
float fTxy = fTy * qQuat.x;
float fTyz = fTz * qQuat.y;
float fTzz = fTz * qQuat.z;
return vec3( fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx );
}
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
v.xy += t * -sign(v.xy);
return v;
}
"""
,"""
void _tangent_init() {
vec4 qtangent = normalize( iris_qTangent ); //Needed because of the quantization caused by 16-bit SNORM
iris_Normal = xAxis( qtangent );
iris_tangent = vec4(yAxis( qtangent ), sign( iris_qTangent.w ));
iris_Normal = oct_to_vec3(iris_qTangent.xy);
iris_tangent = vec4(oct_to_vec3(vec2(iris_qTangent.z, abs(iris_qTangent.w) * 2.0 - 1.0)), sign(iris_qTangent.w));
}
""");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,10 @@

import net.minecraft.util.Mth;
import org.joml.Math;
import org.joml.Matrix3f;
import org.joml.Quaternionf;

public class QTangentCalculator {
private Matrix3f tbn = new Matrix3f();
private Quaternionf qTangent = new Quaternionf();
private void vec_to_oct(int value)
{
float invL1Norm = 1.0f / (Math.abs(valueX) + Math.abs(valueY) + Math.abs(valueZ));
float resX = 0.0f, resY = 0.0f;
if (valueZ < 0.0f) {
resX = (1.0f - Math.abs(valueY * invL1Norm)) * Mth.sign(valueX);
resY = (1.0f - Math.abs(valueX * invL1Norm)) * Mth.sign(valueY);
} else {
resX = valueX * invL1Norm;
resY = valueY * invL1Norm;
}

normalConvX = floatToSnorm8(resX);
normalConvY = floatToSnorm8(resY);
}
public class OctahedralCalculator {
private static float bias = 1.0f / (2^(8 - 1) - 1);


private void vec_to_tangent(float valueX, float valueY, float valueZ, float valueW) {
//encode to octahedron, result in range [-1, 1]
float invL1Norm = 1.0f / (Math.abs(valueX) + Math.abs(valueY) + Math.abs(valueZ));
float resX = 0.0f, resY = 0.0f;
if (valueZ < 0.0f) {
resX = (1.0f - Math.abs(valueY * invL1Norm)) * Mth.sign(valueX);
resY = (1.0f - Math.abs(valueX * invL1Norm)) * Mth.sign(valueY);
} else {
resX = valueX * invL1Norm;
resY = valueY * invL1Norm;
}

// map y to always be positive
resY = resY * 0.5f + 0.5f;

// add a bias so that y is never 0 (sign in the vertex shader)
if (resY < bias)
resY = bias;

// Apply the sign of the binormal to y, which was computed elsewhere
if (valueW < 0)
resY *= -1;

tangentX = floatToSnorm8(resX);
tangentY = floatToSnorm8(resY);
}


private static byte floatToSnorm8( float v )
{
//According to D3D10 rules, the value "-1.0f" has two representations:
Expand All @@ -67,7 +19,7 @@ private static byte floatToSnorm8( float v )
127.0f );
}

public int calculateQTangent(boolean flipUpcomingNormal, QuadView q) {
public int calculateOctahedralEncode(boolean flipUpcomingNormal, QuadView q) {
final float x0;
final float y0;
final float z0;
Expand All @@ -81,34 +33,18 @@ public int calculateQTangent(boolean flipUpcomingNormal, QuadView q) {
final float y3;
final float z3;

// TODO: can tangents also use flipped xyz?
if (false) {
x0 = q.x(3);
y0 = q.y(3);
z0 = q.z(3);
x1 = q.x(2);
y1 = q.y(2);
z1 = q.z(2);
x2 = q.x(1);
y2 = q.y(1);
z2 = q.z(1);
x3 = q.x(0);
y3 = q.y(0);
z3 = q.z(0);
} else {
x0 = q.x(0);
y0 = q.y(0);
z0 = q.z(0);
x1 = q.x(1);
y1 = q.y(1);
z1 = q.z(1);
x2 = q.x(2);
y2 = q.y(2);
z2 = q.z(2);
x3 = q.x(3);
y3 = q.y(3);
z3 = q.z(3);
}
x0 = q.x(0);
y0 = q.y(0);
z0 = q.z(0);
x1 = q.x(1);
y1 = q.y(1);
z1 = q.z(1);
x2 = q.x(2);
y2 = q.y(2);
z2 = q.z(2);
x3 = q.x(3);
y3 = q.y(3);
z3 = q.z(3);

final float dx0 = x2 - x0;
final float dy0 = y2 - y0;
Expand All @@ -121,7 +57,7 @@ public int calculateQTangent(boolean flipUpcomingNormal, QuadView q) {
float normY = dz0 * dx1 - dx0 * dz1;
float normZ = dx0 * dy1 - dy0 * dx1;

float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
float l = Math.sqrt(normX * normX + normY * normY + normZ * normZ);

if (l != 0) {
normX /= l;
Expand Down Expand Up @@ -199,36 +135,45 @@ public int calculateQTangent(boolean flipUpcomingNormal, QuadView q) {
tangentW = 1.0F;
}

float invL1Norm = (1.0f) / (Math.abs(normX) + Math.abs(normY) + Math.abs(normZ));

float octNormX;
float octNormY;

float invL1Norm = 1.0f / (Math.abs(normX) + Math.abs(normY) + Math.abs(normZ));
float resX = 0.0f, resY = 0.0f;
if (normZ < 0.0f) {
octNormX = (1.0f - Math.abs(normY * invL1Norm)) * Math.signum(normX);
octNormY = (1.0f - Math.abs(normX * invL1Norm)) * Math.signum(normY);
resX = (1.0f - Math.abs(normY * invL1Norm)) * Mth.sign(normX);
resY = (1.0f - Math.abs(normX * invL1Norm)) * Mth.sign(normY);
} else {
octNormX = normX * invL1Norm;
octNormY = normY * invL1Norm;
resX = normX * invL1Norm;
resY = normY * invL1Norm;
}

float invL1Tang = (1.0f) / (Math.abs(tangentx) + Math.abs(tangenty) + Math.abs(tangentz));

float octTangX;
float octTangY;
byte normalConvX = floatToSnorm8(resX);
byte normalConvY = floatToSnorm8(resY);

//encode to octahedron, result in range [-1, 1]
float invL1Tang = 1.0f / (Math.abs(tangentx) + Math.abs(tangenty) + Math.abs(tangentz));
float tanX = 0.0f, tanY = 0.0f;
if (tangentz < 0.0f) {
octTangX = (1.0f - Math.abs(tangenty * invL1Tang)) * Math.signum(tangentx);
octTangY = (1.0f - Math.abs(tangentx * invL1Tang)) * Math.signum(tangenty);
tanX = (1.0f - Math.abs(tangenty * invL1Tang)) * Mth.sign(tangentx);
tanY = (1.0f - Math.abs(tangentx * invL1Tang)) * Mth.sign(tangenty);
} else {
octTangX = normX * invL1Tang;
octTangY = normY * invL1Tang;
tanX = tangentx * invL1Tang;
tanY = tangenty * invL1Tang;
}

octTangY = octTangY * 0.5f + 0.5f;
octTangY = Math.max(octTangY, bias) * Math.signum(tangentW);
// map y to always be positive
tanY = tanY * 0.5f + 0.5f;

// add a bias so that y is never 0 (sign in the vertex shader)
if (tanY < bias)
tanY = bias;

// Apply the sign of the binormal to y, which was computed elsewhere
if (tangentW < 0)
tanY *= -1;

byte convTangX = floatToSnorm8(tanX);
byte convTangY = floatToSnorm8(tanY);

return NormI8.pack(octNormX, octNormY, octTangX, octTangY);
return convTangY << 24 | convTangX << 16 | normalConvY << 8 | normalConvX << 0;
}

private static float rsqrt(float value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@
import net.caffeinemc.mods.sodium.api.util.ColorU8;
import net.coderbot.iris.compat.sodium.impl.block_context.BlockContextHolder;
import net.coderbot.iris.compat.sodium.impl.block_context.ContextAwareVertexWriter;
import net.coderbot.iris.vertices.NormI8;
import net.coderbot.iris.vertices.QTangentCalculator;
import net.coderbot.iris.vertices.OctahedralCalculator;
import net.coderbot.iris.vertices.QuadView;
import net.minecraft.util.Mth;
import org.joml.Matrix3f;
import org.joml.Quaternionf;
import org.joml.Vector2f;
import org.joml.Vector3f;
import net.coderbot.iris.vertices.ExtendedDataHelper;
import net.coderbot.iris.vertices.NormalHelper;
import org.lwjgl.system.MemoryUtil;

import static net.coderbot.iris.compat.sodium.impl.vertex_format.terrain_xhfp.XHFPModelVertexType.STRIDE;
Expand All @@ -34,6 +28,7 @@ public class XHFPTerrainVertex implements ChunkVertexEncoder, ContextAwareVertex
private float uSum;
private float vSum;
private boolean flipUpcomingNormal;
private Vertex[] vertices = new Vertex[4];

// TODO: FIX

Expand Down Expand Up @@ -62,7 +57,7 @@ public void copyQuadAndFlipNormal() {
}*/

private long writePointer;
private QTangentCalculator qTangentCalc = new QTangentCalculator();
private OctahedralCalculator encoder = new OctahedralCalculator();

@Override
public void iris$setContextHolder(BlockContextHolder holder) {
Expand All @@ -73,43 +68,16 @@ public void copyQuadAndFlipNormal() {
public void flipUpcomingQuadNormal() {
flipUpcomingNormal = true;
}
static float bias = 1.0f / (2^(8 - 1) - 1);

Quaternionf tangent_space_to_quat(Vector3f normal, Vector3f tangent, Vector3f bitangent) {
Matrix3f tbn = new Matrix3f(normal, tangent, bitangent);
Quaternionf qTangent = new Quaternionf();
qTangent.normalize();

//Make sure QTangent is always positive
if (qTangent.w < 0)
qTangent.set(-qTangent.x, -qTangent.y, -qTangent.z, -qTangent.w);


//Because '-0' sign information is lost when using integers,
//we need to apply a "bias"; while making sure the Quaternion
//stays normalized.
// ** Also our shaders assume qTangent.w is never 0. **
if (qTangent.w < bias) {
float normFactor = (float) Math.sqrt( 1 - bias * bias );
qTangent.w = bias;
qTangent.x *= normFactor;
qTangent.y *= normFactor;
qTangent.z *= normFactor;
}

//If it's reflected, then make sure .w is negative.
Vector3f naturalBinormal = tangent.cross(normal);
if (naturalBinormal.dot(bitangent) <= 0)
qTangent.set(-qTangent.x, -qTangent.y, -qTangent.z, -qTangent.w);
return qTangent;
}
static float bias = 1.0f / (2^(8 - 1) - 1);

@Override
public long write(long ptr,
Material material, Vertex vertex, int sectionIndex) {
uSum += vertex.u;
vSum += vertex.v;

vertices[vertexCount] = vertex;

this.writePointer = ptr;

vertexCount++;
Expand Down Expand Up @@ -173,12 +141,12 @@ public long write(long ptr,
// Implementation based on the algorithm found here:
// https://github.com/IrisShaders/ShaderDoc/blob/master/vertex-format-extensions.md#surface-normal-vector

int tangent = qTangentCalc.calculateQTangent(flipUpcomingNormal, this);
int normTangent = encoder.calculateOctahedralEncode(flipUpcomingNormal, this);

MemoryUtil.memPutInt(ptr + 20, tangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE, tangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE * 2, tangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE * 3, tangent);
MemoryUtil.memPutInt(ptr + 20, normTangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE, normTangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE * 2, normTangent);
MemoryUtil.memPutInt(ptr + 20 - STRIDE * 3, normTangent);

flipUpcomingNormal = false;
}
Expand All @@ -188,26 +156,26 @@ public long write(long ptr,

@Override
public float x(int index) {
return XHFPModelVertexType.decodePosition(MemoryUtil.memGetShort(writePointer - STRIDE * (3L - index)));
return vertices[index].x;
}

@Override
public float y(int index) {
return XHFPModelVertexType.decodePosition(MemoryUtil.memGetShort(writePointer + 2 - STRIDE * (3L - index)));
return vertices[index].y;
}

@Override
public float z(int index) {
return XHFPModelVertexType.decodePosition(MemoryUtil.memGetShort(writePointer + 4 - STRIDE * (3L - index)));
return vertices[index].z;
}

@Override
public float u(int index) {
return XHFPModelVertexType.decodeTexture(MemoryUtil.memGetShort(writePointer + 12 - STRIDE * (3L - index)));
return vertices[index].u;
}

@Override
public float v(int index) {
return XHFPModelVertexType.decodeTexture(MemoryUtil.memGetShort(writePointer + 14 - STRIDE * (3L - index)));
return vertices[index].v;
}
}

0 comments on commit 75d0906

Please sign in to comment.