Skip to content

Instantly share code, notes, and snippets.

@nexustheru
Created March 5, 2018 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nexustheru/d38f2c5e249df39bc6e330369c61bfa3 to your computer and use it in GitHub Desktop.
Save nexustheru/d38f2c5e249df39bc6e330369c61bfa3 to your computer and use it in GitHub Desktop.
//triangleshape
// Copyright 2006 Herre Kuijpers - <herre@xs4all.nl>
//
// This source file(s) may be redistributed, altered and customized
// by any means PROVIDING the authors name and all copyright
// notices remain intact.
// THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED. USE IT AT YOUR OWN RISK. THE AUTHOR ACCEPTS NO
// LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE.
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
namespace RayTracer
{
public class TriangleShape : BaseShape
{
public double R;
Vector v0;
Vector v1;
Vector v2;
public List<Vector> vertex = new List<Vector>();
public List<Vector> triangle = new List<Vector>();
public List<Vector> uv = new List<Vector>();
public List<Vector> normal = new List<Vector>();
public List<Vector> col = new List<Vector>();//0:diffuse,1:spec,2:reflective,3:transparent ,count from +4 i per material
private const float Epilson = 1e-06f;
public void setUv( List<Vector> uv)
{
this.uv = uv;
}
public void setNormal(List<Vector> normal)
{
this.normal = normal;
}
public void setCol(List<Vector> col)
{
this.col = col;
}
public TriangleShape()
{
}
public TriangleShape(Vector pos, double r, IMaterial material, Vector v0, Vector v1, Vector v2)
{
R = r;
Position = pos;
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
Material = material;
}
public TriangleShape(Vector pos, double r, IMaterial material, List<Vector> vertex, List<Vector> triangle)
{
R = r;
Position = pos;
this.vertex = vertex;
this.triangle = triangle;
Material = material;
}
#region IShape Members
public bool intersectTriangle(Ray ray, Vector v0 ,Vector v1 ,Vector v2, double t ,double u ,double v )
{
Vector edge1 = v1 - v0;
Vector edge2 = v2 - v0;
Vector normal = edge1.Cross(edge2);
normal.Normalize();
Vector dist = ray.Position - v0;
Vector pvec = ray.Direction.Cross(edge2);
double det = edge1.Dot(pvec);
if (det > -0 && det < 0)
{
return false;
}
double invDet = 1 / det;
Vector tvec = ray.Position - v0;
u = tvec.Dot(pvec) * invDet;
if (u < 0 || u > 1)
{
return false;
}
Vector QVector3D = tvec.Cross(edge1);
v = ray.Direction.Dot(QVector3D) * invDet;
if (v < 0 || u + v > 1)
{
return false;
}
t = edge2.Dot(QVector3D) * invDet;
if (t < 0)
{
return false;
}
return true;
}
public override IntersectInfo Intersect(Ray ray)
{
IntersectInfo info = new IntersectInfo();
info.Element = this;
double t = 0;
double u = 0;
double v = 0;
for (int ve = 0; ve < triangle.Count; ve++)
{
Vector triangles = triangle[ve];
double ind0 = triangle[ve].x;
double ind1 = triangle[ve].y;
double ind2 = triangle[ve].z;
Vector vert0 = vertex[(int)ind0];
Vector vert1 = vertex[(int)ind1];
Vector vert2 = vertex[(int)ind2];
Vector edge1 = vert1 - vert0;
Vector edge2 = vert2 - vert0;
Vector normal = edge1.Cross(edge2);
Vector dist = ray.Position - vert0;
//normal.Normalize();
Vector hit = ray.Position + ray.Direction * t;
if (intersectTriangle(ray, vert0, vert1, vert2, t, u, v))
{
info.IsHit = true;
info.Distance = t;
info.Position = hit;
info.Normal = normal;
info.Color = this.Material.GetColor(u, v);
return info;
}
else
{
info.IsHit = false;
}
}
info.Color = this.Material.GetColor(0, 0);
return info;
}
//public override IntersectInfo Intersect(Ray ray)
//{
// double t = 0;
// double u = 0;
// double v = 0;
// IntersectInfo info = new IntersectInfo();
// info.Element = this;
// Vector edge1 = v1 - v0;
// Vector edge2 = v2 - v0;
// Vector normal = edge1.Cross( edge2);
// Vector dist = ray.Position - v0;
// normal.Normalize();
// Vector hit = ray.Position + ray.Direction * t;
// if(intersectTriangle(ray,v0,v1,v2,t,u,v))
// {
// info.IsHit = true;
// info.Distance = t;
// info.Position = hit;
// info.Normal = normal;
// }
// else
// {
// info.IsHit = false;
// }
// info.Color = this.Material.GetColor(0, 0);
// return info;
//}
#endregion
public override string ToString()
{
return string.Format("TriangleShape ({0},{1},{2}) Radius: {3}", Position.x, Position.y, Position.z, R);
}
}
}
//parser
Imports Assimp
Imports RayTracer
Public Class Parser
Dim importer As AssimpContext
Dim ascen As Assimp.Scene
Dim vertex As List(Of Vector)
Dim triangles As List(Of Vector)
Dim uv As List(Of Vector)
Dim normal As List(Of Vector)
Dim material As List(Of Vector)
Public Sub parsefile(filename As String)
Try
importer = New AssimpContext()
ascen = importer.ImportFile(filename,
PostProcessSteps.CalculateTangentSpace &
PostProcessSteps.GenerateSmoothNormals &
PostProcessSteps.Triangulate &
PostProcessSteps.JoinIdenticalVertices &
PostProcessSteps.SortByPrimitiveType)
If IsNothing(ascen) = True Then
MessageBox.Show("could not load file,newer format?")
Else
MessageBox.Show("file loaded ok")
If (ascen.HasMeshes = True) Then
parsemesh()
End If
If (ascen.HasMaterials = True) Then
parsematerial()
End If
End If
Catch ex As AssimpException
MessageBox.Show(ex.Message)
End Try
End Sub
Public Sub parsemesh()
vertex = New List(Of Vector)
triangles = New List(Of Vector)
Dim count As Integer = 0
For Each m As Mesh In ascen.Meshes
For Each v In m.Vertices
count += 1
Dim ve As Vector = New Vector(v.X, v.Y, v.Z)
vertex.Add(ve)
If m.HasTextureCoords(count) Then
parseuv(ve, count, m)
End If
Next
If m.HasNormals Then
parsenormal(m)
End If
For Each fa In m.Faces
Dim ind As Integer = fa.Indices.ElementAt(0)
Dim ind1 As Integer = fa.Indices.ElementAt(1)
Dim ind2 As Integer = fa.Indices.ElementAt(2)
Dim myface As Vector = New Vector(ind, ind1, ind2)
triangles.Add(myface)
Next
Next
End Sub
Public Sub parsematerial()
material = New List(Of Vector)
For Each mat As Assimp.Material In ascen.Materials
Dim col As Vector = New Vector(mat.ColorDiffuse.R, mat.ColorDiffuse.G, mat.ColorDiffuse.B)
Dim colspec As Vector = New Vector(mat.ColorSpecular.R, mat.ColorSpecular.G, mat.ColorSpecular.B)
Dim colsref As Vector = New Vector(mat.ColorReflective.R, mat.ColorReflective.G, mat.ColorReflective.B)
Dim colstrans As Vector = New Vector(mat.ColorTransparent.R, mat.ColorTransparent.G, mat.ColorTransparent.B)
material.Add(col)
material.Add(colspec)
material.Add(colsref)
material.Add(colstrans)
Next
End Sub
Public Sub parsenormal(m As Mesh)
normal = New List(Of Vector)
For Each n In m.Normals
Dim ve As Vector = New Vector(n.X, n.Y, n.Z)
normal.Add(ve)
Next
End Sub
Public Sub parseuv(ve As Vector, index As Integer, m As Mesh)
uv = New List(Of Vector)
Dim x = m.TextureCoordinateChannels.ElementAt(0).ElementAt(index).X
Dim y = m.TextureCoordinateChannels.ElementAt(0).ElementAt(index).Y
Dim z = m.TextureCoordinateChannels.ElementAt(0).ElementAt(index).Z
Dim cord As Vector = New Vector(x, y, z)
uv.Add(cord)
End Sub
Function returnvertex() As List(Of Vector)
Return vertex
End Function
Function returntriangles() As List(Of Vector)
Return triangles
End Function
Function returnvnormal() As List(Of Vector)
Return normal
End Function
Function returntruv() As List(Of Vector)
Return uv
End Function
Function returnmaterial() As List(Of Vector)
Return material
End Function
End Class
//form
Imports System.ComponentModel
Imports RayTracer
Public Class Form1
Dim p As Parser = New Parser()
Private IsTracing As Boolean
Private scene As New Scene()
Private anti_aliasing As AntiAliasing = AntiAliasing.Medium
Private sceneId As Integer = 0
Private marbleTexture As Texture
Private woodTexture As Texture
Private wallTexture As Texture
Private bitmap As Drawing.Bitmap
Dim vertex As List(Of Vector)
Dim triangles As List(Of Vector)
Dim uv As List(Of Vector)
Dim normal As List(Of Vector)
Dim material As List(Of Vector)
#Region "Setup scene"
Private Sub SetupScene2()
scene = New Scene()
scene.Background = New Background(New Color(0.2, 0.3, 0.4), 0.5)
Dim campos As New Vector(0, 0, -5)
scene.Camera = New Camera(campos, campos / -2, (New Vector(0, 1, 0)).Normalize())
Dim rnd As New Random()
For i As Integer = 0 To 39
' setup a solid reflecting sphere
scene.Shapes.Add(New SphereShape(New Vector(rnd.Next(-100, 100) / 50.0, rnd.Next(-100, 100) / 50.0, rnd.Next(0, 200) / 50.0), 0.2, New SolidMaterial(New Color(rnd.Next(0, 100) / 100.0, rnd.Next(0, 100) / 100.0, rnd.Next(0, 100) / 100.0), 0.4, 0.0, 2.0)))
Next i
scene.Lights.Add(New Light(New Vector(5, 10, -1), New Color(0.8, 0.8, 0.8)))
scene.Lights.Add(New Light(New Vector(-3, 5, -15), New Color(0.8, 0.8, 0.8)))
End Sub
Private Sub SetupScene1()
Dim woodMaterial As New TextureMaterial(woodTexture, 0.2, 0.0, 2, 0.5)
Dim marbleMaterial As New TextureMaterial(marbleTexture, 0.0, 0.0, 2, 0.5)
Dim wallMaterial As New TextureMaterial(wallTexture, 0.0, 0.0, 2, 0.4)
scene = New Scene()
scene.Background = New Background(New Color(0.8, 0.8, 0.8), 0.8)
Dim campos As New Vector(5, 1.8, -15)
scene.Camera = New Camera(campos, campos / -3, (New Vector(0, 1, 0)).Normalize())
' marble
scene.Shapes.Add(New SphereShape(New Vector(1, 1, -5), 1, marbleMaterial))
'floor
scene.Shapes.Add(New PlaneShape((New Vector(0, 1, 0)).Normalize(), 0, woodMaterial))
'wall
scene.Shapes.Add(New PlaneShape((New Vector(0, 0, 1)).Normalize(), 0, wallMaterial))
scene.Lights.Add(New Light(New Vector(25, 20, -20), New Color(0.5, 0.5, 0.5)))
scene.Lights.Add(New Light(New Vector(-3, 5, -15), New Color(0.5, 0.5, 0.5)))
End Sub
' metallic box with marble on stone floor
Private Sub SetupScene4()
Dim woodMaterial As New TextureMaterial(woodTexture, 0.0, 0.0, 2, 0.5)
Dim marbleMaterial As New TextureMaterial(marbleTexture, 0.3, 0.0, 2, 0.5)
Dim wallMaterial As New TextureMaterial(wallTexture, 0.0, 0.0, 2, 0.4)
scene = New Scene()
scene.Background = New Background(New Color(0.3, 0.8, 0.8), 0.8)
Dim campos As New Vector(14, 2, -6)
scene.Camera = New Camera(campos, campos / -2.5, (New Vector(-0, 1, 0.1)).Normalize())
' marble
scene.Shapes.Add(New SphereShape(New Vector(-3, 1, 5), 2, marbleMaterial))
' box
scene.Shapes.Add(New BoxShape(New Vector(0, 1, -1), New Vector(1, 0, 0), woodMaterial))
'floor
scene.Shapes.Add(New PlaneShape((New Vector(0, 1, 0)).Normalize(), 0, wallMaterial))
'wall
'scene.Shapes.Add(new PlaneShape(new Vector(0, 0, 1).Normalize(), 0, wallMaterial));
scene.Lights.Add(New Light(New Vector(25, 20, -20), New Color(0.5, 0.5, 0.5)))
scene.Lights.Add(New Light(New Vector(-23, 25, -15), New Color(0.5, 0.5, 0.5)))
End Sub
' single reflective shere on chessboard scene
Private Sub SetupScene3()
scene = New Scene()
scene.Camera = New Camera(New Vector(0, 0, -15), New Vector(-0.2, 0, 5), New Vector(0, 1, 0))
scene.Background = New Background(New Color(0.5, 0.5, 0.5), 0.4)
' setup a solid reflecting sphere
scene.Shapes.Add(New SphereShape(New Vector(-0.5, 0.5, -2), 1.5, New SolidMaterial(New Color(0, 0.5, 0.5), 0.3, 0.0, 2.0)))
' setup the chessboard floor
scene.Shapes.Add(New PlaneShape((New Vector(0.1, 0.9, -0.5)).Normalize(), 1.2, New ChessboardMaterial(New Color(1, 1, 1), New Color(0, 0, 0), 0.2, 0, 1, 0.7)))
'add two lights for better lighting effects
scene.Lights.Add(New Light(New Vector(5, 10, -1), New Color(0.8, 0.8, 0.8)))
scene.Lights.Add(New Light(New Vector(-3, 5, -15), New Color(0.8, 0.8, 0.8)))
End Sub
' marble balls scene
Private Sub SetupScene0()
Dim texture As New TextureMaterial(marbleTexture, 0.0, 0.0, 2, 0.5)
scene = New Scene()
scene.Camera = New Camera(New Vector(0, 0, -15), New Vector(-0.2, 0, 5), New Vector(0, 1, 0))
' setup a solid reflecting sphere
scene.Shapes.Add(New SphereShape(New Vector(-1.5, 0.5, 0), 0.5, New SolidMaterial(New Color(0, 0.5, 0.5), 0.2, 0.0, 2.0)))
' setup sphere with a marble texture from an image
scene.Shapes.Add(New SphereShape(New Vector(0, 0, 0), 1, texture))
' setup the chessboard floor
scene.Shapes.Add(New PlaneShape((New Vector(0.1, 0.9, -0.5)).Normalize(), 1.2, New ChessboardMaterial(New Color(1, 1, 1), New Color(0, 0, 0), 0.2, 0, 1, 0.7)))
'add two lights for better lighting effects
scene.Lights.Add(New Light(New Vector(5, 10, -1), New Color(0.8, 0.8, 0.8)))
scene.Lights.Add(New Light(New Vector(-3, 5, -15), New Color(0.8, 0.8, 0.8)))
End Sub
' trianglescene
Private Sub SetupScene5()
Dim marbleMaterial As New TextureMaterial(marbleTexture, 0.0, 0.0, 2, 0.5)
scene = New Scene()
scene.Background = New Background(New Color(0.8, 0.8, 0.8), 0.8)
Dim campos As New Vector(5, 1.8, -15)
scene.Camera = New Camera(campos, campos / -3, (New Vector(0, 1, 0)).Normalize())
Dim tri As New TriangleShape()
tri.normal = normal
tri.vertex = vertex
tri.triangle = triangles
tri.uv = uv
tri.col = material
tri.R = 1 'radius
tri.Position = New Vector(-3, 1, 5).Normalize()
If tri.col.Count > 0 Then
Dim diffuse As Vector = tri.col.ElementAt(0)
Dim specular As Vector = tri.col.ElementAt(1)
Dim reflective As Vector = tri.col.ElementAt(2)
Dim transparent As Vector = tri.col.ElementAt(3)
tri.Material = New SolidMaterial(New Color(diffuse.x, diffuse.y, diffuse.z), reflective.toDouble(), transparent.toDouble(), specular.toDouble())
Else
tri.Material = New SolidMaterial(New Color(tri.col.ElementAt(0).x, 0, 0), 0.5, 0, 2.0)
End If
scene.Shapes.Add(tri)
scene.Shapes.Add(New PlaneShape((New Vector(0, 1, 0)).Normalize(), 0, marbleMaterial))
scene.Lights.Add(New Light(New Vector(25, 20, -20), New Color(0.5, 0.5, 0.5)))
scene.Lights.Add(New Light(New Vector(-3, 5, -15), New Color(0.8, 0.8, 0.8)))
End Sub
#End Region ' Setup scene
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
IsTracing = False
Application.DoEvents()
Dim path As String = Application.StartupPath
' pre-load the textures here, so it only needs to be done once
woodTexture = Texture.FromFile(path & "\wood2.png")
marbleTexture = Texture.FromFile(path & "\marble1.png")
wallTexture = Texture.FromFile(path & "\wall1.png")
End Sub
Private Sub tracer_RenderUpdate(progress As Integer, duration As Double, ETA As Double, scanline As Integer)
'only invalidate part of the picturebox that needs to be redrawn
PictureBox1.Invalidate(New Drawing.Rectangle(0, scanline - 1, PictureBox1.Image.Width, 2))
Label1.Text = "Eta: " & (ETA / 1000).ToString("0.0") & "s"
Label2.Text = "Duration:" & (duration / 1000).ToString("0.0") & "s"
Application.DoEvents() ' some time to redraw the screen
End Sub
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
If (OpenFileDialog1.ShowDialog() = DialogResult.OK) Then
p.parsefile(OpenFileDialog1.FileName)
vertex = New List(Of Vector)
triangles = New List(Of Vector)
uv = New List(Of Vector)
normal = New List(Of Vector)
material = New List(Of Vector)
uv = p.returntruv
normal = p.returnvnormal
material = p.returnmaterial
triangles = p.returntriangles
vertex = p.returnvertex
End If
End Sub
Private Sub RenderToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RenderToolStripMenuItem.Click
IsTracing = True
SetupScene5()
Label1.Text = "Eta:"
Label2.Text = "Duration:"
Dim RayTracer As New RayTracer.RayTracer(anti_aliasing, True, True, True, True, True)
AddHandler raytracer.RenderUpdate, AddressOf tracer_RenderUpdate
Dim rect As New Drawing.Rectangle(0, 0, PictureBox1.Width, PictureBox1.Height)
bitmap = New Drawing.Bitmap(rect.Width, rect.Height)
Dim g As Drawing.Graphics = Drawing.Graphics.FromImage(bitmap)
Dim t As Date = Date.Now
PictureBox1.Image = bitmap
raytracer.RayTraceScene(g, rect, scene)
IsTracing = False
Dim s As TimeSpan = Date.Now.Subtract(t)
Console.WriteLine("total render time: " & s.TotalMilliseconds.ToString("0.00"))
Label2.Text = ""
End Sub
End Class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment