mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
refactored & improved shaders and materials
This commit is contained in:
parent
b8d731c3ae
commit
86c3eba85f
|
|
@ -1,118 +1,136 @@
|
|||
#version 330 core
|
||||
#define MAX_UV_COUNT 8
|
||||
|
||||
in vec3 fPos;
|
||||
in vec3 fNormal;
|
||||
in vec3 fTangent;
|
||||
in vec2 fTexCoords;
|
||||
in float fTexLayer;
|
||||
in vec4 fColor;
|
||||
|
||||
struct Material {
|
||||
sampler2D diffuseMap[8];
|
||||
sampler2D normalMap[8];
|
||||
sampler2D specularMap[8];
|
||||
sampler2D emissionMap[8];
|
||||
|
||||
bool useSpecularMap;
|
||||
|
||||
bool hasDiffuseColor;
|
||||
vec4 diffuseColor;
|
||||
|
||||
vec4 emissionColor[8];
|
||||
|
||||
float metallic_value;
|
||||
float roughness_value;
|
||||
struct Texture
|
||||
{
|
||||
sampler2D Sampler;
|
||||
vec4 Color;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
vec3 position;
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
struct Boost
|
||||
{
|
||||
vec3 Color;
|
||||
float Exponent;
|
||||
};
|
||||
|
||||
uniform Material material;
|
||||
uniform Light light;
|
||||
uniform vec3 viewPos;
|
||||
uniform bool display_vertex_colors;
|
||||
uniform int numTexCoords;
|
||||
struct Mask
|
||||
{
|
||||
sampler2D Sampler;
|
||||
Boost SkinBoost;
|
||||
|
||||
float AmbientOcclusion;
|
||||
float Cavity;
|
||||
};
|
||||
|
||||
struct Parameters
|
||||
{
|
||||
Texture Diffuse[MAX_UV_COUNT];
|
||||
Texture Normals[MAX_UV_COUNT];
|
||||
Texture SpecularMasks[MAX_UV_COUNT];
|
||||
Texture Emissive[MAX_UV_COUNT];
|
||||
|
||||
Mask M;
|
||||
bool HasM;
|
||||
|
||||
float Roughness;
|
||||
float SpecularMult;
|
||||
float EmissiveMult;
|
||||
|
||||
float UVScale;
|
||||
};
|
||||
|
||||
uniform Parameters uParameters;
|
||||
uniform int uNumTexCoords;
|
||||
uniform vec3 uViewPos;
|
||||
uniform bool bVertexColors;
|
||||
uniform bool bVertexNormals;
|
||||
uniform bool bVertexTangent;
|
||||
uniform bool bVertexTexCoords;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
int LayerToIndex()
|
||||
{
|
||||
return min(int(fTexLayer), numTexCoords - 1);
|
||||
return min(int(fTexLayer), uNumTexCoords - 1);
|
||||
}
|
||||
|
||||
vec4 SamplerSelector(sampler2D array[8])
|
||||
vec4 SamplerToVector(sampler2D s)
|
||||
{
|
||||
return texture(array[LayerToIndex()], fTexCoords);
|
||||
return texture(s, fTexCoords * uParameters.UVScale);
|
||||
}
|
||||
|
||||
vec4 VectorSelector(vec4 array[8])
|
||||
vec3 ComputeNormals(int layer)
|
||||
{
|
||||
return array[LayerToIndex()];
|
||||
}
|
||||
vec3 normal = SamplerToVector(uParameters.Normals[layer].Sampler).rgb * 2.0 - 1.0;
|
||||
|
||||
vec3 getNormalFromMap()
|
||||
{
|
||||
vec3 tangentNormal = SamplerSelector(material.normalMap).xyz * 2.0 - 1.0;
|
||||
|
||||
vec3 q1 = dFdx(fPos);
|
||||
vec3 q2 = dFdy(fPos);
|
||||
vec2 st1 = dFdx(fTexCoords);
|
||||
vec2 st2 = dFdy(fTexCoords);
|
||||
|
||||
vec3 n = normalize(fNormal);
|
||||
vec3 t = normalize(q1*st2.t - q2*st1.t);
|
||||
vec3 t = normalize(fTangent);
|
||||
vec3 n = normalize(fNormal);
|
||||
vec3 b = -normalize(cross(n, t));
|
||||
mat3 tbn = mat3(t, b, n);
|
||||
|
||||
return normalize(tbn * tangentNormal);
|
||||
return normalize(tbn * normal);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (display_vertex_colors)
|
||||
if (bVertexColors)
|
||||
{
|
||||
FragColor = fColor;
|
||||
}
|
||||
else if (bVertexNormals)
|
||||
{
|
||||
FragColor = vec4(fNormal, 1);
|
||||
}
|
||||
else if (bVertexTangent)
|
||||
{
|
||||
FragColor = vec4(fTangent, 1);
|
||||
}
|
||||
else if (bVertexTexCoords)
|
||||
{
|
||||
FragColor = vec4(fTexCoords, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3 n_normal_map = getNormalFromMap();
|
||||
vec3 n_light_direction = normalize(light.position - fPos);
|
||||
float diff = max(dot(n_normal_map, n_light_direction), 0.0f);
|
||||
int layer = LayerToIndex();
|
||||
vec4 diffuse = SamplerToVector(uParameters.Diffuse[layer].Sampler);
|
||||
vec3 result = uParameters.Diffuse[layer].Color.rgb * diffuse.rgb;
|
||||
|
||||
if (material.hasDiffuseColor)
|
||||
vec3 normals = ComputeNormals(layer);
|
||||
vec3 light_direction = normalize(uViewPos - fPos);
|
||||
result += max(dot(normals, light_direction), 0.0f) * result;
|
||||
|
||||
if (uParameters.HasM)
|
||||
{
|
||||
vec4 result = vec4(light.ambient, 1.0) * material.diffuseColor;
|
||||
result += vec4(light.diffuse, 1.0) * diff * material.diffuseColor;
|
||||
FragColor = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec4 diffuse_map = SamplerSelector(material.diffuseMap);
|
||||
vec3 diffuse_no_alpha = vec3(diffuse_map);
|
||||
vec3 result = light.ambient * diffuse_no_alpha;
|
||||
vec3 m = SamplerToVector(uParameters.M.Sampler).rgb;
|
||||
float subsurface = clamp(m.b * .04f, 0.0f, 1.0f);
|
||||
|
||||
// diffuse
|
||||
result += light.diffuse * diff * diffuse_no_alpha;
|
||||
|
||||
// specular
|
||||
if (material.useSpecularMap)
|
||||
if (subsurface > 0.0f && uParameters.M.SkinBoost.Exponent > 0.0f)
|
||||
{
|
||||
vec3 n_view_direction = normalize(viewPos - fPos);
|
||||
vec3 reflect_direction = reflect(-n_light_direction, n_normal_map);
|
||||
float metallic = pow(max(dot(n_view_direction, reflect_direction), 0.0f), material.metallic_value);
|
||||
vec3 specular_map = vec3(SamplerSelector(material.specularMap));
|
||||
result += specular_map.r * light.specular * (metallic * specular_map.g);
|
||||
result += material.roughness_value * specular_map.b;
|
||||
vec3 color = pow(uParameters.M.SkinBoost.Exponent, 2) * uParameters.M.SkinBoost.Color;
|
||||
result *= clamp(color * m.b, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
// emission
|
||||
vec3 emission_map = vec3(SamplerSelector(material.emissionMap));
|
||||
result += VectorSelector(material.emissionColor).rgb * emission_map;
|
||||
|
||||
FragColor = vec4(result, 1.0);
|
||||
result *= m.r * uParameters.M.AmbientOcclusion;
|
||||
result += m.g * uParameters.M.Cavity;
|
||||
}
|
||||
|
||||
vec3 reflect_direction = reflect(-light_direction, normals);
|
||||
vec3 specular_masks = SamplerToVector(uParameters.SpecularMasks[layer].Sampler).rgb;
|
||||
float specular = uParameters.SpecularMult * max(0.0f, specular_masks.r);
|
||||
float metallic = max(0.0f, dot(light_direction, reflect_direction) * specular_masks.g);
|
||||
float roughness = max(0.0f, uParameters.Roughness * specular_masks.b);
|
||||
result += metallic * roughness * specular;
|
||||
|
||||
vec4 emissive = SamplerToVector(uParameters.Emissive[layer].Sampler);
|
||||
result += uParameters.Emissive[layer].Color.rgb * emissive.rgb * uParameters.EmissiveMult;
|
||||
|
||||
FragColor = vec4(result, 1.0f);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
layout (location = 1) in vec3 vPos;
|
||||
layout (location = 2) in vec3 vNormal;
|
||||
layout (location = 3) in vec2 vTexCoords;
|
||||
layout (location = 4) in float vTexLayer;
|
||||
layout (location = 5) in vec4 vColor;
|
||||
layout (location = 6) in ivec4 vBoneIds;
|
||||
layout (location = 7) in vec4 vWeights;
|
||||
layout (location = 8) in mat4 vInstanceMatrix;
|
||||
layout (location = 12) in vec3 vMorphTarget;
|
||||
layout (location = 3) in vec3 vTangent;
|
||||
layout (location = 4) in vec2 vTexCoords;
|
||||
layout (location = 5) in float vTexLayer;
|
||||
layout (location = 6) in vec4 vColor;
|
||||
layout (location = 7) in ivec4 vBoneIds;
|
||||
layout (location = 8) in vec4 vWeights;
|
||||
layout (location = 9) in mat4 vInstanceMatrix;
|
||||
layout (location = 13) in vec3 vMorphTarget;
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform mat4 uProjection;
|
||||
|
|
@ -16,6 +17,7 @@ uniform float uMorphTime;
|
|||
|
||||
out vec3 fPos;
|
||||
out vec3 fNormal;
|
||||
out vec3 fTangent;
|
||||
out vec2 fTexCoords;
|
||||
out float fTexLayer;
|
||||
out vec4 fColor;
|
||||
|
|
@ -27,6 +29,7 @@ void main()
|
|||
|
||||
fPos = vec3(vInstanceMatrix * vec4(pos, 1.0));
|
||||
fNormal = mat3(transpose(inverse(vInstanceMatrix))) * vNormal;
|
||||
fTangent = mat3(transpose(inverse(vInstanceMatrix))) * vTangent;
|
||||
fTexCoords = vTexCoords;
|
||||
fTexLayer = vTexLayer;
|
||||
fColor = vColor;
|
||||
|
|
|
|||
|
|
@ -2,20 +2,20 @@
|
|||
|
||||
layout (location = 1) in vec3 vPos;
|
||||
layout (location = 2) in vec3 vNormal;
|
||||
layout (location = 8) in mat4 vInstanceMatrix;
|
||||
layout (location = 12) in vec3 vMorphTarget;
|
||||
layout (location = 9) in mat4 vInstanceMatrix;
|
||||
layout (location = 13) in vec3 vMorphTarget;
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform vec3 uViewPos;
|
||||
uniform mat4 uProjection;
|
||||
uniform float uMorphTime;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 pos = vec3(vInstanceMatrix * vec4(mix(vPos, vMorphTarget, uMorphTime), 1.0));
|
||||
vec3 nor = mat3(transpose(inverse(vInstanceMatrix))) * vNormal;
|
||||
|
||||
float scaleFactor = distance(pos, viewPos) * 0.0025;
|
||||
float scaleFactor = distance(pos, uViewPos) * 0.0025;
|
||||
vec3 scaleVertex = pos + nor * scaleFactor;
|
||||
gl_Position = uProjection * uView * vec4(scaleVertex, 1.0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#version 330 core
|
||||
|
||||
layout (location = 1) in vec3 vPos;
|
||||
layout (location = 8) in mat4 vInstanceMatrix;
|
||||
layout (location = 12) in vec3 vMorphTarget;
|
||||
layout (location = 9) in mat4 vInstanceMatrix;
|
||||
layout (location = 13) in vec3 vMorphTarget;
|
||||
|
||||
uniform mat4 uView;
|
||||
uniform mat4 uProjection;
|
||||
|
|
|
|||
|
|
@ -56,24 +56,6 @@ public class Cache : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void Render(Shader shader)
|
||||
{
|
||||
foreach (var model in Models.Values)
|
||||
{
|
||||
if (!model.Show) continue;
|
||||
model.Render(shader);
|
||||
}
|
||||
}
|
||||
|
||||
public void Outline(Shader shader)
|
||||
{
|
||||
foreach (var model in Models.Values)
|
||||
{
|
||||
if (!model.IsSelected || !model.Show) continue;
|
||||
model.Outline(shader);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeModels()
|
||||
{
|
||||
foreach (var model in Models.Values)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -22,12 +23,17 @@ public class Material : IDisposable
|
|||
public Texture[] SpecularMasks;
|
||||
public Texture[] Emissive;
|
||||
|
||||
public Vector4 DiffuseColor;
|
||||
public Vector4[] EmissionColor;
|
||||
public bool HasSpecularMap;
|
||||
public bool HasDiffuseColor;
|
||||
public Vector4[] DiffuseColor;
|
||||
public Vector4[] EmissiveColor;
|
||||
|
||||
private Vector3 _ambientLight;
|
||||
public Mask M;
|
||||
public bool HasM;
|
||||
|
||||
public float Roughness;
|
||||
public float SpecularMult = 1f;
|
||||
public float EmissiveMult = 1f;
|
||||
|
||||
public float UVScale = 1f;
|
||||
|
||||
public Material()
|
||||
{
|
||||
|
|
@ -39,13 +45,7 @@ public class Material : IDisposable
|
|||
Normals = Array.Empty<Texture>();
|
||||
SpecularMasks = Array.Empty<Texture>();
|
||||
Emissive = Array.Empty<Texture>();
|
||||
|
||||
DiffuseColor = Vector4.Zero;
|
||||
EmissionColor = Array.Empty<Vector4>();
|
||||
HasSpecularMap = false;
|
||||
HasDiffuseColor = false;
|
||||
|
||||
_ambientLight = Vector3.One;
|
||||
EmissiveColor = Array.Empty<Vector4>();
|
||||
}
|
||||
|
||||
public Material(UMaterialInterface unrealMaterial) : this()
|
||||
|
|
@ -65,7 +65,7 @@ public class Material : IDisposable
|
|||
|
||||
if (Parameters.IsNull)
|
||||
{
|
||||
DiffuseColor = new Vector4(1, 0, 0, 1);
|
||||
Diffuse = new[] { new Texture(new FLinearColor(1f, 0f, 0f, 1f)) };
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -74,29 +74,53 @@ public class Material : IDisposable
|
|||
Fill(cache, numTexCoords, ref SpecularMasks, true, CMaterialParams2.SpecularMasks, CMaterialParams2.FallbackSpecularMasks);
|
||||
Fill(cache, numTexCoords, ref Emissive, true, CMaterialParams2.Emissive, CMaterialParams2.FallbackEmissive);
|
||||
|
||||
// if (Parameters.Colors.TryGetValue("ColorMult", out var color) && color is { A: > 0})
|
||||
// {
|
||||
// DiffuseColor = new Vector4(color.R, color.G, color.B, color.A);
|
||||
// }
|
||||
if (Parameters.TryGetTexture2d(out var o, "M") && cache.TryGetCachedTexture(o, out var t))
|
||||
{
|
||||
M = new Mask { Texture = t, AmbientOcclusion = 0.7f };
|
||||
HasM = true;
|
||||
if (Parameters.TryGetLinearColor(out var l, "Skin Boost Color And Exponent"))
|
||||
M.SkinBoost = new Boost { Color = new Vector3(l.R, l.G, l.B), Exponent = l.A };
|
||||
}
|
||||
|
||||
EmissionColor = new Vector4[numTexCoords];
|
||||
for (int i = 0; i < EmissionColor.Length; i++)
|
||||
if (Parameters.TryGetScalar(out var roughnessMin, "RoughnessMin", "SpecRoughnessMin") &&
|
||||
Parameters.TryGetScalar(out var roughnessMax, "RoughnessMax", "SpecRoughnessMax"))
|
||||
Roughness = (roughnessMin + roughnessMax) / 2f;
|
||||
if (Parameters.TryGetScalar(out var roughness, "Rough", "Roughness"))
|
||||
Roughness = roughness;
|
||||
|
||||
if (Parameters.TryGetScalar(out var specularMult, "SpecularMult"))
|
||||
SpecularMult = specularMult;
|
||||
if (Parameters.TryGetScalar(out var emissiveMult, "emissive mult", "Emissive_Mult"))
|
||||
EmissiveMult = emissiveMult;
|
||||
|
||||
if (Parameters.TryGetScalar(out var uvScale, "UV Scale"))
|
||||
UVScale = uvScale;
|
||||
|
||||
DiffuseColor = new Vector4[numTexCoords];
|
||||
for (int i = 0; i < DiffuseColor.Length; i++)
|
||||
{
|
||||
if (Diffuse[i] == null) continue;
|
||||
|
||||
if (Parameters.TryGetLinearColor(out var color, "ColorMult", "Color_mul", "Color") && color is { A: > 0 })
|
||||
{
|
||||
DiffuseColor[i] = new Vector4(color.R, color.G, color.B, color.A);
|
||||
}
|
||||
else DiffuseColor[i] = new Vector4(0.5f);
|
||||
}
|
||||
|
||||
EmissiveColor = new Vector4[numTexCoords];
|
||||
for (int i = 0; i < EmissiveColor.Length; i++)
|
||||
{
|
||||
if (Emissive[i] == null) continue;
|
||||
|
||||
if (Parameters.TryGetLinearColor(out var color, $"Emissive{(i > 0 ? i + 1 : "")}") && color is { A: > 0 })
|
||||
string[] names = i == 0 ? new[] { "Emissive", "EmissiveColor", "Emissive Color" } : new[] { $"Emissive{i + 1}" };
|
||||
if (Parameters.TryGetLinearColor(out var color, names) && color is { A: > 0 })
|
||||
{
|
||||
EmissionColor[i] = new Vector4(color.R, color.G, color.B, color.A);
|
||||
EmissiveColor[i] = new Vector4(color.R, color.G, color.B, color.A);
|
||||
}
|
||||
else EmissionColor[i] = Vector4.One;
|
||||
else EmissiveColor[i] = Vector4.One;
|
||||
}
|
||||
|
||||
// diffuse light is based on normal map, so increase ambient if no normal map
|
||||
_ambientLight = new Vector3(Normals[0] == null ? 1.0f : 0.2f);
|
||||
HasSpecularMap = SpecularMasks[0] != null;
|
||||
}
|
||||
|
||||
HasDiffuseColor = DiffuseColor != Vector4.Zero;
|
||||
}
|
||||
|
||||
/// <param name="cache"></param>
|
||||
|
|
@ -118,11 +142,6 @@ public class Material : IDisposable
|
|||
array[i] = array[i - 1];
|
||||
}
|
||||
}
|
||||
else if (Parameters.Colors.TryGetValue("Color", out var linearColor)) // POC
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
array[i] = new Texture(linearColor);
|
||||
}
|
||||
else if (Parameters.Textures.TryGetValue(fallback, out var u) && u is UTexture2D o && cache.TryGetCachedTexture(o, out var t))
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
|
|
@ -138,41 +157,45 @@ public class Material : IDisposable
|
|||
public void Render(Shader shader)
|
||||
{
|
||||
var unit = 0;
|
||||
|
||||
for (var i = 0; i < Diffuse.Length; i++)
|
||||
{
|
||||
shader.SetUniform($"material.diffuseMap[{i}]", unit);
|
||||
shader.SetUniform($"uParameters.Diffuse[{i}].Sampler", unit);
|
||||
shader.SetUniform($"uParameters.Diffuse[{i}].Color", DiffuseColor[i]);
|
||||
Diffuse[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Normals.Length; i++)
|
||||
{
|
||||
shader.SetUniform($"material.normalMap[{i}]", unit);
|
||||
shader.SetUniform($"uParameters.Normals[{i}].Sampler", unit);
|
||||
Normals[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
for (var i = 0; i < SpecularMasks.Length; i++)
|
||||
{
|
||||
shader.SetUniform($"material.specularMap[{i}]", unit);
|
||||
shader.SetUniform($"uParameters.SpecularMasks[{i}].Sampler", unit);
|
||||
SpecularMasks[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Emissive.Length; i++)
|
||||
{
|
||||
shader.SetUniform($"material.emissionMap[{i}]", unit);
|
||||
shader.SetUniform($"material.emissionColor[{i}]", EmissionColor[i]);
|
||||
shader.SetUniform($"uParameters.Emissive[{i}].Sampler", unit);
|
||||
shader.SetUniform($"uParameters.Emissive[{i}].Color", EmissiveColor[i]);
|
||||
Emissive[i]?.Bind(TextureUnit.Texture0 + unit++);
|
||||
}
|
||||
|
||||
shader.SetUniform("material.useSpecularMap", HasSpecularMap);
|
||||
M.Texture?.Bind(TextureUnit.Texture31);
|
||||
shader.SetUniform("uParameters.M.Sampler", 31);
|
||||
shader.SetUniform("uParameters.M.SkinBoost.Color", M.SkinBoost.Color);
|
||||
shader.SetUniform("uParameters.M.SkinBoost.Exponent", M.SkinBoost.Exponent);
|
||||
shader.SetUniform("uParameters.M.AmbientOcclusion", M.AmbientOcclusion);
|
||||
shader.SetUniform("uParameters.M.Cavity", M.Cavity);
|
||||
shader.SetUniform("uParameters.HasM", HasM);
|
||||
|
||||
shader.SetUniform("material.hasDiffuseColor", HasDiffuseColor);
|
||||
shader.SetUniform("material.diffuseColor", DiffuseColor);
|
||||
shader.SetUniform("uParameters.Roughness", Roughness);
|
||||
shader.SetUniform("uParameters.SpecularMult", SpecularMult);
|
||||
shader.SetUniform("uParameters.EmissiveMult", EmissiveMult);
|
||||
|
||||
shader.SetUniform("material.metallic_value", 1f);
|
||||
shader.SetUniform("material.roughness_value", 0f);
|
||||
|
||||
shader.SetUniform("light.ambient", _ambientLight);
|
||||
shader.SetUniform("uParameters.UVScale", UVScale);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -193,6 +216,22 @@ public class Material : IDisposable
|
|||
{
|
||||
Emissive[i]?.Dispose();
|
||||
}
|
||||
M.Texture?.Dispose();
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
}
|
||||
|
||||
public struct Mask
|
||||
{
|
||||
public Texture Texture;
|
||||
public Boost SkinBoost;
|
||||
|
||||
public float AmbientOcclusion;
|
||||
public float Cavity;
|
||||
}
|
||||
|
||||
public struct Boost
|
||||
{
|
||||
public Vector3 Color;
|
||||
public float Exponent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class Model : IDisposable
|
|||
private BufferObject<Matrix4x4> _matrixVbo;
|
||||
private VertexArrayObject<float, uint> _vao;
|
||||
|
||||
private readonly int _vertexSize = 10; // VertexIndex + Position + Normal + UV + TextureLayer
|
||||
private readonly int _vertexSize = 13; // VertexIndex + Position + Normal + Tangent + UV + TextureLayer
|
||||
private readonly uint[] _facesIndex = { 1, 0, 2 };
|
||||
private const int _faceSize = 3; // just so we don't have to do .Length
|
||||
|
||||
|
|
@ -46,7 +46,10 @@ public class Model : IDisposable
|
|||
public bool Wireframe;
|
||||
public bool IsSetup;
|
||||
public bool IsSelected;
|
||||
public bool DisplayVertexColors;
|
||||
public bool bVertexColors;
|
||||
public bool bVertexNormals;
|
||||
public bool bVertexTangent;
|
||||
public bool bVertexTexCoords;
|
||||
public bool DisplayBones;
|
||||
public int SelectedInstance;
|
||||
public float MorphTime;
|
||||
|
|
@ -127,6 +130,9 @@ public class Model : IDisposable
|
|||
Vertices[baseIndex + count++] = vert.Normal.X;
|
||||
Vertices[baseIndex + count++] = vert.Normal.Z;
|
||||
Vertices[baseIndex + count++] = vert.Normal.Y;
|
||||
Vertices[baseIndex + count++] = vert.Tangent.X;
|
||||
Vertices[baseIndex + count++] = vert.Tangent.Z;
|
||||
Vertices[baseIndex + count++] = vert.Tangent.Y;
|
||||
Vertices[baseIndex + count++] = vert.UV.U;
|
||||
Vertices[baseIndex + count++] = vert.UV.V;
|
||||
Vertices[baseIndex + count++] = lod.ExtraUV.IsValueCreated ? lod.ExtraUV.Value[0][indice].U : .5f;
|
||||
|
|
@ -188,7 +194,7 @@ public class Model : IDisposable
|
|||
for (var i = 0; i < instanceMatrix.Length; i++)
|
||||
instanceMatrix[i] = Transforms[i].Matrix;
|
||||
_matrixVbo = new BufferObject<Matrix4x4>(instanceMatrix, BufferTarget.ArrayBuffer);
|
||||
_vao.BindInstancing(); // VertexAttributePointer 7, 8, 9, 10
|
||||
_vao.BindInstancing(); // VertexAttributePointer
|
||||
}
|
||||
|
||||
public void Setup(Cache cache)
|
||||
|
|
@ -202,11 +208,12 @@ public class Model : IDisposable
|
|||
_vao.VertexAttributePointer(0, 1, VertexAttribPointerType.Int, _vertexSize, 0); // vertex index
|
||||
_vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 1); // position
|
||||
_vao.VertexAttributePointer(2, 3, VertexAttribPointerType.Float, _vertexSize, 4); // normal
|
||||
_vao.VertexAttributePointer(3, 2, VertexAttribPointerType.Float, _vertexSize, 7); // uv
|
||||
_vao.VertexAttributePointer(4, 1, VertexAttribPointerType.Float, _vertexSize, 9); // texture index
|
||||
_vao.VertexAttributePointer(5, 4, VertexAttribPointerType.Float, _vertexSize, 10); // color
|
||||
_vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Int, _vertexSize, 14); // boneids
|
||||
_vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Float, _vertexSize, 18); // boneweights
|
||||
_vao.VertexAttributePointer(3, 3, VertexAttribPointerType.Float, _vertexSize, 7); // tangent
|
||||
_vao.VertexAttributePointer(4, 2, VertexAttribPointerType.Float, _vertexSize, 10); // uv
|
||||
_vao.VertexAttributePointer(5, 1, VertexAttribPointerType.Float, _vertexSize, 12); // texture index
|
||||
_vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Float, _vertexSize, 13); // color
|
||||
_vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Int, _vertexSize, 17); // boneids
|
||||
_vao.VertexAttributePointer(8, 4, VertexAttribPointerType.Float, _vertexSize, 21); // boneweights
|
||||
|
||||
SetupInstances(); // instanced models transform
|
||||
|
||||
|
|
@ -226,7 +233,7 @@ public class Model : IDisposable
|
|||
_morphVbo = new BufferObject<float>(Morphs[morph].Vertices, BufferTarget.ArrayBuffer);
|
||||
}
|
||||
_vao.Bind();
|
||||
_vao.VertexAttributePointer(12, 3, VertexAttribPointerType.Float, 3, 0); // morph position
|
||||
_vao.VertexAttributePointer(13, 3, VertexAttribPointerType.Float, 3, 0); // morph position
|
||||
_vao.Unbind();
|
||||
}
|
||||
|
||||
|
|
@ -249,8 +256,11 @@ public class Model : IDisposable
|
|||
|
||||
_vao.Bind();
|
||||
shader.SetUniform("uMorphTime", MorphTime);
|
||||
shader.SetUniform("display_vertex_colors", DisplayVertexColors);
|
||||
shader.SetUniform("numTexCoords", NumTexCoords);
|
||||
shader.SetUniform("uNumTexCoords", NumTexCoords);
|
||||
shader.SetUniform("bVertexColors", bVertexColors);
|
||||
shader.SetUniform("bVertexNormals", bVertexNormals);
|
||||
shader.SetUniform("bVertexTangent", bVertexTangent);
|
||||
shader.SetUniform("bVertexTexCoords", bVertexTexCoords);
|
||||
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
|
|
@ -280,12 +290,11 @@ public class Model : IDisposable
|
|||
|
||||
public void Outline(Shader shader)
|
||||
{
|
||||
GL.StencilMask(0x00);
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
GL.StencilFunc(StencilFunction.Notequal, 1, 0xFF);
|
||||
|
||||
_vao.Bind();
|
||||
shader.Use();
|
||||
shader.SetUniform("uMorphTime", MorphTime);
|
||||
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
|
||||
|
|
@ -298,7 +307,7 @@ public class Model : IDisposable
|
|||
|
||||
GL.StencilFunc(StencilFunction.Always, 0, 0xFF);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.StencilMask(0xFF);
|
||||
GL.Disable(EnableCap.StencilTest);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -58,10 +58,7 @@ public class PickingTexture : IDisposable
|
|||
Bind();
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||
|
||||
_shader.Use();
|
||||
_shader.SetUniform("uView", viewMatrix);
|
||||
_shader.SetUniform("uProjection", projMatrix);
|
||||
|
||||
_shader.Render(viewMatrix, projMatrix);
|
||||
foreach ((FGuid guid, Model model) in models)
|
||||
{
|
||||
_shader.SetUniform("uA", guid.A);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ using CUE4Parse.UE4.Assets.Exports.Texture;
|
|||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using Vector3 = OpenTK.Mathematics.Vector3;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
|
@ -20,8 +19,6 @@ public class Renderer : IDisposable
|
|||
{
|
||||
private Shader _shader;
|
||||
private Shader _outline;
|
||||
private Vector3 _diffuseLight;
|
||||
private Vector3 _specularLight;
|
||||
|
||||
public PickingTexture Picking { get; }
|
||||
public Cache Cache { get; }
|
||||
|
|
@ -60,8 +57,6 @@ public class Renderer : IDisposable
|
|||
{
|
||||
_shader = new Shader();
|
||||
_outline = new Shader("outline");
|
||||
_diffuseLight = new Vector3(0.75f);
|
||||
_specularLight = new Vector3(0.5f);
|
||||
|
||||
Picking.Setup();
|
||||
Cache.Setup();
|
||||
|
|
@ -72,24 +67,22 @@ public class Renderer : IDisposable
|
|||
var viewMatrix = cam.GetViewMatrix();
|
||||
var projMatrix = cam.GetProjectionMatrix();
|
||||
|
||||
_outline.Use();
|
||||
_outline.SetUniform("uView", viewMatrix);
|
||||
_outline.SetUniform("uProjection", projMatrix);
|
||||
_outline.SetUniform("viewPos", cam.Position);
|
||||
// render pass
|
||||
_shader.Render(viewMatrix, cam.Position, projMatrix);
|
||||
foreach (var model in Cache.Models.Values)
|
||||
{
|
||||
if (!model.Show) continue;
|
||||
model.Render(_shader);
|
||||
}
|
||||
|
||||
_shader.Use();
|
||||
_shader.SetUniform("uView", viewMatrix);
|
||||
_shader.SetUniform("uProjection", projMatrix);
|
||||
_shader.SetUniform("viewPos", cam.Position);
|
||||
|
||||
_shader.SetUniform("light.position", cam.Position);
|
||||
_shader.SetUniform("light.diffuse", _diffuseLight);
|
||||
_shader.SetUniform("light.specular", _specularLight);
|
||||
|
||||
Cache.Render(_shader);
|
||||
GL.Enable(EnableCap.StencilTest);
|
||||
Cache.Outline(_outline);
|
||||
// outline pass
|
||||
if (Cache.Models.TryGetValue(Settings.SelectedModel, out var selected) && selected.Show)
|
||||
{
|
||||
_outline.Render(viewMatrix, cam.Position, projMatrix);
|
||||
selected.Outline(_outline);
|
||||
}
|
||||
|
||||
// picking pass (dedicated FBO, binding to 0 afterward)
|
||||
Picking.Render(viewMatrix, projMatrix, Cache.Models);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
|
@ -35,11 +35,40 @@ public class Shader : IDisposable
|
|||
GL.DeleteShader(f);
|
||||
}
|
||||
|
||||
private int LoadShader(ShaderType type, string file)
|
||||
{
|
||||
var executingAssembly = Assembly.GetExecutingAssembly();
|
||||
using var stream = executingAssembly.GetManifestResourceStream($"{executingAssembly.GetName().Name}.Resources.{file}");
|
||||
using var reader = new StreamReader(stream);
|
||||
var handle = GL.CreateShader(type);
|
||||
GL.ShaderSource(handle, reader.ReadToEnd());
|
||||
GL.CompileShader(handle);
|
||||
string infoLog = GL.GetShaderInfoLog(handle);
|
||||
if (!string.IsNullOrWhiteSpace(infoLog))
|
||||
{
|
||||
throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}");
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
public void Use()
|
||||
{
|
||||
GL.UseProgram(_handle);
|
||||
}
|
||||
|
||||
public void Render(Matrix4 viewMatrix, Vector3 viewPos, Matrix4 projMatrix)
|
||||
{
|
||||
Render(viewMatrix, projMatrix);
|
||||
SetUniform("uViewPos", viewPos);
|
||||
}
|
||||
public void Render(Matrix4 viewMatrix, Matrix4 projMatrix)
|
||||
{
|
||||
Use();
|
||||
SetUniform("uView", viewMatrix);
|
||||
SetUniform("uProjection", projMatrix);
|
||||
}
|
||||
|
||||
public void SetUniform(string name, int value)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
|
|
@ -83,24 +112,28 @@ public class Shader : IDisposable
|
|||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
public void SetUniform(string name, Vector3 value)
|
||||
public void SetUniform(string name, Vector3 value) => SetUniform3(name, value.X, value.Y, value.Z);
|
||||
public void SetUniform(string name, System.Numerics.Vector3 value) => SetUniform3(name, value.X, value.Y, value.Z);
|
||||
public void SetUniform3(string name, float x, float y, float z)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
GL.Uniform3(location, value.X, value.Y, value.Z);
|
||||
GL.Uniform3(location, x, y, z);
|
||||
}
|
||||
|
||||
public void SetUniform(string name, Vector4 value)
|
||||
public void SetUniform(string name, Vector4 value) => SetUniform4(name, value.X, value.Y, value.Z, value.W);
|
||||
public void SetUniform(string name, System.Numerics.Vector4 value) => SetUniform4(name, value.X, value.Y, value.Z, value.W);
|
||||
public void SetUniform4(string name, float x, float y, float z, float w)
|
||||
{
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
if (location == -1)
|
||||
{
|
||||
throw new Exception($"{name} uniform not found on shader.");
|
||||
}
|
||||
GL.Uniform4(location, value.X, value.Y, value.Z, value.W);
|
||||
GL.Uniform4(location, x, y, z, w);
|
||||
}
|
||||
|
||||
public int GetUniformLocation(string uniform)
|
||||
|
|
@ -135,21 +168,4 @@ public class Shader : IDisposable
|
|||
{
|
||||
GL.DeleteProgram(_handle);
|
||||
}
|
||||
|
||||
private int LoadShader(ShaderType type, string file)
|
||||
{
|
||||
var executingAssembly = Assembly.GetExecutingAssembly();
|
||||
using var stream = executingAssembly.GetManifestResourceStream($"{executingAssembly.GetName().Name}.Resources.{file}");
|
||||
using var reader = new StreamReader(stream);
|
||||
var handle = GL.CreateShader(type);
|
||||
GL.ShaderSource(handle, reader.ReadToEnd());
|
||||
GL.CompileShader(handle);
|
||||
string infoLog = GL.GetShaderInfoLog(handle);
|
||||
if (!string.IsNullOrWhiteSpace(infoLog))
|
||||
{
|
||||
throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}");
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using FModel.Framework;
|
||||
using ImGuiNET;
|
||||
|
|
@ -36,17 +38,51 @@ public class SnimGui
|
|||
DrawNavbar();
|
||||
|
||||
ImGui.Begin("Camera");
|
||||
ImGui.DragFloat("Speed", ref s.Camera.Speed, 0.01f);
|
||||
ImGui.DragFloat("Speed", ref s.Camera.Speed, 0.01f, 0.05f);
|
||||
ImGui.DragFloat("Far Plane", ref s.Camera.Far, 0.1f, 5f, s.Camera.Far * 2f, "%.2f m", ImGuiSliderFlags.AlwaysClamp);
|
||||
ImGui.End();
|
||||
ImGui.Begin("World");
|
||||
ImGui.End();
|
||||
ImGui.Begin("Timeline");
|
||||
ImGui.End();
|
||||
ImGui.Begin("Materials");
|
||||
ImGui.End();
|
||||
ImGui.Begin("Textures");
|
||||
ImGui.End();
|
||||
if (ImGui.Begin("Materials"))
|
||||
{
|
||||
PushStyleCompact();
|
||||
var guid = s.Renderer.Settings.SelectedModel;
|
||||
if (s.Renderer.Cache.Models.TryGetValue(guid, out var model) &&
|
||||
s.Renderer.Settings.TryGetSection(model, out var section))
|
||||
{
|
||||
var material = model.Materials[section.MaterialIndex];
|
||||
foreach ((string key, float value) in material.Parameters.Scalars)
|
||||
{
|
||||
ImGui.Text($"{key}: {value}");
|
||||
}
|
||||
ImGui.Spacing(); ImGui.Separator(); ImGui.Spacing();
|
||||
foreach ((string key, FLinearColor value) in material.Parameters.Colors)
|
||||
{
|
||||
ImGui.Text(key); ImGui.SameLine();
|
||||
ImGui.ColorButton(key, new Vector4(value.R, value.G, value.B, value.A));
|
||||
}
|
||||
}
|
||||
else NoMeshSelected();
|
||||
PopStyleCompact();
|
||||
}
|
||||
if (ImGui.Begin("Textures"))
|
||||
{
|
||||
PushStyleCompact();
|
||||
var guid = s.Renderer.Settings.SelectedModel;
|
||||
if (s.Renderer.Cache.Models.TryGetValue(guid, out var model) &&
|
||||
s.Renderer.Settings.TryGetSection(model, out var section))
|
||||
{
|
||||
var material = model.Materials[section.MaterialIndex];
|
||||
foreach ((string key, UUnrealMaterial value) in material.Parameters.Textures)
|
||||
{
|
||||
ImGui.Text($"{key}: {value.Name}");
|
||||
}
|
||||
}
|
||||
else NoMeshSelected();
|
||||
PopStyleCompact();
|
||||
}
|
||||
|
||||
DrawUvChannels(s);
|
||||
DrawTransform(s);
|
||||
|
|
@ -170,7 +206,7 @@ public class SnimGui
|
|||
ImGui.Text($"Entity: ({model.Type}) {model.Name}");
|
||||
ImGui.Text($"Guid: {guid.ToString(EGuidFormats.UniqueObjectGuid)}");
|
||||
|
||||
ImGui.Columns(4, "Actions", false);
|
||||
ImGui.Columns(3, "Actions", false);
|
||||
if (ImGui.Button("Go To"))
|
||||
{
|
||||
var instancePos = model.Transforms[model.SelectedInstance].Position;
|
||||
|
|
@ -178,7 +214,11 @@ public class SnimGui
|
|||
}
|
||||
ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show);
|
||||
ImGui.NextColumn(); ImGui.BeginDisabled(!model.Show); ImGui.Checkbox("Wire", ref model.Wireframe); ImGui.EndDisabled();
|
||||
ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.DisplayVertexColors); ImGui.EndDisabled();
|
||||
ImGui.Columns(4);
|
||||
ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.bVertexColors); ImGui.EndDisabled();
|
||||
ImGui.NextColumn(); ImGui.Checkbox("Normals", ref model.bVertexNormals);
|
||||
ImGui.NextColumn(); ImGui.Checkbox("Tangent", ref model.bVertexTangent);
|
||||
ImGui.NextColumn(); ImGui.Checkbox("Coords", ref model.bVertexTexCoords);
|
||||
ImGui.Columns(1);
|
||||
|
||||
ImGui.Separator();
|
||||
|
|
@ -301,6 +341,22 @@ public class SnimGui
|
|||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.Begin("test") && s.Renderer.Settings.TryGetSection(model, out var sec))
|
||||
{
|
||||
var material = model.Materials[sec.MaterialIndex];
|
||||
ImGui.DragFloat("Roughness", ref material.Roughness, .01f, 0f, 1f);
|
||||
ImGui.DragFloat("Specular Multiplier", ref material.SpecularMult, .01f, 0f);
|
||||
ImGui.DragFloat("Emissive Multiplier", ref material.EmissiveMult, .01f, 0f);
|
||||
ImGui.DragFloat("UV Scale", ref material.UVScale, .01f, 0f);
|
||||
if (material.HasM)
|
||||
{
|
||||
ImGui.ColorEdit3("Skin Boost Color", ref material.M.SkinBoost.Color);
|
||||
ImGui.DragFloat("Skin Boost Exponent", ref material.M.SkinBoost.Exponent, .01f, 0f);
|
||||
ImGui.DragFloat("AmbientOcclusion", ref material.M.AmbientOcclusion, .01f, 0f, 1f);
|
||||
ImGui.DragFloat("Cavity", ref material.M.Cavity, .01f, 0f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else NoMeshSelected();
|
||||
PopStyleCompact();
|
||||
|
|
@ -402,10 +458,11 @@ public class SnimGui
|
|||
{
|
||||
if (material.Diffuse.Length > 0)
|
||||
{
|
||||
var size = new Vector2(ImGui.GetContentRegionAvail().X / 4.75f);
|
||||
var size = new Vector2(ImGui.GetContentRegionAvail().X / 5.75f);
|
||||
DrawSquareTexture(material.Diffuse[material.SelectedChannel], size); ImGui.SameLine();
|
||||
DrawSquareTexture(material.Normals[material.SelectedChannel], size); ImGui.SameLine();
|
||||
DrawSquareTexture(material.SpecularMasks[material.SelectedChannel], size); ImGui.SameLine();
|
||||
DrawSquareTexture(material.M.Texture, size); ImGui.SameLine();
|
||||
DrawSquareTexture(material.Emissive[material.SelectedChannel], size); ImGui.SameLine();
|
||||
}
|
||||
else TextColored(_errorColor, "no texture in material section");
|
||||
|
|
@ -453,6 +510,7 @@ public class SnimGui
|
|||
{
|
||||
var guid = s.Renderer.Picking.ReadPixel(ImGui.GetMousePos(), ImGui.GetCursorScreenPos(), size);
|
||||
s.Renderer.Settings.SelectModel(guid);
|
||||
ImGui.SetWindowFocus("Outliner");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,19 +41,19 @@ public class VertexArrayObject<TVertexType, TIndexType> : IDisposable where TVer
|
|||
Bind();
|
||||
|
||||
var size = sizeof(Vector4);
|
||||
GL.EnableVertexAttribArray(8);
|
||||
GL.VertexAttribPointer(8, 4, VertexAttribPointerType.Float, false, 4 * size, 0);
|
||||
GL.EnableVertexAttribArray(9);
|
||||
GL.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * size, 1 * size);
|
||||
GL.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * size, 0);
|
||||
GL.EnableVertexAttribArray(10);
|
||||
GL.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * size, 2 * size);
|
||||
GL.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * size, 1 * size);
|
||||
GL.EnableVertexAttribArray(11);
|
||||
GL.VertexAttribPointer(11, 4, VertexAttribPointerType.Float, false, 4 * size, 3 * size);
|
||||
GL.VertexAttribPointer(11, 4, VertexAttribPointerType.Float, false, 4 * size, 2 * size);
|
||||
GL.EnableVertexAttribArray(12);
|
||||
GL.VertexAttribPointer(12, 4, VertexAttribPointerType.Float, false, 4 * size, 3 * size);
|
||||
|
||||
GL.VertexAttribDivisor(8, 1);
|
||||
GL.VertexAttribDivisor(9, 1);
|
||||
GL.VertexAttribDivisor(10, 1);
|
||||
GL.VertexAttribDivisor(11, 1);
|
||||
GL.VertexAttribDivisor(12, 1);
|
||||
|
||||
Unbind();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user