346 lines
8.1 KiB
C#
346 lines
8.1 KiB
C#
using System;
|
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
using OpenTK;
|
|
|
|
using org.budnhead.core;
|
|
using System.Collections.Generic;
|
|
|
|
namespace org.budnhead.graphics {
|
|
|
|
public class Model3D {
|
|
|
|
protected int vao = 0,
|
|
vbo, // Vertex Buffer
|
|
cbo, // Color Buffer
|
|
cbo2, // Second Color Buffer
|
|
nbo; // Normals Buffer
|
|
|
|
protected int nTriangles;
|
|
|
|
public Vector3[] vertexes = null;
|
|
public Vector4[] colors = null;
|
|
public Vector4[] colors2 = null;
|
|
public Vector3[] normals = null;
|
|
|
|
public Triangle[] triangles = new Triangle[0];
|
|
|
|
public Model3D(){
|
|
nTriangles = 0;
|
|
|
|
prepare();
|
|
}
|
|
|
|
protected void prepare(){
|
|
vao = GL.GenVertexArray();
|
|
vbo = GL.GenBuffer();
|
|
cbo = GL.GenBuffer();
|
|
cbo2 = GL.GenBuffer();
|
|
nbo = GL.GenBuffer();
|
|
|
|
GL.BindVertexArray(vao);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
|
|
GL.VertexAttribPointer(0,
|
|
3,
|
|
VertexAttribPointerType.Float,
|
|
false,
|
|
0,
|
|
0);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, cbo);
|
|
GL.VertexAttribPointer(1,
|
|
4,
|
|
VertexAttribPointerType.Float,
|
|
false,
|
|
0,
|
|
0);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, nbo);
|
|
GL.VertexAttribPointer(2,
|
|
3,
|
|
VertexAttribPointerType.Float,
|
|
false,
|
|
0,
|
|
0);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, cbo2);
|
|
GL.VertexAttribPointer(3,
|
|
4,
|
|
VertexAttribPointerType.Float,
|
|
false,
|
|
0,
|
|
0);
|
|
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
public void prepareBuffers(int nTriangles){
|
|
this.vertexes = new Vector3[nTriangles * 3];
|
|
this.normals = new Vector3[nTriangles * 3];
|
|
this.colors = new Vector4[nTriangles * 3];
|
|
this.colors2 = new Vector4[nTriangles * 3];
|
|
|
|
this.vertexes.Fill(new Vector3(0,0,0));
|
|
this.colors.Fill(new Vector4(0.5f,0.5f,0.5f,1.0f));
|
|
this.colors2.Fill(new Vector4(1.0f,1.0f,1.0f,1.0f));
|
|
|
|
this.nTriangles = nTriangles;
|
|
rebind();
|
|
}
|
|
|
|
public void bind(){
|
|
this.nTriangles = this.vertexes.Length / 3;
|
|
if (this.vertexes == null){
|
|
this.vertexes = new Vector3[nTriangles * 3];
|
|
this.vertexes.Fill(new Vector3(0,0,0));
|
|
}
|
|
if (this.normals == null){
|
|
this.normals = new Vector3[nTriangles * 3];
|
|
}
|
|
if (this.colors == null){
|
|
this.colors = new Vector4[nTriangles * 3];
|
|
this.colors.Fill(new Vector4(0.5f,0.5f,0.5f,1.0f));
|
|
}
|
|
if (this.colors2 == null){
|
|
this.colors2 = new Vector4[nTriangles * 3];
|
|
this.colors2.Fill(new Vector4(0.0f,0.0f,0.0f,1.0f));
|
|
}
|
|
rebind();
|
|
}
|
|
|
|
public void rebind(){
|
|
if (vao != 0){
|
|
prepare();
|
|
}
|
|
|
|
bindVertexes();
|
|
bindNormals();
|
|
bindColors();
|
|
bindColors2();
|
|
}
|
|
|
|
protected void bindVertexes(){
|
|
GL.BindVertexArray(vao);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, 12 * vertexes.Length, vertexes, BufferUsageHint.StaticDraw);
|
|
|
|
GL.EnableVertexAttribArray(0);
|
|
|
|
if (this.triangles.Length != nTriangles){
|
|
int nt = this.triangles.Length;
|
|
|
|
Array.Resize<Triangle>(ref this.triangles,nTriangles);
|
|
|
|
for (int n=nt;n<nTriangles;n++){
|
|
this.triangles[n] = new Triangle(this,n);
|
|
}
|
|
}
|
|
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
protected void bindNormals(){
|
|
GL.BindVertexArray(vao);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, nbo);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, 12 * normals.Length, normals, BufferUsageHint.StaticDraw);
|
|
|
|
GL.EnableVertexAttribArray(2);
|
|
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
protected void bindColors(){
|
|
GL.BindVertexArray(vao);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, cbo);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, 16 * colors.Length, colors, BufferUsageHint.StaticDraw);
|
|
|
|
GL.EnableVertexAttribArray(1);
|
|
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
protected void bindColors2(){
|
|
GL.BindVertexArray(vao);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, cbo2);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, 16 * colors2.Length, colors2, BufferUsageHint.StaticDraw);
|
|
|
|
GL.EnableVertexAttribArray(3);
|
|
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
protected void bind(Vector3[] vertexes,Vector4[] colors,Vector3[] normals,Vector2[] uvs){
|
|
if (vertexes != null){
|
|
this.vertexes = vertexes;
|
|
}
|
|
if (colors != null){
|
|
this.colors = colors;
|
|
}
|
|
if (normals != null){
|
|
this.normals = normals;
|
|
}
|
|
bindVertexes();
|
|
bindColors();
|
|
bindNormals();
|
|
}
|
|
|
|
public virtual void draw(){
|
|
GL.BindVertexArray(this.vao);
|
|
GL.DrawArrays(PrimitiveType.Triangles, 0, nTriangles * 3);
|
|
GL.BindVertexArray(0);
|
|
}
|
|
|
|
|
|
public static void setTriangle(Vector3[] vertexes,int n, Vector3 a, Vector3 b, Vector3 c)
|
|
{
|
|
vertexes[(3 * n)] = a;
|
|
vertexes[(3 * n)+1] = b;
|
|
vertexes[(3 * n)+2] = c;
|
|
}
|
|
|
|
public void computeNormals(){
|
|
if ((normals == null)||(normals.Length != vertexes.Length)){
|
|
normals = new Vector3[vertexes.Length];
|
|
}
|
|
|
|
for (int n=0;n<vertexes.Length-2;n+=3){
|
|
Vector3 normal = Vector3.Cross( vertexes[n+2] - vertexes[n], vertexes[n+1] - vertexes[n] );
|
|
normal.Normalize();
|
|
|
|
normals[(n) ] = normal;
|
|
normals[(n) + 1] = normal;
|
|
normals[(n) + 2] = normal;
|
|
}
|
|
}
|
|
|
|
public Triangle[] Triangles {
|
|
get { return this.triangles; }
|
|
}
|
|
|
|
|
|
public static Model3D loadObjFile(string filename,float scale){
|
|
return new LoadedModel(filename,scale);
|
|
}
|
|
|
|
|
|
public void smoothNormals(){
|
|
Dictionary<Vector3, List<int>> dnormals = new Dictionary<Vector3, List<int>>();
|
|
|
|
for (int n = 0; n < vertexes.Length ; n++){
|
|
if (!dnormals.ContainsKey(vertexes[n])){
|
|
dnormals.Add(vertexes[n],new List<int>());
|
|
}
|
|
|
|
dnormals[vertexes[n]].Add(n);
|
|
}
|
|
|
|
foreach (Vector3 v in dnormals.Keys){
|
|
Vector3 norm = new Vector3();
|
|
List<int> ind = dnormals[v];
|
|
foreach (int p in ind){
|
|
norm += normals[p];
|
|
}
|
|
|
|
norm /= ind.Count;
|
|
|
|
foreach (int p in ind){
|
|
normals[p] = norm;
|
|
}
|
|
}
|
|
|
|
bindNormals();
|
|
|
|
}
|
|
|
|
|
|
|
|
public class Triangle{
|
|
Model3D model;
|
|
int n;
|
|
|
|
public Triangle(Model3D model,int n){
|
|
this.model = model;
|
|
this.n = n;
|
|
}
|
|
|
|
public void vertexes(ref Vector3 a,ref Vector3 b,ref Vector3 c){
|
|
a = model.vertexes[(3*n)];
|
|
b = model.vertexes[(3*n)+1];
|
|
c = model.vertexes[(3*n)+2];
|
|
}
|
|
public void vertexes(Vector3 a,Vector3 b,Vector3 c){
|
|
model.vertexes[(3*n)] = a;
|
|
model.vertexes[(3*n)+1] = b;
|
|
model.vertexes[(3*n)+2] = c;
|
|
}
|
|
|
|
public void vertex(int a,ref Vector3 v){
|
|
v = model.vertexes[(3*n) + a];
|
|
}
|
|
public void normal(int a,ref Vector3 n){
|
|
n = model.vertexes[(3*this.n) + a];
|
|
}
|
|
public void color(int a,ref Vector4 c){
|
|
c = model.colors[(3*n)+a];
|
|
}
|
|
|
|
public Vector3 VertexA {
|
|
get { return model.vertexes[(3*n)]; }
|
|
set { model.vertexes[(3*n)] = value; }
|
|
}
|
|
public Vector3 VertexB {
|
|
get { return model.vertexes[(3*n)+1]; }
|
|
set { model.vertexes[(3*n)+1] = value; }
|
|
}
|
|
public Vector3 VertexC {
|
|
get { return model.vertexes[(3*n)+2]; }
|
|
set { model.vertexes[(3*n)+2] = value; }
|
|
}
|
|
|
|
public Vector4 ColorA {
|
|
get { return model.colors[(3*n)]; }
|
|
set { model.colors[(3*n)] = value; }
|
|
}
|
|
|
|
public Vector4 ColorB {
|
|
get { return model.colors[(3*n)+1]; }
|
|
set { model.colors[(3*n)+1] = value; }
|
|
}
|
|
|
|
public Vector4 ColorC {
|
|
get { return model.colors[(3*n)+2]; }
|
|
set { model.colors[(3*n)+2] = value; }
|
|
}
|
|
|
|
public Vector4 Color2A {
|
|
get { return model.colors2[(3*n)]; }
|
|
set { model.colors2[(3*n)] = value; }
|
|
}
|
|
|
|
public Vector4 Color2B {
|
|
get { return model.colors2[(3*n)+1]; }
|
|
set { model.colors2[(3*n)+1] = value; }
|
|
}
|
|
|
|
public Vector4 Color2C {
|
|
get { return model.colors2[(3*n)+2]; }
|
|
set { model.colors2[(3*n)+2] = value; }
|
|
}
|
|
|
|
public void updateNormals(){
|
|
Vector3 normal = Vector3.Cross( model.vertexes[(3*n)+1] - model.vertexes[(3*n)], model.vertexes[(3*n)+2] - model.vertexes[(3*n)] );
|
|
normal.Normalize();
|
|
model.normals[(3*n)] = normal;
|
|
model.normals[(3*n)+1] = normal;
|
|
model.normals[(3*n)+2] = normal;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
} |