|
3D рендеринг в операционной системе A2SAGE Исходные тексты уроков с сайта www.scratchapixel.comПредставляю Вашему вниманию исходные тексты уроков с сайта www.scratchapixel.com, портированные на Active Oberon. При портировании с C++ использованна возможность перегрузки операторов присутствующая в языке Active Oberon. Многопоточность достигнута с использованием концепции активных объектов. Урок 1. Алгоритм обратной трассировки лучей
АнтиалиасингНа основе кода данного урока, в качестве эксперимента реализован алгоритм одноуровневого адаптивного антиалиасинга. Суть алгоритма заключается в нахождении проблемных пикселей на границах объектов. Затем цвет таких пикселей уточняется путём смешения с цветами четырёх суб-пикселей с учётом их веса. Для более качественного антиалиасинга можно уточнять цвет и самих суб-пикселей производя их деление на ещё более мелкие элементы, однако было решено ограничится суб-пиксельным уровнем. Нахождение проблемных пикселей было решено производить путём вычисления расстояния между цветом каждого пикселя и цветами соседних с ним пикселей в цветовом прострастве, аналогично тому, как вычисляется расстояние между точками в трёхмерном пространстве. В случае если цветовое расстояние хоть с одним из соседних пикселей превышает заданное пороговое значение, пиксель считается проблемным. Результат обнаружения проблемных пикселей при пороговом значении равном 0.05:
Хорошо видно, что такое пороговое значение даёт хороший запас и в число проблемных пикселей попадает много пикселей без видимых артефактов алиасинга. Пороговое значение вполне можно повысить. Далее для всех проблемных пикселей вычисляются и трассируются четыре дополнительных луча, проходящих через центры суб-пикселей. Вычисляется усреднённый цвет суб-пикселей и относительно него вычисляются цветовые расстояния для их цветов. Вычисляются веса по принципу: цвет суб-пикселя с наибольшим расстоянием от усреднённого цвета имеет наибольший вес. Далее вычисляется усреднённый вес суб-пикселей с учётом весов и результат усредняется с вычесленным ранее цветом пикселя. Результат работы алгоритма выглядит достаточно неплохо при том что для его достижения было оттрассированно всего 28000 лучей дополнительно. Таким образом для рендеринга сцены было оттрассировано около 1.09 лучей на каждый пиксель. Результат работы алгоритма антиалиасинга:
Антиалиасинг в 2D графикеОпыт полученный от экспериментов с адаптивным антиалиасигом нашёл успешное применение и для антиалиасинга в 2D графике. BohdanT модифицировал модуль WMClock для рисования более симпатичных стрелочек в режиме аналоговых часов, но результат хоть и был неплохим, всю картину портило присутствие эффекта алиасинга изображения стрелок. Я решил продемонстрировать принципиальную возможность использования адаптивного антиалиасинга и в данном случае. Причём многоуровневый адаптивный антиалиасинг теперь реализован полностью, и доступно задание число его уровней. Вот результат работы алгоритма:
Урок 6. Пересечение луча с треугольникомЦвет в точке пересечения задан барицентрическими координатами:
Треугольник закрашен цветом, полученным интерполяцией цвета вершин:
Стоит привести несколько соображений по поводу улучшения производительности. Авторы уроков в тексте тоже неоднократно этот вопрос поднимают. Я сделал небольшой бенчмарк на основе кода lesson6b.Mod, демонстрирующий зависимость длительности вычислений от размера элементарного фрагмента обрабатываемых данных bucketSize. Учитывалось только время затраченное на непосредственные вычисления в параллельных потоках. Результаты бенчмарка (параметры системы: одноядерный P4 3,400 GHz с технологией HyperThreading, WinAos rev. 1567), время вычислений для всего фрейма 640x480 пикселей, в миллисекундах: Bucket size: 32 Time elapsed: 1208 Bucket size: 64 Time elapsed: 623 Bucket size: 128 Time elapsed: 335 Bucket size: 256 Time elapsed: 203 Bucket size: 512 Time elapsed: 157 Bucket size: 1024 Time elapsed: 160 Затем, тип LONGREAL был заменён на REAL, и соответственно, импортирован модуль Math вместо MathL. После компиляции и повторного запуска результаты были следующими: Bucket size: 32 Time elapsed: 858 Bucket size: 64 Time elapsed: 446 Bucket size: 128 Time elapsed: 235 Bucket size: 256 Time elapsed: 143 Bucket size: 512 Time elapsed: 110 Bucket size: 1024 Time elapsed: 111 Как видно из результатов, на такой простой сцене нет абсолютно никакого смысла в разбиении фрейма на минимальные фрагметы. И разбиение на потоки с наличием технологии HyperThreading тоже не дало ощутимого прироста производительности. Естественно, на других, более сложных сценах и на другом оборудовании картина можеть быть иная. Ещё бенчмарк показал, что предпочтительнее использование типа REAL. Модуль lesson6bench.Mod с использованием типа REAL включён в архив с исходными текстами к уроку. Урок 7. Примитивы
Адаптивный антиалиасинг + многопоточность + SSE оптимизацияПосле длительного перерыва, нашлось время полностью переписать код примеров 1 и 6. Результаты в Raytracer.zip. Адаптивный антиалиасинг теперь реализован полностью. Многопоточный код теперь стал реально многопоточным, что видно по бенчмаркам. Также, присутствуют SSE оптимизации вычислений. SSE оптимизации вынесены отдельно, при необходимости их можно включить, поменяв lib := Lib3D на lib := Lib3D_SSE в секции импорта. По бенчмаркам видно, что SSE оптимизации не дают ощутимого прироста производительности, поскольку используются unaligned варианты SSE команд. Т.е. ещё есть что оптимизировать :) Результаты бенчмарка (параметры системы: AMD A10-7850K Radeon R7, 12 Compute Cores 4C+8G @ 3.70 GHz (4 cores, 4 threads)). Lesson1, без SSE: nThreadsTotal: 1, bucket size: 640 x 480, nBucketsTotal: 1, time elapsed: 1.2909 nThreadsTotal: 2, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.7199 nThreadsTotal: 4, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.3787 Lesson1, SSE: nThreadsTotal: 1, bucket size: 640 x 480, nBucketsTotal: 1, time elapsed: 1.0590 nThreadsTotal: 2, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.5875 nThreadsTotal: 4, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.3032 Lesson6, без SSE: nThreadsTotal: 1, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.2253 nThreadsTotal: 2, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.1196 nThreadsTotal: 4, bucket size: 80 x 60, nBucketsTotal: 64, time elapsed: 0.0673 Lesson6, SSE: nThreadsTotal: 1, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.1826 nThreadsTotal: 2, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.0976 nThreadsTotal: 4, bucket size: 80 x 60, nBucketsTotal: 64, time elapsed: 0.0541 Lesson6, быстрый алгоритм пересечения треугольника с лучём (Möller–Trumbore), без SSE: nThreadsTotal: 1, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.2030 nThreadsTotal: 2, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.1079 nThreadsTotal: 4, bucket size: 80 x 60, nBucketsTotal: 64, time elapsed: 0.0592 Lesson6, быстрый алгоритм пересечения треугольника с лучём (Möller–Trumbore), SSE: nThreadsTotal: 1, bucket size: 320 x 240, nBucketsTotal: 4, time elapsed: 0.1565 nThreadsTotal: 2, bucket size: 160 x 120, nBucketsTotal: 16, time elapsed: 0.0826 nThreadsTotal: 4, bucket size: 80 x 60, nBucketsTotal: 64, time elapsed: 0.0451 Результаты работы алгоритмов. С антиалиасигом гораздо симпатичнее!
Дата последнего обновления: 28-1-16 22:39:39 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright © 2005-2021 SAGE. Все права защищены. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||