Created
March 5, 2018 12:23
-
-
Save nexustheru/d38f2c5e249df39bc6e330369c61bfa3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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