Cortes romanos trouxeram rosas vermelhas escritas em scripts JavaScript. Rose feita com código é o melhor presente do Dia dos Namorados, dado à sua namorada por programadores incríveis! (Dica: o efeito e a velocidade de visualização serão muito diferentes em diferentes navegadores)
A imagem é gerada pelo código e o usuário pode atualizar a página e repetir o processo de apresentação de assistir a rosa.
O código de implementação do 3D Rose é o seguinte:
A cópia do código é a seguinte: com (m = matemática) c = cos, s = sin, p = pow, r = aleatório; c.width = c.Height = f = 500; h = -250; função; p (a, b, c) {if (c> 60) retorna [s (a*7)*(13+5/(. 2+p (b*4,4)))-s (b)*50, b*f+50,625+c (a*7)*(13+ 5/(. 2+P (B*4,4)))+B*400, A*1-B/2, A]; A = A*2-1; B = B*2-1; if (a*a+b*b <1) {if (c> 37) {n = (j = c & 1) ? 6: 4; o = 0,5/(a+.01)+c (b*125)*3-a*300; w = b*h; retorna [o*c (n)+w*s (n)+j*610-390, o*s (n) -w*c (n)+550-j*350,1180+c (b+a)*99-j*300, .4-a*.1+p (1-b*b, -h*6)*. 15-a*b*.4+c (a+b)/5+p (c ((((c. o*(a+1)+(b> 0? w: -w))/25), 30)*. 1*(1-b*b), o/1e3+.7-o*w*3e-6]} if (c> 32) {c = c*1.16-15; o = a*45-20; w = b*b*h; z = o*s (c)+w*c (c) +620; retorna [o*c (c) -w*s (c), 28+c (b*.5)*99-b*b*b*60-z/ 2-h, z, (b*b*.3+p ((1- (a*a)), 7)*. 15+.3)*b, b*.7]} o = a*(2-b)*(80-c*2); w = 99-c (a)*120-C (b)*(-hc*4.9)+c (p (1-b, 7)*) 50+c*2; z = o*s (c)+w*c (c) +700; Retorno [O*C (C) -W*S (C), B*99-C (P (B, 7))*50-C/3-Z/1,35+450, Z, (1-B/1.2)*. 9+A*.1, P ((1-b), 20) /4+.05]}} setInterval ('para (i = 0; i <1e4; i ++) se (s = p (r (), r (), i%46/.74)) {z = s [2]; x = ~~ (s [0]*f/zh); (! m [q = y*f+x] | m [q]> z) m [q] = z, a.fillstyle = "rgb ("+~ (s [3]*h)+","+~ (s [4]*h)+","+~ (s [3]*s [3]*-80)+"), A.FL)," "+~ (s [3]*s, [3]*-80)+"), A.FL), ""+~ (s [3]*s, [3]*-80)+"), A.FL)," "+~ (s [3]*s, [3]*-80)+"), A.FL).
Obviamente, as pessoas interessadas podem entender o seguinte processo de implementação e teorias relacionadas:
O efeito de apresentação desse código tridimensional Rose usa o método Monte Carlo, e o criador elogiou o método Monte Carlo. Ele disse que o método Monte Carlo é uma "ferramenta incrivelmente poderosa" em termos de otimização e amostragem funcionais. Para o método Monte Carlo, consulte: Método Monte Carlo.
Operações específicas:
Desenho de renderização de amostragem de aparência
Eu usei vários diagramas de formas diferentes para formar esse código ROSE. Foram utilizados 31 formas: 24 pétalas, 4 sépalas, 2 folhas e 1 haste de flor, e cada diagrama de formas foi retratado no código.
Primeiro, defina um intervalo de amostragem:
função superfície (a, b) {// Estou usando A e B como parâmetros variados de 0 a 1. Returno {x: a*50, y: b*50}; // Essa superfície será um quadrado de 50x50 unidades de tamanho}Em seguida, escreva o código de delineamento da forma:
var Canvas = document.Body.AppendChild (document.createElement ("Canvas")), context = Canvas.getContext ("2D"), A, B, Position; // Agora vou amostrar a superfície em intervalos .1 para (B = B = para (a = 0; a <1; a += .1) {para (B = B = B =; b); context.fillrect (position.x, position.y, 1, 1);}}Agora, tente um intervalo de amostragem mais denso:
Como você pode ver agora, como os intervalos de amostragem estão ficando mais densos e mais próximos, os pontos estão cada vez mais próximos da densidade mais alta, a distância entre os pontos adjacentes é menor que um pixel e o intervalo não pode ser visto pelo olho nu (ver 0,01). Para não causar muita diferença visual, o intervalo de amostragem é reduzido ainda mais. No momento, a área de desenho foi preenchida (os resultados da comparação são de 0,01 e 0,001).
Em seguida, uso esta fórmula para desenhar um círculo: (x-x0)^2 + (y-y0)^2 <raio^2, onde (x0, y0) é o centro do círculo:
função superfície (a, b) {var x = a * 100, y = b * 100, raio = 50, x0 = 50, y0 = 50; if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <raio * raio) {// dentro do circlereTurn {x: x, y: y}Para evitar transbordamento, uma condição de amostragem deve ser adicionada:
if (position = superfície (a, b)) {context.fillrect (position.x, position.y, 1, 1);}Existem diferentes maneiras de definir um círculo, algumas das quais não exigem rejeição da amostragem. Não preciso usar qual para definir um círculo, então uso outro método para definir um círculo:
função superfície (a, b) {// círculo usando coordenados polares ângulo = a * math.pi * 2, raio = 50, x0 = 50, y0 = 50; retorna {x: math.cos (ângulo) * raio * b + x0, y: math.sin (ângulo) * raio * b + y0};};(Este método requer amostragem densa para preenchimento em comparação com o método anterior.)
Ok, agora deixe o círculo se deformar para fazer com que pareça mais uma pétala:
função superfície (a, b) {var x = a * 100, y = b * 100, raio = 50, x0 = 50, y0 = 50; if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <raio * raio) {return {x: x, y: y * (1 + b) / 2 // 2 // 2 // »{};Parece uma pétala de rosa. Aqui você também pode tentar modificar alguns valores de função, e muitas formas interessantes aparecerão.
Em seguida, adicione cor:
Função superfície (a, b) {var x = a * 100, y = b * 100, raio = 50, x0 = 50, y0 = 50; if ((x - x0) * (x - x0) + (y - y0) * (y - y0) <raio * raio) {return {x: x, y: y * (1 + b) / 2, 2, 2, Radius) {Return {x: x, y: y: y * (1 + b) / 2, 2, 2, Radius * Radius) {X: x, y: y: y * (y - y0) <Radius * Radius) {X: x, y: y * (y - y0) Adicione um gradienteg: 50, b: 50};} else {return null;}} para (a = 0; a <1; a + = 0,01) {for (b = 0; b <1; b + = 0,001) {if (Point = Surface (a, b)) {context.fillstyle = "rgb (" " +" + (a, a, b)) {context.fillstyle = "rgb (" ")"; context.fillRect (Point.x, Point.y, 1, 1);}}}Uma pétala colorida aparece.
Projeção de superfície e perspectiva 3D
Definir uma superfície tridimensional é simples, por exemplo, definir um objeto tubular:
Função superfície (a, b) {var angle = a * math.pi * 2, raio = 100, comprimento = 400; retorna {x: math.cos (ângulo) * raio, y: math.sin (ângulo) * raio, z: b * comprimento - comprimento / 2, // subtraindo / 2 eu tenho centralizado o tubo em (0, 0, 0, 0, 0), b * comprimento, 0, 0, 0). 0};}Em seguida, adicione uma perspectiva de projeção. Primeiro, precisamos definir uma câmera:
Como mostrado acima, coloque a câmera na posição (0, 0, z) e a tela no plano X/Y. Os pontos de amostragem projetados na tela são:
var px, py, // projetado na tela x e y coordenados mais = (Point.x * Perspective) / (Point.Z - Cameraz) + HalfWidth; Py = (Point.y * Perspective) / (Point.Z - Cameraz) + HalfHeight; context.fillstyle = "rgb) (" + Point.r + "," + Point.g + "," + Point.b + ")";O efeito é:
Z-Buffer
O Z-Buffer é uma técnica muito comum em computação gráfica. Ao sombrear objetos, o trabalho de "eliminação da superfície oculto" é realizado para que a parte por trás dos objetos ocultos não seja exibida.
A imagem acima é uma rosa processada com a tecnologia Z-Buffer. (Você pode ver que ele já tem tridimensionalidade)
O código é o seguinte:
var zbuffer = [], zbufferindex; for (a = 0; a <1; a += 0,001) {for (b = 0; b <1; b += 0,01) {if (point = superfície (a, b)) {px = math.floor (point.x * perspectiva) / ((point.z - Cameraz) / (Point.Z - Cameraz) + HalfHeight); Zbufferindex = py * Canvas.width + px; if ((typeof zbuffer [zbufferindex] === "Undefined") || (Point.z <ZBuffer [ZBufferIndEx]) {Zbffer [Zbuffer Point.r + "," + Point.g + "," + Point.b + ")"; context.fillrect (px, py, 1, 1);}}}}Girar
Você pode usar qualquer método de rotação vetorial. Na criação do código aumentou, eu uso a rotação de Euler. Agora gire o objeto tubular anteriormente escrito para girar em torno do eixo y:
Função superfície (a, b) {var angle = a * math.pi * 2, raio = 100, comprimento = 400, x = math.cos (ângulo) * raio, y = math.sin (ângulo) * raio, z = b * comprimento - comprimento / 2, yaxisrotation = -.4, // em radianos! Math.sin (yaxisrotationangle), giratedz = x * -math.sin (yaxisrotationAnge) + z * math.cos (yaxisrotationAngle); return {x: giratedx, y: y, z: gotatedz, r: 0, g: math.floor (b * 255), b: 0Efeito:
Método de Monte Carlo
Em relação ao tempo de amostragem, muito grande e muito pequeno, causará uma experiência visual extremamente baixa, portanto, um intervalo de amostragem razoável precisa ser definido, e o método Monte Carlo é usado aqui.
var i; window.setInterval (function () {for (i = 0; i <10000; i ++) {if (ponto = superfície (math.random (), math.random ()) {px = math.floor (Point.x * perspectiva) / (Point.z - Cameraz) +HalfWidth); py); halfHeight); zbufferindex = py * canvas.width + px; if ((typeof zbuffer [zbufferindex] === "indefinido") || (point.z <zBuffer [zBufferIndex])) {zbuffer [rushrindex] = point.z; + "," + Point.B + ")"; context.fillRect (px, py, 1, 1);}}}}, 0);Defina A e B como parâmetros aleatórios e complete o enchimento da superfície com amostragem suficiente. Desenho 10000 pontos a cada vez e aguardo a tela concluir a atualização.
Deve -se notar também que, se um número aleatório estiver incorreto, o efeito de enchimento da superfície estará incorreto. Em alguns navegadores, a execução da matemática. Random é linear, o que pode levar a erros nos efeitos de enchimento da superfície. Neste momento, você deve usar algo como Mersenne Twister (um algoritmo de número aleatório) para realizar amostragem de PRNG de alta qualidade para evitar erros.
Terminar
Para que cada parte da rosa seja concluída e renderizada ao mesmo tempo, um recurso precisa ser adicionado para definir um parâmetro para cada parte retornar o valor para a sincronização. E use uma função de segmento para representar as várias partes da rosa. Por exemplo, na parte da pétala, uso rotação e deformação para criá -las.
Embora o método de amostragem de superfície seja um dos métodos mais famosos e mais antigos para criar gráficos tridimensionais, esse método de adicionar Monte Carlo e Z-Buffer à amostragem de superfície não é comum. Isso pode não ser muito criativo para a produção de cenários da vida real, mas sua simples implementação de código e tamanho pequeno ainda são satisfatórios.
Espero que este artigo inspire os entusiastas de computadores gráficos a experimentar diferentes métodos de apresentação e se divertir. (Cortes romanos)
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.