2015-11-03 55 views
14

Mam okrąg, który krąży co 10 sekund. Próbuję rzucić cień, który jest ustawiony pod kątem do orbity (źródło światła), jednocześnie biorąc pod uwagę kąt kamery.Przenoszenie cienia wokół okręgu

Cień działa pod pewnymi kątami, ale gdy kamera jest bardziej lub bardziej z góry na dół, zaczyna wyglądać mniej precyzyjnie i nie mam pojęcia, jak to poprawić - wydaje się to skomplikowanym zagadnieniem matematycznym, którym jestem. walcząc, aby dowiedzieć się, jak rozwiązać.

Jest to animacja: http://jsfiddle.net/8y2bm88w/

A mój kod losowanie cieniu:

ctx.beginPath(); 

//rotate shadow with the planet 
ctx.translate(originX + obj[i].x, originY + obj[i].y); 
ctx.rotate(obj[i].angle); //rotate around origin 
ctx.translate(-(originX + obj[i].x), -(originY + obj[i].y)); 


var offsetX = -(10 * Math.sin(obj[0].angle)); //i feel this is the issue 
var offsetY = 0; //this too 

ctx.rect(originX + obj[i].x + offsetX, originY + obj[i].y + offsetY - 10, 20, 20); 
ctx.fillStyle = 'rgba(213,0,0,0.9)'; //red shadow - easier to see 
ctx.fill(); 

Kod większy sens poprzez JSFiddle gdyż stawia kod na więcej kontekstu.

Sądzę, że ma to związek z matematyką dla zmiennych offsetX i offsetY, ponieważ użytkownik zmienia kąt kamery, do której musi się dostosować offset i zmienia sposób poruszania cienia. Ale to naprawdę mylące, jak rozwiązać.

+0

Tak więc, jeśli dobrze rozumiem, chcesz półkuli koło skierowane na pochodzenie, które ma być oświetlone, a reszta jest ciemna. Jest to prawdą niezależnie od kąta kamery. Poprawny? –

+0

@AsadSaeeduddin należy wziąć pod uwagę kąt, w którym oglądasz planetę. Więc wierzę, że zrozumiałeś poprawnie. – Sir

+0

@AsadSaeeduddin dobry punkt, w zasadzie to po prostu musi wyglądać poprawnie z oczu widza. Jeśli spojrzysz na krawędź "kąta kamery = 0", powinien on rzucić pełny cień i bez cienia itp., Z góry w dół "kąt kamery = 1" będzie rzucał pół cienia cały czas. – Sir

Odpowiedz

7

Ty trafienia to ponieważ obj[i].angle bazuje na elipsy współrzędnych a nie na współrzędne XY z widoku z góry na dół (co jest rzeczywiście to, co jesteś generowania wszystko inne od więc nie zrobić trzeba wykonać dla niego obliczenia).

Będziesz potrzebować obu kątów, więc dodałem drugą właściwość dla drugiego kąta. Kąt elipsy jest potrzebny do obrócenia kontekstu, dzięki czemu możesz być prostopadły do ​​wektora od punktu początkowego, tak jak go widziałeś. Nowy kąt jest dla obliczeń. Można to sobie wyobrazić jako wersję odwzorowaną w 2D.

obj[i].trueAngle = angle; 

Teraz mamy wartość do pracy, proponuję rysunek półokrąg na „ciemną stronę”, a następnie dodanie lub wycinanie z tego regionu wymagane przy użyciu krzywej wyboru, aby zakończyć cień, np

// centre on planet 
ctx.translate(originX + obj[i].x, originY + obj[i].y); 
ctx.rotate(obj[i].angle - Math.PI/2); 
// semicircle dark side 
ctx.arc(0, 0, 12, 0, Math.PI, false); 
// path along terminator 
var offset_terminator = -20 * Math.sin(obj[0].trueAngle) * (1 - camera.angle); 
ctx.bezierCurveTo(-7, offset_terminator, 7, offset_terminator, 12, 0); 
//fill 
ctx.fillStyle = 'rgba(213,0,0,0.9)'; //red shadow - easier to see 
ctx.fill(); 

Tu również cień kilka px większy niż planety, po prostu grał z numerów, aż znalazłem takie, które wyglądały dobrze.

Uwaga skonfigurować rotacja tak 0, 0 jest środek naszej planety, a oś x przemieszcza się wzdłuż terminator

DEMO

+0

Jeśli chcesz mieć więcej cienkich półksiężyców, rozważ zmniejszenie skali skalowania 'offset_terminator' z' -20' do '-14', co sprawia, że ​​wygląda całkiem ładnie –

+0

Dlaczego magia liczy 12 i 7? Czy nie powinny to być odpowiednio 10 i 5? Zdaję sobie sprawę, że jest to spowodowane uderzeniem, ale czy nie ma sensu po prostu pozbyć się obrysu i zamiast tego rozszerzyć promień okręgu? –

+1

@FuzzyLogic I wybrał "12", aby upewnić się, że kolor cienia jest nad wszystkimi pikselami, nawet gdy krawędzie są mieszane, ponieważ mogą nie pasować idealnie do pikseli "10". OP ma zarys, który by to ukrył. "11" nie działa po obu stronach. Co do '7', ponieważ dał on niezłą krzywą kształtu. –