2014-10-22 1 views
2

Я работаю над игрушечным райтером, используя треугольники на основе вершин, похожие на OpenGL. Каждая вершина имеет свой собственный цвет, а окраска треугольника в каждой точке должна основываться на средневзвешенном цвете вершин, взвешенном по тому, насколько близко точка к каждой вершине.Алгоритм окраски треугольника по цвету вершин

Я не могу понять, как рассчитать вес каждого цвета в данной точке треугольника, чтобы имитировать оттенок цвета, сделанный OpenGL, как показано многими примерами here. У меня есть несколько мыслей, но я не уверен, какой из них правильный (V - это вершина, U и W - две другие вершины, P - это точка для цвета, C - это центр тяжести треугольника, а |PQ| - расстояние форма точка P указать Q):

  1. имеет вес, равный `1- (| VP |/| VC |), но это оставит черное на центроида (все цвета взвешиваются 0), которая не является верный.
  2. Вес равен 1-(|VP|/max(|VU|,|VW|)), поэтому V имеет ненулевой вес ближе к двум вершинам, что, по моему мнению, неверно.
  3. Вес равен 1-(|VP|/min(|VU|,|VW|)), поэтому V имеет нулевой вес ближе к двум вершинам и отрицательный вес (который насыщается до 0) в дальнейшем. Я не уверен, правильно это или нет.
  4. сегмент линии L простирается от V через P на противоположную сторону треугольника (UW): вес представляет собой отношение |VP| к |L|. Таким образом, вес V будет равен 0 по всей противоположной стороне.

Последний, пожалуй, самый вероятный, но у меня возникли проблемы с его внедрением, поэтому я не уверен, что он правильный.

+4

OpenGL использует [Барицентрическая координату] (http://en.wikipedia.org/wiki/Barycentric_coordinate_system) для интерполяции –

+1

Это может сделать: http://en.wikibooks.org/wiki/GLSL_Programming/Rasterization#Linear_Interpolation_of_Varying_Variables –

ответ

3

OpenGL использует барицентрические координаты (линейная интерполяция точно, хотя вы можете изменить это с помощью функций интерполяции или классификаторов, таких как centroid или noperspective в последних версиях).

В случае, если вы не знаете, барицентрическое координирует работы, как, что:
для местоположения Р в виде треугольника из вершин V1, V2 и V3, чьи соответствующие коэффициенты С1, С2, С3, такие как С1 + С2 + С3 = 1 (эти коэффициенты относится к влиянию каждой вершины в цвете P) OpenGL, необходимо вычислить такие, как результат эквивалентен

C1 = (AreaOfTriangle PV2V3)/(AreaOfTriangle V1V2V3) 
C2 = (AreaOfTriangle PV3V1)/(AreaOfTriangle V1V2V3) 
C3 = (AreaOfTriangle PV1V2)/(AreaOfTriangle V1V2V3) 

и площадь треугольника может быть вычислена с половиной длины перекрестного произведения двух векторов, определяющих его (в прямом смысле), например AreaOfTriangle V1V2V3 = length(cross(V2-V1, V3-V1))/2. Затем мы имеем что-то вроде:

float areaOfTriangle = length(cross(V2-V1, V3-V1)); //Two times the area of the triangle 
float C1 = length(cross(V2-P, V3-P))/areaOfTriangle; //Because A1*2/A*2 = A1/A 
float C2 = length(cross(V3-P, V1-P))/areaOfTriangle; //Because A2*2/A*2 = A2/A 
float C3 = 1.0f - C1 - C2;        //Because C1 + C2 + C3 = 1 

Но после некоторой математики (и немного веб-исследований: D), наиболее эффективный способ сделать это я нашел:

YOURVECTYPE sideVec1 = V2 - V1, sideVec2 = V3 - V1, sideVec3 = P - V1; 
float dot11 = dot(sideVec1, sideVec1); 
float dot12 = dot(sideVec1, sideVec2); 
float dot22 = dot(sideVec2, sideVec2); 
float dot31 = dot(sideVec3, sideVec1); 
float dot32 = dot(sideVec3, sideVec2); 
float denom = dot11 * dot22 - dot12 * dot12; 
float C1 = (dot22 * dot31 - dot12 * dot32)/denom; 
float C2 = (dot11 * dot32 - dot12 * dot31)/denom; 
float C3 = 1.0f - C1 - C2; 

Затем интерполировать такие вещи, как цвет, COLOR1, цвет2 и color3 быть цвета ваших вершин, вы делаете:

float color = C1*color1 + C2*color2 + C3*color3; 

Но нужно учитывать, что это не работает должным образом, если вы используете перспективные преобразования (или любое преобразование вершин, подразумевающие w компонент), так что в этом случае , вам придется использовать:

float color = (C1*color1/w1 + C2*color2/w2 + C3*color3/w3)/(C1/w1 + C2/w2 + C3/w3); 

w1, w2 и w3 соответственно четвертые компоненты исходных вершин, сделанных V1, V2 и V3.
V1, V210 и V3 в первом вычислении должно быть 3 размера из-за поперечного произведения, но во втором (наиболее эффективное) оно может быть двухмерным и трехмерным, результаты будут одинаковыми (I думайте, что вы догадались, что 2D был быстрее во втором вычислении), но в обоих случаях не забудьте разделить их на четвертый компонент их исходного вектора, если вы делаете перспективные преобразования и используете вторую формулу для интерполяции в этом случае , (И в случае, если вы не поняли, все векторы в этих расчетах НЕ должны включают в себя четвертый компонент!)

И последнее; Я настоятельно рекомендую вам использовать OpenGL, просто предоставив большой квадратик на экране и поместив весь ваш код в шейдеры (хотя вам понадобятся очень сильные знания об OpenGL для расширенного использования), потому что вы будете пользоваться параллелизмом (даже с #! + видеокарта), за исключением случаев, когда вы пишете это на компьютере с 30 годами, или если вы просто делаете это, чтобы посмотреть, как это работает.

+0

Oh S #! + , уже ответил ... XD – Lewin

+0

Спасибо за подробный ответ, это очень полезно! – brianmearns

+0

В качестве продолжения я обнаружил, что барицентрические координаты также могут использоваться для проверки того, находится ли точка на плоскости внутри или вне треугольника, но вы должны использовать зону _signed_ каждого треугольника для получения барицентрических координат. В этом случае, если _any_ из барицентрических координат отрицательны, то точка находится за пределами треугольника. Чтобы получить подписанную область, я взял перекрестное произведение смежных векторов, как вы описали, и усеял их фиксированным вектором _unit_, нормальным к треугольнику (например, единицей V1V2 x V1V3). Половина результата - это подписанная область треугольника. – brianmearns

0

IIRC, для этого вам не нужно ничего делать в GLSL - интерполированный цвет уже будет цветом ввода для вашего шейдера фрагмента, если вы просто передадите цвет вершин в вершинном шейдере.

Редактировать: Да, это не отвечает на вопрос - правильный ответ уже в первом комментарии выше: используйте барицентрические координаты (что и делает GL).

+0

I подумайте, что вы неправильно поняли мой вопрос: я не использую opengl или какую-либо другую библиотеку, я пишу лучевой трассир с нуля, для образовательных целей. – brianmearns

+0

Ah да извините O :) –

+0

p.s. Мета: следует ли удалить неправильный ответ? Кроме того, я думаю, что комментарий № 1 на вопрос действительно отвечает на этот вопрос, может быть, вы должны добавить ответ, указывающий на комментарий @Colonel Thirty Two и принять его, чтобы отметить это закрыто .... –

 Смежные вопросы

  • Нет связанных вопросов^_^