mirror of
https://github.com/xiaopeng12138/MaiDXR.git
synced 2024-12-19 04:15:53 +01:00
443 lines
13 KiB
C#
443 lines
13 KiB
C#
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
* All rights reserved.
|
|
*
|
|
* Licensed under the Oculus SDK License Agreement (the "License");
|
|
* you may not use the Oculus SDK except in compliance with the License,
|
|
* which is provided at the time of installation or download, or which
|
|
* otherwise accompanies this software in either electronic or hard copy form.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://developer.oculus.com/licenses/oculussdk/
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, the Oculus SDK
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System;
|
|
using UnityEngine;
|
|
using OVRSimpleJSON;
|
|
using Unity.Jobs;
|
|
using Unity.Collections;
|
|
|
|
public enum OVRGLTFType
|
|
{
|
|
NONE,
|
|
SCALAR,
|
|
VEC2,
|
|
VEC3,
|
|
VEC4,
|
|
MAT4,
|
|
}
|
|
|
|
public enum OVRGLTFComponentType
|
|
{
|
|
BYTE = 5120,
|
|
UNSIGNED_BYTE = 5121,
|
|
SHORT = 5122,
|
|
UNSIGNED_SHORT = 5123,
|
|
UNSIGNED_INT = 5125,
|
|
FLOAT = 5126,
|
|
}
|
|
|
|
public class OVRGLTFAccessor
|
|
{
|
|
// Buffer View parameters
|
|
private int byteOffset;
|
|
private int byteLength;
|
|
private int byteStride;
|
|
private int bufferId;
|
|
private int bufferLength;
|
|
|
|
// Accessor parameters
|
|
private int additionalOffset;
|
|
private OVRGLTFType dataType;
|
|
private OVRGLTFComponentType componentType;
|
|
private int dataCount;
|
|
|
|
public OVRGLTFAccessor(JSONNode node, JSONNode root, bool bufferViewOnly = false)
|
|
{
|
|
JSONNode jsonBufferView = node;
|
|
if (!bufferViewOnly)
|
|
{
|
|
additionalOffset = node["byteOffset"].AsInt;
|
|
dataType = ToOVRType(node["type"].Value);
|
|
componentType = (OVRGLTFComponentType)node["componentType"].AsInt;
|
|
dataCount = node["count"].AsInt;
|
|
|
|
int bufferViewId = node["bufferView"].AsInt;
|
|
jsonBufferView = root["bufferViews"][bufferViewId];
|
|
}
|
|
|
|
int bufferId = jsonBufferView["buffer"].AsInt;
|
|
byteOffset = jsonBufferView["byteOffset"].AsInt;
|
|
byteLength = jsonBufferView["byteLength"].AsInt;
|
|
byteStride = jsonBufferView["byteStride"].AsInt;
|
|
|
|
var jsonBuffer = root["buffers"][bufferId];
|
|
bufferLength = jsonBuffer["byteLength"].AsInt;
|
|
}
|
|
|
|
public int GetDataCount()
|
|
{
|
|
return dataCount;
|
|
}
|
|
|
|
private static OVRGLTFType ToOVRType(string type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case "SCALAR":
|
|
return OVRGLTFType.SCALAR;
|
|
case "VEC2":
|
|
return OVRGLTFType.VEC2;
|
|
case "VEC3":
|
|
return OVRGLTFType.VEC3;
|
|
case "VEC4":
|
|
return OVRGLTFType.VEC4;
|
|
case "MAT4":
|
|
return OVRGLTFType.MAT4;
|
|
default:
|
|
Debug.LogError("Unsupported accessor type.");
|
|
return OVRGLTFType.NONE;
|
|
}
|
|
}
|
|
|
|
public void ReadAsInt(OVRBinaryChunk chunk, ref int[] data, int offset)
|
|
{
|
|
if (dataType != OVRGLTFType.SCALAR)
|
|
{
|
|
Debug.LogError("Tried to read non-scalar data as a uint array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int stride = byteStride > 0 ? byteStride : GetStrideForType(componentType);
|
|
for(int i = 0; i < dataCount; i++)
|
|
{
|
|
data[offset + i] = (int)ReadElementAsUint(bufferData, i * stride, componentType);
|
|
}
|
|
}
|
|
|
|
public void ReadAsVector2(OVRBinaryChunk chunk, ref Vector2[] data, int offset)
|
|
{
|
|
if (dataType != OVRGLTFType.VEC2)
|
|
{
|
|
Debug.LogError("Tried to read non-vec3 data as a vec2 array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * 2;
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
if (componentType == OVRGLTFComponentType.FLOAT)
|
|
{
|
|
data[offset + i].x = ReadElementAsFloat(bufferData, i * stride);
|
|
data[offset + i].y = ReadElementAsFloat(bufferData, i * stride + dataTypeSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadAsVector3(OVRBinaryChunk chunk, ref Vector3[] data, int offset, Vector3 conversionScale)
|
|
{
|
|
if (dataType != OVRGLTFType.VEC3)
|
|
{
|
|
Debug.LogError("Tried to read non-vec3 data as a vec3 array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * 3;
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
if (componentType == OVRGLTFComponentType.FLOAT)
|
|
{
|
|
data[offset + i].x = ReadElementAsFloat(bufferData, i * stride);
|
|
data[offset + i].y = ReadElementAsFloat(bufferData, i * stride + dataTypeSize);
|
|
data[offset + i].z = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 2);
|
|
}
|
|
else
|
|
{
|
|
data[offset + i].x = ReadElementAsUint(bufferData, i * stride, componentType);
|
|
data[offset + i].y = ReadElementAsUint(bufferData, i * stride + dataTypeSize, componentType);
|
|
data[offset + i].z = ReadElementAsUint(bufferData, i * stride + dataTypeSize * 2, componentType);
|
|
}
|
|
data[offset + i].Scale(conversionScale);
|
|
}
|
|
}
|
|
|
|
public void ReadAsVector4(OVRBinaryChunk chunk, ref Vector4[] data, int offset, Vector4 conversionScale)
|
|
{
|
|
if (dataType != OVRGLTFType.VEC4)
|
|
{
|
|
Debug.LogError("Tried to read non-vec4 data as a vec4 array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * 4;
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
if (componentType == OVRGLTFComponentType.FLOAT)
|
|
{
|
|
data[offset + i].x = ReadElementAsFloat(bufferData, i * stride);
|
|
data[offset + i].y = ReadElementAsFloat(bufferData, i * stride + dataTypeSize);
|
|
data[offset + i].z = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 2);
|
|
data[offset + i].w = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 3);
|
|
}
|
|
else
|
|
{
|
|
data[offset + i].x = ReadElementAsUint(bufferData, i * stride, componentType);
|
|
data[offset + i].y = ReadElementAsUint(bufferData, i * stride + dataTypeSize, componentType);
|
|
data[offset + i].z = ReadElementAsUint(bufferData, i * stride + dataTypeSize * 2, componentType);
|
|
data[offset + i].w = ReadElementAsUint(bufferData, i * stride + dataTypeSize * 3, componentType);
|
|
}
|
|
data[offset + i].Scale(conversionScale);
|
|
}
|
|
}
|
|
|
|
public void ReadAsColor(OVRBinaryChunk chunk, ref Color[] data, int offset)
|
|
{
|
|
if (dataType != OVRGLTFType.VEC4 && dataType != OVRGLTFType.VEC3)
|
|
{
|
|
Debug.LogError("Tried to read non-color type as a color array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int vecSize = dataType == OVRGLTFType.VEC3 ? 3 : 4;
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * vecSize;
|
|
float maxValue = GetMaxValueForType(componentType);
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
if (componentType == OVRGLTFComponentType.FLOAT)
|
|
{
|
|
data[offset + i].r = ReadElementAsFloat(bufferData, i * stride);
|
|
data[offset + i].g = ReadElementAsFloat(bufferData, i * stride + dataTypeSize);
|
|
data[offset + i].b = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 2);
|
|
data[offset + i].a = dataType == OVRGLTFType.VEC3 ? 1.0f : ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 3);
|
|
}
|
|
else
|
|
{
|
|
data[offset + i].r = ReadElementAsUint(bufferData, i * stride, componentType) / maxValue;
|
|
data[offset + i].g = ReadElementAsUint(bufferData, i * stride + dataTypeSize, componentType) / maxValue;
|
|
data[offset + i].b = ReadElementAsUint(bufferData, i * stride + dataTypeSize * 2, componentType) / maxValue;
|
|
data[offset + i].a = dataType == OVRGLTFType.VEC3 ? 1.0f : ReadElementAsUint(bufferData, i * stride + dataTypeSize * 3, componentType) / maxValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadAsMatrix4x4(OVRBinaryChunk chunk, ref Matrix4x4[] data, int offset, Vector3 conversionScale)
|
|
{
|
|
if (dataType != OVRGLTFType.MAT4)
|
|
{
|
|
Debug.LogError("Tried to read non-vec3 data as a vec3 array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * 16;
|
|
|
|
Matrix4x4 scale = Matrix4x4.Scale(conversionScale);
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
for (int m = 0; m < 16; m++)
|
|
{
|
|
data[offset + i][m] = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * m);
|
|
}
|
|
data[offset + i] = scale * data[offset + i] * scale;
|
|
}
|
|
}
|
|
|
|
public byte[] ReadAsKtxTexture(OVRBinaryChunk chunk)
|
|
{
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return null;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
return bufferData;
|
|
}
|
|
|
|
public void ReadAsBoneWeights(OVRBinaryChunk chunk, ref Vector4[] data, int offset)
|
|
{
|
|
if (dataType != OVRGLTFType.VEC4)
|
|
{
|
|
Debug.LogError("Tried to read bone weights data as a non-vec4 array.");
|
|
return;
|
|
}
|
|
|
|
if (chunk.chunkLength != bufferLength)
|
|
{
|
|
Debug.LogError("Chunk length is not equal to buffer length.");
|
|
return;
|
|
}
|
|
|
|
byte[] bufferData = new byte[byteLength];
|
|
|
|
chunk.chunkStream.Seek(chunk.chunkStart + byteOffset + additionalOffset, SeekOrigin.Begin);
|
|
chunk.chunkStream.Read(bufferData, 0, byteLength);
|
|
|
|
int dataTypeSize = GetStrideForType(componentType);
|
|
int stride = byteStride > 0 ? byteStride : dataTypeSize * 4;
|
|
for (int i = 0; i < dataCount; i++)
|
|
{
|
|
data[offset + i].x = ReadElementAsFloat(bufferData, i * stride);
|
|
data[offset + i].y = ReadElementAsFloat(bufferData, i * stride + dataTypeSize);
|
|
data[offset + i].z = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 2);
|
|
data[offset + i].w = ReadElementAsFloat(bufferData, i * stride + dataTypeSize * 3);
|
|
|
|
float weightSum = data[offset + i].x + data[offset + i].y + data[offset + i].z + data[offset + i].w;
|
|
if (!Mathf.Approximately(weightSum, 0))
|
|
{
|
|
data[offset + i] /= weightSum;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int GetStrideForType(OVRGLTFComponentType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case OVRGLTFComponentType.BYTE:
|
|
return sizeof(sbyte);
|
|
case OVRGLTFComponentType.UNSIGNED_BYTE:
|
|
return sizeof(byte);
|
|
case OVRGLTFComponentType.SHORT:
|
|
return sizeof(short);
|
|
case OVRGLTFComponentType.UNSIGNED_SHORT:
|
|
return sizeof(ushort);
|
|
case OVRGLTFComponentType.UNSIGNED_INT:
|
|
return sizeof(uint);
|
|
case OVRGLTFComponentType.FLOAT:
|
|
return sizeof(float);
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private float GetMaxValueForType(OVRGLTFComponentType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case OVRGLTFComponentType.BYTE:
|
|
return sbyte.MaxValue;
|
|
case OVRGLTFComponentType.UNSIGNED_BYTE:
|
|
return byte.MaxValue;
|
|
case OVRGLTFComponentType.SHORT:
|
|
return short.MaxValue;
|
|
case OVRGLTFComponentType.UNSIGNED_SHORT:
|
|
return ushort.MaxValue;
|
|
case OVRGLTFComponentType.UNSIGNED_INT:
|
|
return uint.MaxValue;
|
|
case OVRGLTFComponentType.FLOAT:
|
|
return float.MaxValue;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private uint ReadElementAsUint(byte[] data, int index, OVRGLTFComponentType type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case OVRGLTFComponentType.BYTE:
|
|
return (uint)Convert.ToSByte(data[index]);
|
|
case OVRGLTFComponentType.UNSIGNED_BYTE:
|
|
return data[index];
|
|
case OVRGLTFComponentType.SHORT:
|
|
return (uint)BitConverter.ToInt16(data, index);
|
|
case OVRGLTFComponentType.UNSIGNED_SHORT:
|
|
return BitConverter.ToUInt16(data, index);
|
|
case OVRGLTFComponentType.UNSIGNED_INT:
|
|
return BitConverter.ToUInt32(data, index);
|
|
default:
|
|
Debug.Log(String.Format("Failed to read Component Type {0} as a uint.", type));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private float ReadElementAsFloat(byte[] data, int index)
|
|
{
|
|
return BitConverter.ToSingle(data, index);
|
|
}
|
|
}
|