Kirjoittaja: peki
Kirjoitettu: 27.05.2004 – 27.05.2004
Tagit: koodi näytille, vinkki
Vesi -efekti. Toimii vain ja ainoastaan vb.net 2003:lla johtuen >> operaattorista.
Jos joku viitsii, niin voisi tehdä funkkarin, joka matkisi tuota. Sitten toimisi aiemmillakin versioilla.
Pyydän kommentteja.
Vaatii kuvan "Koe.jpg" suoraan C: aseman juureen.
Exe löytyy: http://koti.mbnet.fi/peku1/Water.exe (et voi ajaa ilman koe.jpg nimistä kuvaa c:n juuressa)
Kommentointi on aika hyvää, joten ohjelman toimintaa en kuvaa tässä sen tarkemmin.
Tästä koodista voisi oppia erittäin nopean bittikartan pikseleiden manipuloimisen, sekä tietysti vesiefektin toteuttamisen
Edit: jos joku ei ymmärrä koodia kommenttejakaan lukemalla, niin voi käydä täällä(oma lähdemateriaalini): http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
Edit2: Koodiin on tehty parannuksia:
Hieman lisää nopeutta, fps -countteri, sade
Exe on myös päivitetty ja mainittakoon vielä kerran, exeni eivät sisällä mitään vakoiluohjelmia, vaikka jotkut niin väittävätkin.
Edit3: Älä aja exeä suoraan IEExecin läpi, vaan tallenna se kiintolevylle ja aja vasta siellä. Muuten c: asemalla sijaitsevaa kuvaa ei voida avata. (itsellä kävi näin)
Imports System.Drawing.Imaging Imports System.Runtime.InteropServices Public Class frmWater Inherits System.Windows.Forms.Form ' yleisiä muuttujia Private bmp As Bitmap Private waves As Long(,,) Private bmpWidth As Integer Private bmpHeight As Integer Private activeBuffer As Integer = 0 Private weHaveWaves As Boolean Private bmpBytes As Byte() Private bmpBitmapData As BitmapData ' asettaa pisaran säteen Private dropRadius As Integer = 5 ' Kuinka kauan aallot säilyvät. Mitä isompi arvo, sitä kauemmin aallot kestävät Private dampener As Integer = 3 Dim fps As Integer Dim fnt As New Font("Arial", 10) #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Haluamme piirtää itse -> ei automaattipäivitystä SetStyle(ControlStyles.UserPaint, True) 'Piirto tapahtuu vain ja ainoastaan paint metodissa SetStyle(ControlStyles.AllPaintingInWmPaint, True) 'Haluamme käyttää myös kaksoispuskurointia SetStyle(ControlStyles.DoubleBuffer, True) End Sub 'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer 'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Friend WithEvents EffectTimer As System.Windows.Forms.Timer Friend WithEvents picSurface As System.Windows.Forms.PictureBox <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.components = New System.ComponentModel.Container Me.EffectTimer = New System.Windows.Forms.Timer(Me.components) Me.picSurface = New System.Windows.Forms.PictureBox Me.SuspendLayout() ' 'EffectTimer ' Me.EffectTimer.Enabled = True Me.EffectTimer.Interval = 1 ' 'picSurface ' Me.picSurface.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ Or System.Windows.Forms.AnchorStyles.Left) _ Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) Me.picSurface.Location = New System.Drawing.Point(0, 0) Me.picSurface.Name = "picSurface" Me.picSurface.Size = New System.Drawing.Size(448, 368) Me.picSurface.TabIndex = 0 Me.picSurface.TabStop = False ' 'frmWater ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(448, 366) Me.Controls.Add(Me.picSurface) Me.Name = "frmWater" Me.Text = "Water" Me.ResumeLayout(False) End Sub #End Region Private Sub frmWater_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Ladataan bittikartta bmp = New Bitmap("C:/koe.jpg") ' otetaan ylös arvot(lukeminen suoraan muuttujasta nopeampaa) bmpHeight = bmp.Height bmpWidth = bmp.Width ' alustetaan aaltotaulukko ReDim Me.waves(bmpWidth, bmpHeight, 2) ' hankitaan bittikartta dataa(NOPEA TAPA!!!) ReDim Me.bmpBytes(bmpWidth * bmpHeight * 4) bmpBitmapData = bmp.LockBits(New Rectangle(0, 0, bmpWidth, bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb) Marshal.Copy(bmpBitmapData.Scan0, bmpBytes, 0, bmpWidth * bmpHeight * 4) End Sub Private Sub ProcessWaves() Dim wavesFound As Boolean = False Dim x, y As Integer Dim newBuffer As Integer If (activeBuffer = 0) Then newBuffer = 1 Else newBuffer = 0 End If x = 1 Do While (x < (bmpWidth - 1)) y = 1 Do While (y < (bmpHeight - 1)) ' aalto filtterin "kaava" waves(x, y, newBuffer) = CInt((waves(x - 1, y - 1, activeBuffer) + _ waves(x, y - 1, activeBuffer) + _ waves(x + 1, y - 1, activeBuffer) + _ waves(x - 1, y, activeBuffer) + _ waves(x + 1, y, activeBuffer) + _ waves(x - 1, y + 1, activeBuffer) + _ waves(x, y + 1, activeBuffer) + _ waves(x + 1, y + 1, activeBuffer) >> 2) - waves(x, y, newBuffer)) 'pehmennys(jotta aallot joskus häviäisivät :D) If Not (waves(x, y, newBuffer) = 0) Then waves(x, y, newBuffer) -= CInt(waves(x, y, newBuffer) >> dampener) wavesFound = True ' Jos tänne on päästy(ks. iffi) niin aaltoja (vielä) on End If y += 1 Loop 'y++ x += 1 Loop 'x++ weHaveWaves = wavesFound activeBuffer = newBuffer End Sub Private Sub picSurface_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picSurface.Paint Dim tmp As Bitmap = bmp.Clone() Dim x, y As Integer Dim xOffset, yOffset As Integer Dim alpha As Integer If (weHaveWaves) Then Dim tmpData As BitmapData = tmp.LockBits(New Rectangle(0, 0, bmpWidth, bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb) Dim tmpBytes(bmpWidth * bmpHeight * 4) As Byte Marshal.Copy(tmpData.Scan0, tmpBytes, 0, bmpWidth * bmpHeight * 4) x = 1 Do While (x < (bmpWidth - 1)) y = 1 Do While (y < (bmpHeight - 1)) 'tsekkaa törmäilyt If (x <= 0) Then x = 1 ElseIf (x >= bmpWidth - 1) Then x = bmpWidth - 2 End If If (y <= 0) Then y = 1 ElseIf (y >= bmpHeight - 1) Then y = bmpHeight - 2 End If 'Tämä on johdettu raytracingistä(AH!) heijastetaan oikea pikseli siten, 'että saadaan aikaan valoa taittava efekti. xOffset = waves(x - 1, y, activeBuffer) - waves(x + 1, y, activeBuffer) >> 3 yOffset = waves(x, y - 1, activeBuffer) - waves(x, y + 1, activeBuffer) >> 3 If ((Not (xOffset = 0)) Or (Not (yOffset = 0))) Then 'tsekkaa törmailyt(heijastetuille pikseleille) If (x + xOffset >= bmpWidth - 1) Then xOffset = bmpWidth - x - 1 If (x + xOffset < 0) Then xOffset = -x If (y + yOffset >= bmpHeight - 1) Then yOffset = bmpHeight - y - 1 If (y + yOffset < 0) Then yOffset = -y 'luodaan alpha alpha = CInt(200 - xOffset) If (alpha < 0) Then alpha = 0 ElseIf (alpha > 255) Then alpha = 254 End If 'asetetaan värit oikeisiin kohtiin(napataan oikeasta kohdasta bittitaulukkoa) tmpBytes(4 * (x + y * bmpWidth)) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth)) tmpBytes(4 * (x + y * bmpWidth) + 1) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth) + 1) tmpBytes(4 * (x + y * bmpWidth) + 2) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth) + 2) tmpBytes(4 * (x + y * bmpWidth) + 3) = alpha End If y += 1 Loop 'y x += 1 Loop 'x 'kopioidaan data takasin Marshal.Copy(tmpBytes, 0, tmpData.Scan0, bmpWidth * bmpHeight * 4) tmp.UnlockBits(tmpData) End If e.Graphics.DrawImage(tmp, 0, 0, picSurface.ClientRectangle.Width, picSurface.ClientRectangle.Height) e.Graphics.DrawString("fps: " & fps, fnt, Brushes.Black, 50, 50) End Sub Private Sub PutDrop(ByVal x As Integer, ByVal y As Integer, ByVal height As Short) ' Simuloi pyöreää pisaraa ' täyttää aaltotaulukon sopivilla arvoilla ' Käytetään hyväksi kosiniaaltoa ' (Jos tykkäät geomatriasta/algebrasta RAKASTAT tätä aliohjelmaa ' Silloin tulet nauttimaan myös renderöinnin "raytracing" osuudesta) ' Nyt meillä ON aaltoja :D weHaveWaves = True Dim radius As Integer = dropRadius 'etäisyyden neliö Dim distSquared As Double 'aloitetaan "pallon" reunoilta Dim i As Integer = -radius Dim tmpX, tmpY As Integer Do While (i <= radius) Dim j As Integer = -radius Do While (j <= radius) tmpX = x + i tmpY = y + j If (((tmpX >= 0) And (tmpX < bmpWidth - 1)) And ((tmpY >= 0) And (tmpY < bmpHeight - 1))) Then ' i:n ja j:n välisen etäisyyden neliö distSquared = Math.Sqrt(i * i + j * j) ' jos etäisyys on < säde silloin aalto "oikein" If (distSquared < radius) Then ' pistetään kosiniaaltoa silmukan osoittamaan paikkaan waves(x + i, y + j, activeBuffer) = CShort(Math.Cos(distSquared * Math.PI / radius) * height) End If End If j += 1 Loop 'j i += 1 Loop 'i End Sub Private Sub picSurface_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picSurface.MouseMove ' Koska bittikarttaa skaalataan, täytyy hiiren koordinaatteja hieman säätää... Dim realX As Integer = CInt((e.X / CDbl(picSurface.ClientRectangle.Width)) * bmpWidth) Dim realY As Integer = CInt((e.Y / CDbl(picSurface.ClientRectangle.Height)) * bmpHeight) PutDrop(realX, realY, 200) End Sub Private Sub frmWater_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated Do Dim d As Long = Now().Millisecond Dim ft As Long ' jos aaltoja -> piirretään If weHaveWaves Then picSurface.Invalidate() ProcessWaves() End If If Int(Rnd() * 100) > 70 Then PutDrop(Int(Rnd() * bmpWidth), Int(Rnd() * bmpHeight), Int(Rnd() * 100) + 100) End If Application.DoEvents() ft = Now().Millisecond - d fps = 1 / ft * 1000 Loop End Sub Private Sub frmWater_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed End End Sub End Class
Hieno ja todentuntuinen efekti, nopeutta voisit vielä koettaa saada lisää.
Todella upea efekti tämä on.
Ai että toi on kyllä hieno! Saispa saman VB:lle... Ei vaan löytyny :(
Nopeutta saa lisää käyttämällä pienempää kuvaa, ja laskemalla damperin arvoa(tein jo muutoksen 4 -> 3 koodiin),
dropRadiusta pienentämällä nopeutta saa myös lisää.
Jos kiinostuneita riittää, ajattelin kirjoittaa tästä efektistä oppaan.
Harmi ettei nuo exet toimi mulla :(
Whinee jostain rekisteriavaimesta...
Hanki .net-alusta mikkisoftalta.
Niijja itse vinkistä, TOSI UPEE EFEKTI! Sikahieano.
Ei toimi mullakaan... Mitä lie vakoiluohjelmia sisältää....
Öh. Käy lataamassa http://www.microsoft.com/downloads/details.aspx?
Edit: ja toisekseen, ohjelmani eivät sisällä vakoiluohjelmia, joten turha panettelu sikseen!
Edit2: koodia on päivitetty: Hieman lisää nopeutta, fps -countteri, sade
Noniin, nyt toimii, kiitos tuosta linkistä!
Näyttää hienolta, mutta helvetin hidas vain on :(
Onhan se hieno. Tosin meni hetki ennenkuin vanha hokasi mitä siinä itseasiassa tapahtuu. Näkyy parhaiten kun kuvassa on jyrkkiä kontrasteja. Mulla se on kyllä hidas, kuva päivittyy noin peri kertaa sekunnissa. Toi kuva on melkein puoli megaa, ehkä siinä syy.
Edit. Kokeilin pienemmällä kuvalla ( 4 kt ). Todella mahtava efekti, kerrassaan hieano ! Ihan itsekö kehittelit vai saitko jostain vinkkiä. Melkoisia osaajia täällä putkassa !!
Itse vesiefekti on omani, mutta tuohon renderöimiseen korkeuskartan läpi sain netistä hieman apua englanninkielisen hieman "sekavan oppaan" muodossa. :D
Edit: Tuo lähdemateriaali, minkä mainitsin kuvauksessa siis.
osaisko kukaa kääntää tota vb 6:selle
"Sovelluksen alustus epäonnistui..." -> Pitäisikö minun siis muka ladata 24 megan paketti Microsoftilta, että saan sen toimimaan?
Kyllä. Ikävä kyllä näin on.
.NET sovellukset eivät toimi ilman Framework nimistä kirjastoa. Omat sovellukseni siis vaativat version 1.1 toistaiseksi.
mulla se .net framework 1.1 oli win xp pro:n asennus levykkeellä. Muistaakseni siinä lisäosat tai lisätoiminnot tai jotain sinnepäin ni siin kohassa.
ihan ärsygdävän bieniä dibboja, niin ja mulla on 2.jotain .net framwork ja sitä ei kyllä löydy siltä levyltä, mut jos kiinnostaa ni let's go to microsoft.com
ei helvetti noit mun gommenddeja... lol