LoginSignup
0
0

More than 1 year has passed since last update.

cscの作法 その22 レイトレース

Last updated at Posted at 2020-01-03

概要

cscの作法、調べてみた。
練習問題やってみた。

練習問題

レイトレースを表示せよ。

参考にしたページ

写真

image.png

サンプルコード

using System;
using System.Windows.Forms;
using System.Drawing;

class form1: Form {
    form1() {
        Text = "ray";
        ClientSize = new Size(300, 300);
    }
    protected override void OnPaint(PaintEventArgs e) {
        Graphics g = e.Graphics;
        Color clrBackground = Color.Black;
        g.FillRectangle(new SolidBrush(clrBackground), new Rectangle(0, 0, 200, 200));
        Rectangle rect = new Rectangle(0, 0, 200, 200);
        System.Collections.ArrayList obj3dArrayList;
        obj3dArrayList = new System.Collections.ArrayList();
        obj3dArrayList.Add(new Sphere(0.0, 0.0, 90.0, 100.0, 0.0, 0.0, 255.0));
        obj3dArrayList.Add(new Sphere(-180.0, -130.0, -110.0, 15.0, 255.0, 0.0, 0.0));
        obj3dArrayList.Add(new Sphere(-140.0, -140.0, -150.0, 20.0, 255.0, 200.0, 0.0));
        Graphics graphics = g;
        double px = (double) 0,
            py = (double) 0,
            pz = (double) 500;
        double lpx = (double) 200,
            lpy = (double) 200,
            lpz = (double) 200;
        double lvx = (double) -1.0,
            lvy = (double) -1.0,
            lvz = (double) -1.0;
        double fMax = 200.0;
        for (int i = rect.Left; i <= rect.Right; i++)
        {
            double x = Sphere.GetCoord(rect.Left, rect.Right, -fMax, fMax, i);
            for (int j = rect.Top; j <= rect.Bottom; j++)
            {
                double y = Sphere.GetCoord(rect.Top, rect.Bottom, fMax, -fMax, j);
                double t = 1.0E10;
                double vx = x - px, vy = y - py, vz = -pz;
                double mod_v = Sphere.modv(vx, vy, vz);
                vx = vx / mod_v;
                vy = vy / mod_v;
                vz = vz / mod_v;
                bool bShadow = false;
                Sphere spherehit = null;
                for (int k = 0; k < (int) obj3dArrayList.Count; k++)
                {
                    Sphere sphn = (Sphere) obj3dArrayList[k];
                    double taux = Sphere.GetSphereIntersec(sphn.cx, sphn.cy, sphn.cz, sphn.radius, px, py, pz, vx, vy, vz);
                    if (taux < 0) continue;
                    if (taux > 0 && taux < t)
                    {
                        t = taux;
                        spherehit = sphn;
                    }
                }
                Color color = Color.FromArgb(10, 20, 10);
                if (spherehit != null)
                {
                    double itx = px + t * vx, ity = py + t * vy, itz = pz + t * vz;
                    double tauxla = Sphere.GetSphereIntersec(spherehit.cx, spherehit.cy, spherehit.cz, spherehit.radius, lpx, lpy, lpz, itx - lpx, ity - lpy, itz - lpz);
                    for (int k = 0; k < (int)obj3dArrayList.Count; k++)
                    {
                        Sphere sphnb = (Sphere)(obj3dArrayList[k]);
                        if (sphnb != spherehit)
                        {
                            double tauxlb = Sphere.GetSphereIntersec(sphnb.cx, sphnb.cy, sphnb.cz, sphnb.radius, lpx, lpy, lpz, itx - lpx, ity - lpy, itz - lpz);
                            if (tauxlb > 0 && tauxla < tauxlb)
                            {
                                bShadow = true;
                                break;
                            }
                        }
                    }
                    double cost = Sphere.GetCosAngleV1V2(lvx, lvy, lvz, itx - spherehit.cx, ity - spherehit.cy, itz - spherehit.cz);
                    if (cost < 0) cost = 0;
                    double fact = 1.0;
                    if (bShadow == true) fact = 0.5; else fact = 1.0;
                    double rgbR = spherehit.clR * cost * fact;
                    double rgbG = spherehit.clG * cost * fact;
                    double rgbB = spherehit.clB * cost * fact;
                    color = Color.FromArgb((int)rgbR, (int)rgbG, (int)rgbB);
                    Pen pen = new Pen(color);
                }
                Brush brs = new SolidBrush(color);
                graphics.FillRectangle(brs, i, j, 1, 1);
                brs.Dispose();
            }
        }
        base.OnPaint(e);
    }
    class Sphere {
    public Sphere(double x, double y, double z, double r, double clr, double clg, double clb) {
        cx = x;
        cy = y;
        cz = z;
        radius = r;
        clR = clr;
        clG = clg;
        clB = clb;
    }
    public static double GetCoord(double i1, double i2, double w1, double w2, double p) {
        return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1;
    }
    public static double modv(double vx, double vy, double vz) {
        return System.Math.Sqrt(vx * vx + vy * vy + vz * vz);
    }
    void Move(double vx, double vy, double vz) {
        cx += vx;
        cy += vy;
        cz += vz;
    }
    void MoveTo(double vx, double vy, double vz) {
        cx = vx;
        cy = vy;
        cz = vz;
    }
    void RotX(double angle) {
        double y = cy * System.Math.Cos(angle) - cz * System.Math.Sin(angle);
        double z = cy * System.Math.Sin(angle) + cz * System.Math.Cos(angle);
        cy = y;
        cz = z;
    }
    void RotY(double angle) {
        double x = cx * System.Math.Cos(angle) - cz * System.Math.Sin(angle);
        double z = cx * System.Math.Sin(angle) + cz * System.Math.Cos(angle);
        cx = x;
        cz = z;
    }
    public static double GetSphereIntersec(double cx, double cy, double cz, double radius, double px, double py, double pz, double vx, double vy, double vz) {
        double A = (vx * vx + vy * vy + vz * vz);
        double B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
        double C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy + pz * pz - 2 * pz * cz + cz * cz - radius * radius;
        double D = B * B - 4 * A * C;
        double t = -1.0;
        if (D >= 0)
        {
            double t1 = (-B - System.Math.Sqrt(D)) / (2.0 * A);
            double t2 = (-B + System.Math.Sqrt(D)) / (2.0 * A);
            if (t1 > t2) t = t1; else t = t2;
        }
        return t;
    }
    public static double GetCosAngleV1V2(double v1x, double v1y, double v1z, double v2x, double v2y, double v2z) {
        return (v1x * v2x + v1y * v2y + v1z * v2z) / (modv(v1x, v1y, v1z) * modv(v2x, v2y, v2z));
    }
    public double cx,
        cy,
        cz,
        radius,
        clR,
        clG,
        clB;
    }
    [STAThread]
    public static void Main() {
        Application.Run(new form1());
    }
}





以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0